Version 2.6.0-dev.1.0

Merge commit 'cbdbb464ca0301060f95c861d5fe0069d0d372f7' into dev
diff --git a/CHANGELOG.md b/CHANGELOG.md
index c6555d2..8574697 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,29 @@
 
 ### Language
 
+### Core libraries
+
+### Dart VM
+
+### Tools
+
+#### Pub
+
+#### Linter
+
+The Linter was updated to `0.1.97+1`, which includes:
+
+* internal migration away from using analyzer `resolutionMap`
+* various fixes and improvements to anticipate support for extension-methods
+* new lint: `camel_case_extensions`
+* rule template generation improvements
+* new lint: `avoid_equals_and_hash_code_on_mutable_classes`
+* extended `avoid_slow_async_io` to flag async `Directory` methods
+
+## 2.5.0 - 2019-09-10
+
+### Language
+
 The set of operations allowed in constant expressions has been expanded as
 described in
 the [constant update proposal](https://github.com/dart-lang/language/issues/61).
@@ -124,7 +147,7 @@
 
 #### `dart:io`
 
-* **Breaking change** [#37192](https://github.com/dart-lang/sdk/issues/37192): 
+* **Breaking change** [#37192](https://github.com/dart-lang/sdk/issues/37192):
   The `Cookie` class's constructor's `name` and `value`
   optional positional parameters are now mandatory. The
   signature changes from:
@@ -142,7 +165,7 @@
   Since code could not previously correctly omit the parameters, this is not
   really a breaking change.
 
-* **Breaking change** [#37192](https://github.com/dart-lang/sdk/issues/37192): 
+* **Breaking change** [#37192](https://github.com/dart-lang/sdk/issues/37192):
   The `Cookie` class's `name` and `value` setters now
   validates that the strings are made from the allowed character set and are not
   null. The constructor already made these checks and this
@@ -161,14 +184,11 @@
 
 #### Linter
 
-The Linter was updated to `0.1.97+1`, which includes:
+The Linter was updated to `0.1.96`, which includes:
 
-* internal migration away from using analyzer `resolutionMap`
-* various fixes and improvements to anticipate support for extension-methods
-* new lint: `camel_case_extensions`
-* rule template generation improvements
-* new lint: `avoid_equals_and_hash_code_on_mutable_classes`
-* extended `avoid_slow_async_io` to flag async `Directory` methods
+* fixed false positives in `unnecessary_parens`
+* various changes to migrate to preferred analyzer APIs
+* rule test fixes
 
 #### Dartdoc
 
diff --git a/DEPS b/DEPS
index 6033eca..dc46d63 100644
--- a/DEPS
+++ b/DEPS
@@ -174,7 +174,7 @@
   Var("dart_root") + "/tools/sdks": {
       "packages": [{
           "package": "dart/dart-sdk/${{platform}}",
-          "version": "version:2.5.0-dev.1.0",
+          "version": "version:2.5.0",
       }],
       "dep_type": "cipd",
   },
diff --git a/PRESUBMIT.py b/PRESUBMIT.py
index 7beb3f8..63a5b47 100644
--- a/PRESUBMIT.py
+++ b/PRESUBMIT.py
@@ -57,16 +57,6 @@
     return unformatted_files
 
 
-def _CheckBuildStatus(input_api, output_api):
-    results = []
-    status_check = input_api.canned_checks.CheckTreeIsOpen(
-        input_api,
-        output_api,
-        json_url='http://dart-status.appspot.com/current?format=json')
-    results.extend(status_check)
-    return results
-
-
 def _CheckDartFormat(input_api, output_api):
     local_root = input_api.change.RepositoryRoot()
     upstream = input_api.change._upstream
@@ -250,16 +240,22 @@
             long_text=stdout)
     ]
 
+
+def _CommonChecks(input_api, output_api):
+    results = []
+    results.extend(_CheckValidHostsInDEPS(input_api, output_api))
+    results.extend(_CheckDartFormat(input_api, output_api))
+    results.extend(_CheckStatusFiles(input_api, output_api))
+    results.extend(_CheckLayering(input_api, output_api))
+    results.extend(_CheckClangTidy(input_api, output_api))
+    results.extend(
+        input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
+    return results
+
+
 def CheckChangeOnCommit(input_api, output_api):
-    return (_CheckValidHostsInDEPS(input_api, output_api) + _CheckBuildStatus(
-        input_api, output_api) + _CheckDartFormat(input_api, output_api) +
-            _CheckStatusFiles(input_api, output_api) + _CheckLayering(
-                input_api, output_api) + _CheckClangTidy(
-                input_api, output_api))
+    return _CommonChecks(input_api, output_api)
 
 
 def CheckChangeOnUpload(input_api, output_api):
-    return (_CheckValidHostsInDEPS(input_api, output_api) + _CheckDartFormat(
-        input_api, output_api) + _CheckStatusFiles(input_api, output_api) +
-            _CheckLayering(input_api, output_api) + _CheckClangTidy(
-                input_api, output_api))
+    return _CommonChecks(input_api, output_api)
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/completion_manager.dart b/pkg/analysis_server/lib/src/services/completion/dart/completion_manager.dart
index 9e1113b..4d77c9c 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/completion_manager.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/completion_manager.dart
@@ -214,6 +214,7 @@
       if (opType.includeReturnValueSuggestions) {
         kinds.add(protocol.ElementKind.CONSTRUCTOR);
         kinds.add(protocol.ElementKind.ENUM_CONSTANT);
+        kinds.add(protocol.ElementKind.EXTENSION);
         kinds.add(protocol.ElementKind.FUNCTION);
         kinds.add(protocol.ElementKind.TOP_LEVEL_VARIABLE);
       }
diff --git a/pkg/analysis_server/lib/src/services/correction/assist.dart b/pkg/analysis_server/lib/src/services/correction/assist.dart
index 9cb8c62..3d37042 100644
--- a/pkg/analysis_server/lib/src/services/correction/assist.dart
+++ b/pkg/analysis_server/lib/src/services/correction/assist.dart
@@ -104,9 +104,7 @@
   static const CONVERT_TO_PACKAGE_IMPORT = const AssistKind(
       'dart.assist.convert.relativeToPackageImport',
       30,
-      "Convert to 'package:' import",
-      // todo (pq): migrate to (conditional) fix
-      associatedErrorCodes: <String>['avoid_relative_lib_imports']);
+      "Convert to 'package:' import");
   static const CONVERT_TO_SET_LITERAL = const AssistKind(
       'dart.assist.convert.toSetLiteral', 30, "Convert to set literal",
       // todo (brianwilkerson): unify w/ fix
@@ -114,13 +112,9 @@
   static const CONVERT_TO_SINGLE_QUOTED_STRING = const AssistKind(
       'dart.assist.convert.toSingleQuotedString',
       30,
-      "Convert to single quoted string",
-      // todo (pq): migrate to (conditional) fix
-      associatedErrorCodes: <String>['prefer_single_quotes']);
-  static const CONVERT_TO_SPREAD =
-      const AssistKind('dart.assist.convertToSpread', 30, "Convert to a spread",
-          // todo (pq): migrate to (conditional) fix
-          associatedErrorCodes: <String>['prefer_spread_collections']);
+      "Convert to single quoted string");
+  static const CONVERT_TO_SPREAD = const AssistKind(
+      'dart.assist.convertToSpread', 30, "Convert to a spread");
   static const ENCAPSULATE_FIELD =
       const AssistKind('dart.assist.encapsulateField', 30, "Encapsulate field");
   static const EXCHANGE_OPERANDS =
diff --git a/pkg/analysis_server/lib/src/services/correction/assist_internal.dart b/pkg/analysis_server/lib/src/services/correction/assist_internal.dart
index f3ba612..8d88015 100644
--- a/pkg/analysis_server/lib/src/services/correction/assist_internal.dart
+++ b/pkg/analysis_server/lib/src/services/correction/assist_internal.dart
@@ -101,8 +101,16 @@
     )) {
       await _addProposal_convertToNullAware();
     }
-    await _addProposal_convertToPackageImport();
-    await _addProposal_convertToSingleQuotedString();
+    if (!_containsErrorCode(
+      {LintNames.avoid_relative_lib_imports},
+    )) {
+      await _addProposal_convertToPackageImport();
+    }
+    if (!_containsErrorCode(
+      {LintNames.prefer_single_quotes},
+    )) {
+      await _addProposal_convertToSingleQuotedString();
+    }
     await _addProposal_encapsulateField();
     await _addProposal_exchangeOperands();
     await _addProposal_flutterConvertToChildren();
@@ -151,7 +159,11 @@
       }
     }
     if (experimentStatus.spread_collections) {
-      await _addProposal_convertAddAllToSpread();
+      if (!_containsErrorCode(
+        {LintNames.prefer_spread_collections},
+      )) {
+        await _addProposal_convertAddAllToSpread();
+      }
     }
 
     return assists;
@@ -252,83 +264,13 @@
   }
 
   Future<void> _addProposal_convertAddAllToSpread() async {
-    AstNode node = this.node;
-    if (node is! SimpleIdentifier || node.parent is! MethodInvocation) {
-      _coverageMarker();
-      return;
+    final change = await createBuilder_convertAddAllToSpread();
+    if (change != null) {
+      final kind = change.isLineInvocation
+          ? DartAssistKind.INLINE_INVOCATION
+          : DartAssistKind.CONVERT_TO_SPREAD;
+      _addAssistFromBuilder(change.builder, kind, args: change.args);
     }
-    SimpleIdentifier name = node;
-    MethodInvocation invocation = node.parent;
-    if (name != invocation.methodName ||
-        name.name != 'addAll' ||
-        !invocation.isCascaded ||
-        invocation.argumentList.arguments.length != 1) {
-      _coverageMarker();
-      return;
-    }
-    CascadeExpression cascade = invocation.thisOrAncestorOfType();
-    NodeList<Expression> sections = cascade.cascadeSections;
-    Expression target = cascade.target;
-    if (target is! ListLiteral || sections[0] != invocation) {
-      // TODO(brianwilkerson) Consider extending this to handle set literals.
-      _coverageMarker();
-      return;
-    }
-
-    bool isEmptyListLiteral(Expression expression) =>
-        expression is ListLiteral && expression.elements.isEmpty;
-
-    ListLiteral list = target;
-    Expression argument = invocation.argumentList.arguments[0];
-    String elementText;
-    AssistKind kind = DartAssistKind.CONVERT_TO_SPREAD;
-    List<String> args = null;
-    if (argument is BinaryExpression &&
-        argument.operator.type == TokenType.QUESTION_QUESTION) {
-      Expression right = argument.rightOperand;
-      if (isEmptyListLiteral(right)) {
-        // ..addAll(things ?? const [])
-        // ..addAll(things ?? [])
-        elementText = '...?${utils.getNodeText(argument.leftOperand)}';
-      }
-    } else if (experimentStatus.control_flow_collections &&
-        argument is ConditionalExpression) {
-      Expression elseExpression = argument.elseExpression;
-      if (isEmptyListLiteral(elseExpression)) {
-        // ..addAll(condition ? things : const [])
-        // ..addAll(condition ? things : [])
-        String conditionText = utils.getNodeText(argument.condition);
-        String thenText = utils.getNodeText(argument.thenExpression);
-        elementText = 'if ($conditionText) ...$thenText';
-      }
-    } else if (argument is ListLiteral) {
-      // ..addAll([ ... ])
-      NodeList<CollectionElement> elements = argument.elements;
-      if (elements.isEmpty) {
-        // TODO(brianwilkerson) Consider adding a cleanup for the empty list
-        //  case. We can essentially remove the whole invocation because it does
-        //  nothing.
-        return;
-      }
-      int startOffset = elements.first.offset;
-      int endOffset = elements.last.end;
-      elementText = utils.getText(startOffset, endOffset - startOffset);
-      kind = DartAssistKind.INLINE_INVOCATION;
-      args = ['addAll'];
-    }
-    elementText ??= '...${utils.getNodeText(argument)}';
-    DartChangeBuilder changeBuilder = _newDartChangeBuilder();
-    await changeBuilder.addFileEdit(file, (DartFileEditBuilder builder) {
-      if (list.elements.isNotEmpty) {
-        // ['a']..addAll(['b', 'c']);
-        builder.addSimpleInsertion(list.elements.last.end, ', $elementText');
-      } else {
-        // []..addAll(['b', 'c']);
-        builder.addSimpleInsertion(list.leftBracket.end, elementText);
-      }
-      builder.addDeletion(range.node(invocation));
-    });
-    _addAssistFromBuilder(changeBuilder, kind, args: args);
   }
 
   Future<void> _addProposal_convertClassToMixin() async {
@@ -1310,45 +1252,9 @@
   }
 
   Future<void> _addProposal_convertToPackageImport() async {
-    var node = this.node;
-    if (node is StringLiteral) {
-      node = node.parent;
-    }
-    if (node is ImportDirective) {
-      ImportDirective importDirective = node;
-      var uriSource = importDirective.uriSource;
-
-      // Ignore if invalid URI.
-      if (uriSource == null) {
-        return;
-      }
-
-      var importUri = uriSource.uri;
-      if (importUri.scheme != 'package') {
-        return;
-      }
-
-      // Don't offer to convert a 'package:' URI to itself.
-      try {
-        if (Uri.parse(importDirective.uriContent).scheme == 'package') {
-          return;
-        }
-      } on FormatException {
-        return;
-      }
-
-      var changeBuilder = _newDartChangeBuilder();
-      await changeBuilder.addFileEdit(file, (builder) {
-        builder.addSimpleReplacement(
-          range.node(importDirective.uri),
-          "'$importUri'",
-        );
-      });
-      _addAssistFromBuilder(
-        changeBuilder,
-        DartAssistKind.CONVERT_TO_PACKAGE_IMPORT,
-      );
-    }
+    final changeBuilder = await createBuilder_convertToPackageImport();
+    _addAssistFromBuilder(
+        changeBuilder, DartAssistKind.CONVERT_TO_PACKAGE_IMPORT);
   }
 
   Future<void> _addProposal_convertToSingleQuotedString() async {
@@ -3432,57 +3338,8 @@
   }
 
   Future<void> _convertQuotes(bool fromDouble, AssistKind kind) async {
-    if (node is SimpleStringLiteral) {
-      SimpleStringLiteral literal = node;
-      if (fromDouble ? !literal.isSingleQuoted : literal.isSingleQuoted) {
-        String newQuote = literal.isMultiline
-            ? (fromDouble ? "'''" : '"""')
-            : (fromDouble ? "'" : '"');
-        int quoteLength = literal.isMultiline ? 3 : 1;
-        String lexeme = literal.literal.lexeme;
-        if (lexeme.indexOf(newQuote) < 0) {
-          var changeBuilder = _newDartChangeBuilder();
-          await changeBuilder.addFileEdit(file, (DartFileEditBuilder builder) {
-            builder.addSimpleReplacement(
-                new SourceRange(
-                    literal.offset + (literal.isRaw ? 1 : 0), quoteLength),
-                newQuote);
-            builder.addSimpleReplacement(
-                new SourceRange(literal.end - quoteLength, quoteLength),
-                newQuote);
-          });
-          _addAssistFromBuilder(changeBuilder, kind);
-        }
-      }
-    } else if (node is InterpolationString) {
-      StringInterpolation parent = node.parent;
-      if (fromDouble ? !parent.isSingleQuoted : parent.isSingleQuoted) {
-        String newQuote = parent.isMultiline
-            ? (fromDouble ? "'''" : '"""')
-            : (fromDouble ? "'" : '"');
-        int quoteLength = parent.isMultiline ? 3 : 1;
-        NodeList<InterpolationElement> elements = parent.elements;
-        for (int i = 0; i < elements.length; i++) {
-          InterpolationElement element = elements[i];
-          if (element is InterpolationString) {
-            String lexeme = element.contents.lexeme;
-            if (lexeme.indexOf(newQuote) >= 0) {
-              return;
-            }
-          }
-        }
-        var changeBuilder = _newDartChangeBuilder();
-        await changeBuilder.addFileEdit(file, (DartFileEditBuilder builder) {
-          builder.addSimpleReplacement(
-              new SourceRange(
-                  parent.offset + (parent.isRaw ? 1 : 0), quoteLength),
-              newQuote);
-          builder.addSimpleReplacement(
-              new SourceRange(parent.end - quoteLength, quoteLength), newQuote);
-        });
-        _addAssistFromBuilder(changeBuilder, kind);
-      }
-    }
+    final changeBuilder = await createBuilder_convertQuotes(fromDouble);
+    _addAssistFromBuilder(changeBuilder, kind);
   }
 
   /**
diff --git a/pkg/analysis_server/lib/src/services/correction/base_processor.dart b/pkg/analysis_server/lib/src/services/correction/base_processor.dart
index a67b7ca..e054c8f 100644
--- a/pkg/analysis_server/lib/src/services/correction/base_processor.dart
+++ b/pkg/analysis_server/lib/src/services/correction/base_processor.dart
@@ -155,182 +155,6 @@
     return validChange ? changeBuilder : null;
   }
 
-  Future<ChangeBuilder> createBuilder_convertToNullAware() async {
-    AstNode node = this.node;
-    if (node is! ConditionalExpression) {
-      _coverageMarker();
-      return null;
-    }
-    ConditionalExpression conditional = node;
-    Expression condition = conditional.condition.unParenthesized;
-    SimpleIdentifier identifier;
-    Expression nullExpression;
-    Expression nonNullExpression;
-    int periodOffset;
-
-    if (condition is BinaryExpression) {
-      //
-      // Identify the variable being compared to `null`, or return if the
-      // condition isn't a simple comparison of `null` to a variable's value.
-      //
-      Expression leftOperand = condition.leftOperand;
-      Expression rightOperand = condition.rightOperand;
-      if (leftOperand is NullLiteral && rightOperand is SimpleIdentifier) {
-        identifier = rightOperand;
-      } else if (rightOperand is NullLiteral &&
-          leftOperand is SimpleIdentifier) {
-        identifier = leftOperand;
-      } else {
-        _coverageMarker();
-        return null;
-      }
-      if (identifier.staticElement is! LocalElement) {
-        _coverageMarker();
-        return null;
-      }
-      //
-      // Identify the expression executed when the variable is `null` and when
-      // it is non-`null`. Return if the `null` expression isn't a null literal
-      // or if the non-`null` expression isn't a method invocation whose target
-      // is the save variable being compared to `null`.
-      //
-      if (condition.operator.type == TokenType.EQ_EQ) {
-        nullExpression = conditional.thenExpression;
-        nonNullExpression = conditional.elseExpression;
-      } else if (condition.operator.type == TokenType.BANG_EQ) {
-        nonNullExpression = conditional.thenExpression;
-        nullExpression = conditional.elseExpression;
-      }
-      if (nullExpression == null || nonNullExpression == null) {
-        _coverageMarker();
-        return null;
-      }
-      if (nullExpression.unParenthesized is! NullLiteral) {
-        _coverageMarker();
-        return null;
-      }
-      Expression unwrappedExpression = nonNullExpression.unParenthesized;
-      Expression target;
-      Token operator;
-      if (unwrappedExpression is MethodInvocation) {
-        target = unwrappedExpression.target;
-        operator = unwrappedExpression.operator;
-      } else if (unwrappedExpression is PrefixedIdentifier) {
-        target = unwrappedExpression.prefix;
-        operator = unwrappedExpression.period;
-      } else {
-        _coverageMarker();
-        return null;
-      }
-      if (operator.type != TokenType.PERIOD) {
-        _coverageMarker();
-        return null;
-      }
-      if (!(target is SimpleIdentifier &&
-          target.staticElement == identifier.staticElement)) {
-        _coverageMarker();
-        return null;
-      }
-      periodOffset = operator.offset;
-
-      DartChangeBuilder changeBuilder = _newDartChangeBuilder();
-      await changeBuilder.addFileEdit(file, (DartFileEditBuilder builder) {
-        builder.addDeletion(range.startStart(node, nonNullExpression));
-        builder.addSimpleInsertion(periodOffset, '?');
-        builder.addDeletion(range.endEnd(nonNullExpression, node));
-      });
-      return changeBuilder;
-    }
-    return null;
-  }
-
-  Future<ChangeBuilder> createBuilder_convertToExpressionFunctionBody() async {
-    // prepare current body
-    FunctionBody body = getEnclosingFunctionBody();
-    if (body is! BlockFunctionBody || body.isGenerator) {
-      _coverageMarker();
-      return null;
-    }
-    // prepare return statement
-    List<Statement> statements = (body as BlockFunctionBody).block.statements;
-    if (statements.length != 1) {
-      _coverageMarker();
-      return null;
-    }
-    Statement onlyStatement = statements.first;
-    // prepare returned expression
-    Expression returnExpression;
-    if (onlyStatement is ReturnStatement) {
-      returnExpression = onlyStatement.expression;
-    } else if (onlyStatement is ExpressionStatement) {
-      returnExpression = onlyStatement.expression;
-    }
-    if (returnExpression == null) {
-      _coverageMarker();
-      return null;
-    }
-
-    // Return expressions can be quite large, e.g. Flutter build() methods.
-    // It is surprising to see this Quick Assist deep in the function body.
-    if (selectionOffset >= returnExpression.offset) {
-      _coverageMarker();
-      return null;
-    }
-
-    var changeBuilder = _newDartChangeBuilder();
-    await changeBuilder.addFileEdit(file, (DartFileEditBuilder builder) {
-      builder.addReplacement(range.node(body), (DartEditBuilder builder) {
-        if (body.isAsynchronous) {
-          builder.write('async ');
-        }
-        builder.write('=> ');
-        builder.write(_getNodeText(returnExpression));
-        if (body.parent is! FunctionExpression ||
-            body.parent.parent is FunctionDeclaration) {
-          builder.write(';');
-        }
-      });
-    });
-    return changeBuilder;
-  }
-
-  /// Returns the text of the given node in the unit.
-  String /* TODO (pq): make visible */ _getNodeText(AstNode node) =>
-      utils.getNodeText(node);
-
-  FunctionBody getEnclosingFunctionBody() {
-    // TODO(brianwilkerson) Determine whether there is a reason why this method
-    // isn't just "return node.getAncestor((node) => node is FunctionBody);"
-    {
-      FunctionExpression function =
-          node.thisOrAncestorOfType<FunctionExpression>();
-      if (function != null) {
-        return function.body;
-      }
-    }
-    {
-      FunctionDeclaration function =
-          node.thisOrAncestorOfType<FunctionDeclaration>();
-      if (function != null) {
-        return function.functionExpression.body;
-      }
-    }
-    {
-      ConstructorDeclaration constructor =
-          node.thisOrAncestorOfType<ConstructorDeclaration>();
-      if (constructor != null) {
-        return constructor.body;
-      }
-    }
-    {
-      MethodDeclaration method = node.thisOrAncestorOfType<MethodDeclaration>();
-      if (method != null) {
-        return method.body;
-      }
-    }
-    return null;
-  }
-
   Future<ChangeBuilder>
       createBuilder_addTypeAnnotation_VariableDeclaration() async {
     AstNode node = this.node;
@@ -391,6 +215,90 @@
     return validChange ? changeBuilder : null;
   }
 
+  Future<ConvertToSpreadCollectionsChange>
+      createBuilder_convertAddAllToSpread() async {
+    AstNode node = this.node;
+    if (node is! SimpleIdentifier || node.parent is! MethodInvocation) {
+      _coverageMarker();
+      return null;
+    }
+    SimpleIdentifier name = node;
+    MethodInvocation invocation = node.parent;
+    if (name != invocation.methodName ||
+        name.name != 'addAll' ||
+        !invocation.isCascaded ||
+        invocation.argumentList.arguments.length != 1) {
+      _coverageMarker();
+      return null;
+    }
+    CascadeExpression cascade = invocation.thisOrAncestorOfType();
+    NodeList<Expression> sections = cascade.cascadeSections;
+    Expression target = cascade.target;
+    if (target is! ListLiteral || sections[0] != invocation) {
+      // TODO(brianwilkerson) Consider extending this to handle set literals.
+      _coverageMarker();
+      return null;
+    }
+
+    bool isEmptyListLiteral(Expression expression) =>
+        expression is ListLiteral && expression.elements.isEmpty;
+
+    ListLiteral list = target;
+    Expression argument = invocation.argumentList.arguments[0];
+    String elementText;
+    ConvertToSpreadCollectionsChange change =
+        ConvertToSpreadCollectionsChange();
+    List<String> args = null;
+    if (argument is BinaryExpression &&
+        argument.operator.type == TokenType.QUESTION_QUESTION) {
+      Expression right = argument.rightOperand;
+      if (isEmptyListLiteral(right)) {
+        // ..addAll(things ?? const [])
+        // ..addAll(things ?? [])
+        elementText = '...?${utils.getNodeText(argument.leftOperand)}';
+      }
+    } else if (experimentStatus.control_flow_collections &&
+        argument is ConditionalExpression) {
+      Expression elseExpression = argument.elseExpression;
+      if (isEmptyListLiteral(elseExpression)) {
+        // ..addAll(condition ? things : const [])
+        // ..addAll(condition ? things : [])
+        String conditionText = utils.getNodeText(argument.condition);
+        String thenText = utils.getNodeText(argument.thenExpression);
+        elementText = 'if ($conditionText) ...$thenText';
+      }
+    } else if (argument is ListLiteral) {
+      // ..addAll([ ... ])
+      NodeList<CollectionElement> elements = argument.elements;
+      if (elements.isEmpty) {
+        // TODO(brianwilkerson) Consider adding a cleanup for the empty list
+        //  case. We can essentially remove the whole invocation because it does
+        //  nothing.
+        return null;
+      }
+      int startOffset = elements.first.offset;
+      int endOffset = elements.last.end;
+      elementText = utils.getText(startOffset, endOffset - startOffset);
+      change.isLineInvocation = true;
+      args = ['addAll'];
+    }
+    elementText ??= '...${utils.getNodeText(argument)}';
+    DartChangeBuilder changeBuilder = _newDartChangeBuilder();
+    await changeBuilder.addFileEdit(file, (DartFileEditBuilder builder) {
+      if (list.elements.isNotEmpty) {
+        // ['a']..addAll(['b', 'c']);
+        builder.addSimpleInsertion(list.elements.last.end, ', $elementText');
+      } else {
+        // []..addAll(['b', 'c']);
+        builder.addSimpleInsertion(list.leftBracket.end, elementText);
+      }
+      builder.addDeletion(range.node(invocation));
+    });
+    change.args = args;
+    change.builder = changeBuilder;
+    return change;
+  }
+
   Future<ChangeBuilder>
       createBuilder_convertConditionalExpressionToIfElement() async {
     AstNode node = this.node.thisOrAncestorOfType<ConditionalExpression>();
@@ -649,6 +557,111 @@
     return changeBuilder;
   }
 
+  Future<ChangeBuilder> createBuilder_convertQuotes(bool fromDouble) async {
+    if (node is SimpleStringLiteral) {
+      SimpleStringLiteral literal = node;
+      if (fromDouble ? !literal.isSingleQuoted : literal.isSingleQuoted) {
+        String newQuote = literal.isMultiline
+            ? (fromDouble ? "'''" : '"""')
+            : (fromDouble ? "'" : '"');
+        int quoteLength = literal.isMultiline ? 3 : 1;
+        String lexeme = literal.literal.lexeme;
+        if (lexeme.indexOf(newQuote) < 0) {
+          var changeBuilder = _newDartChangeBuilder();
+          await changeBuilder.addFileEdit(file, (DartFileEditBuilder builder) {
+            builder.addSimpleReplacement(
+                new SourceRange(
+                    literal.offset + (literal.isRaw ? 1 : 0), quoteLength),
+                newQuote);
+            builder.addSimpleReplacement(
+                new SourceRange(literal.end - quoteLength, quoteLength),
+                newQuote);
+          });
+          return changeBuilder;
+        }
+      }
+    } else if (node is InterpolationString) {
+      StringInterpolation parent = node.parent;
+      if (fromDouble ? !parent.isSingleQuoted : parent.isSingleQuoted) {
+        String newQuote = parent.isMultiline
+            ? (fromDouble ? "'''" : '"""')
+            : (fromDouble ? "'" : '"');
+        int quoteLength = parent.isMultiline ? 3 : 1;
+        NodeList<InterpolationElement> elements = parent.elements;
+        for (int i = 0; i < elements.length; i++) {
+          InterpolationElement element = elements[i];
+          if (element is InterpolationString) {
+            String lexeme = element.contents.lexeme;
+            if (lexeme.indexOf(newQuote) >= 0) {
+              return null;
+            }
+          }
+        }
+        var changeBuilder = _newDartChangeBuilder();
+        await changeBuilder.addFileEdit(file, (DartFileEditBuilder builder) {
+          builder.addSimpleReplacement(
+              new SourceRange(
+                  parent.offset + (parent.isRaw ? 1 : 0), quoteLength),
+              newQuote);
+          builder.addSimpleReplacement(
+              new SourceRange(parent.end - quoteLength, quoteLength), newQuote);
+        });
+        return changeBuilder;
+      }
+    }
+    return null;
+  }
+
+  Future<ChangeBuilder> createBuilder_convertToExpressionFunctionBody() async {
+    // prepare current body
+    FunctionBody body = getEnclosingFunctionBody();
+    if (body is! BlockFunctionBody || body.isGenerator) {
+      _coverageMarker();
+      return null;
+    }
+    // prepare return statement
+    List<Statement> statements = (body as BlockFunctionBody).block.statements;
+    if (statements.length != 1) {
+      _coverageMarker();
+      return null;
+    }
+    Statement onlyStatement = statements.first;
+    // prepare returned expression
+    Expression returnExpression;
+    if (onlyStatement is ReturnStatement) {
+      returnExpression = onlyStatement.expression;
+    } else if (onlyStatement is ExpressionStatement) {
+      returnExpression = onlyStatement.expression;
+    }
+    if (returnExpression == null) {
+      _coverageMarker();
+      return null;
+    }
+
+    // Return expressions can be quite large, e.g. Flutter build() methods.
+    // It is surprising to see this Quick Assist deep in the function body.
+    if (selectionOffset >= returnExpression.offset) {
+      _coverageMarker();
+      return null;
+    }
+
+    var changeBuilder = _newDartChangeBuilder();
+    await changeBuilder.addFileEdit(file, (DartFileEditBuilder builder) {
+      builder.addReplacement(range.node(body), (DartEditBuilder builder) {
+        if (body.isAsynchronous) {
+          builder.write('async ');
+        }
+        builder.write('=> ');
+        builder.write(_getNodeText(returnExpression));
+        if (body.parent is! FunctionExpression ||
+            body.parent.parent is FunctionDeclaration) {
+          builder.write(';');
+        }
+      });
+    });
+    return changeBuilder;
+  }
+
   Future<ChangeBuilder> createBuilder_convertToIntLiteral() async {
     if (node is! DoubleLiteral) {
       _coverageMarker();
@@ -676,6 +689,135 @@
     return changeBuilder;
   }
 
+  Future<ChangeBuilder> createBuilder_convertToNullAware() async {
+    AstNode node = this.node;
+    if (node is! ConditionalExpression) {
+      _coverageMarker();
+      return null;
+    }
+    ConditionalExpression conditional = node;
+    Expression condition = conditional.condition.unParenthesized;
+    SimpleIdentifier identifier;
+    Expression nullExpression;
+    Expression nonNullExpression;
+    int periodOffset;
+
+    if (condition is BinaryExpression) {
+      //
+      // Identify the variable being compared to `null`, or return if the
+      // condition isn't a simple comparison of `null` to a variable's value.
+      //
+      Expression leftOperand = condition.leftOperand;
+      Expression rightOperand = condition.rightOperand;
+      if (leftOperand is NullLiteral && rightOperand is SimpleIdentifier) {
+        identifier = rightOperand;
+      } else if (rightOperand is NullLiteral &&
+          leftOperand is SimpleIdentifier) {
+        identifier = leftOperand;
+      } else {
+        _coverageMarker();
+        return null;
+      }
+      if (identifier.staticElement is! LocalElement) {
+        _coverageMarker();
+        return null;
+      }
+      //
+      // Identify the expression executed when the variable is `null` and when
+      // it is non-`null`. Return if the `null` expression isn't a null literal
+      // or if the non-`null` expression isn't a method invocation whose target
+      // is the save variable being compared to `null`.
+      //
+      if (condition.operator.type == TokenType.EQ_EQ) {
+        nullExpression = conditional.thenExpression;
+        nonNullExpression = conditional.elseExpression;
+      } else if (condition.operator.type == TokenType.BANG_EQ) {
+        nonNullExpression = conditional.thenExpression;
+        nullExpression = conditional.elseExpression;
+      }
+      if (nullExpression == null || nonNullExpression == null) {
+        _coverageMarker();
+        return null;
+      }
+      if (nullExpression.unParenthesized is! NullLiteral) {
+        _coverageMarker();
+        return null;
+      }
+      Expression unwrappedExpression = nonNullExpression.unParenthesized;
+      Expression target;
+      Token operator;
+      if (unwrappedExpression is MethodInvocation) {
+        target = unwrappedExpression.target;
+        operator = unwrappedExpression.operator;
+      } else if (unwrappedExpression is PrefixedIdentifier) {
+        target = unwrappedExpression.prefix;
+        operator = unwrappedExpression.period;
+      } else {
+        _coverageMarker();
+        return null;
+      }
+      if (operator.type != TokenType.PERIOD) {
+        _coverageMarker();
+        return null;
+      }
+      if (!(target is SimpleIdentifier &&
+          target.staticElement == identifier.staticElement)) {
+        _coverageMarker();
+        return null;
+      }
+      periodOffset = operator.offset;
+
+      DartChangeBuilder changeBuilder = _newDartChangeBuilder();
+      await changeBuilder.addFileEdit(file, (DartFileEditBuilder builder) {
+        builder.addDeletion(range.startStart(node, nonNullExpression));
+        builder.addSimpleInsertion(periodOffset, '?');
+        builder.addDeletion(range.endEnd(nonNullExpression, node));
+      });
+      return changeBuilder;
+    }
+    return null;
+  }
+
+  Future<ChangeBuilder> createBuilder_convertToPackageImport() async {
+    var node = this.node;
+    if (node is StringLiteral) {
+      node = node.parent;
+    }
+    if (node is ImportDirective) {
+      ImportDirective importDirective = node;
+      var uriSource = importDirective.uriSource;
+
+      // Ignore if invalid URI.
+      if (uriSource == null) {
+        return null;
+      }
+
+      var importUri = uriSource.uri;
+      if (importUri.scheme != 'package') {
+        return null;
+      }
+
+      // Don't offer to convert a 'package:' URI to itself.
+      try {
+        if (Uri.parse(importDirective.uriContent).scheme == 'package') {
+          return null;
+        }
+      } on FormatException {
+        return null;
+      }
+
+      var changeBuilder = _newDartChangeBuilder();
+      await changeBuilder.addFileEdit(file, (builder) {
+        builder.addSimpleReplacement(
+          range.node(importDirective.uri),
+          "'$importUri'",
+        );
+      });
+      return changeBuilder;
+    }
+    return null;
+  }
+
   @protected
   Future<ChangeBuilder> createBuilder_useCurlyBraces() async {
     Future<ChangeBuilder> doStatement(DoStatement node) async {
@@ -803,6 +945,39 @@
     return null;
   }
 
+  FunctionBody getEnclosingFunctionBody() {
+    // TODO(brianwilkerson) Determine whether there is a reason why this method
+    // isn't just "return node.getAncestor((node) => node is FunctionBody);"
+    {
+      FunctionExpression function =
+          node.thisOrAncestorOfType<FunctionExpression>();
+      if (function != null) {
+        return function.body;
+      }
+    }
+    {
+      FunctionDeclaration function =
+          node.thisOrAncestorOfType<FunctionDeclaration>();
+      if (function != null) {
+        return function.functionExpression.body;
+      }
+    }
+    {
+      ConstructorDeclaration constructor =
+          node.thisOrAncestorOfType<ConstructorDeclaration>();
+      if (constructor != null) {
+        return constructor.body;
+      }
+    }
+    {
+      MethodDeclaration method = node.thisOrAncestorOfType<MethodDeclaration>();
+      if (method != null) {
+        return method.body;
+      }
+    }
+    return null;
+  }
+
   @protected
   bool setupCompute() {
     final locator = NodeLocator(selectionOffset, selectionEnd);
@@ -822,6 +997,10 @@
     }
   }
 
+  /// Returns the text of the given node in the unit.
+  String /* TODO (pq): make visible */ _getNodeText(AstNode node) =>
+      utils.getNodeText(node);
+
   DartChangeBuilder _newDartChangeBuilder() =>
       DartChangeBuilderImpl.forWorkspace(workspace);
 
@@ -833,6 +1012,12 @@
   static void _coverageMarker() {}
 }
 
+class ConvertToSpreadCollectionsChange {
+  ChangeBuilder builder;
+  List<String> args;
+  bool isLineInvocation = false;
+}
+
 /// A visitor that can be used to find references to a parameter.
 class _ParameterReferenceFinder extends RecursiveAstVisitor<void> {
   /// The parameter for which references are being sought, or `null` if we are
diff --git a/pkg/analysis_server/lib/src/services/correction/fix.dart b/pkg/analysis_server/lib/src/services/correction/fix.dart
index ff70d93..bac44cb 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix.dart
@@ -199,6 +199,12 @@
       'CONVERT_TO_NAMED_ARGUMENTS', 50, "Convert to named arguments");
   static const CONVERT_TO_NULL_AWARE =
       const FixKind('CONVERT_TO_NULL_AWARE', 50, "Convert to use '?.'");
+  static const CONVERT_TO_PACKAGE_IMPORT = const FixKind(
+      'CONVERT_TO_PACKAGE_IMPORT', 50, "Convert to 'package:' import");
+  static const CONVERT_TO_SINGLE_QUOTED_STRING = const FixKind(
+      'CONVERT_TO_SINGLE_QUOTED_STRING', 50, "Convert to single quoted string");
+  static const CONVERT_TO_SPREAD =
+      const FixKind('CONVERT_TO_SPREAD', 50, "Convert to a spread");
   static const CREATE_CLASS =
       const FixKind('CREATE_CLASS', 50, "Create class '{0}'");
   static const CREATE_CONSTRUCTOR =
@@ -245,6 +251,8 @@
       const FixKind('IMPORT_LIBRARY_SDK', 54, "Import library '{0}'");
   static const IMPORT_LIBRARY_SHOW =
       const FixKind('IMPORT_LIBRARY_SHOW', 55, "Update library '{0}' import");
+  static const INLINE_INVOCATION =
+      const FixKind('INLINE_INVOCATION', 30, "Inline invocation of '{0}'");
   static const INSERT_SEMICOLON =
       const FixKind('INSERT_SEMICOLON', 50, "Insert ';'");
   static const MAKE_CLASS_ABSTRACT =
diff --git a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
index 0a857ce..491d0e2 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
@@ -585,6 +585,9 @@
       if (name == LintNames.avoid_init_to_null) {
         await _addFix_removeInitializer();
       }
+      if (name == LintNames.avoid_relative_lib_imports) {
+        await _addFix_convertToPackageImport();
+      }
       if (name == LintNames.avoid_return_types_on_setters) {
         await _addFix_removeTypeAnnotation();
       }
@@ -656,9 +659,15 @@
       if (name == LintNames.prefer_null_aware_operators) {
         await _addFix_convertToNullAware();
       }
+      if (name == LintNames.prefer_single_quotes) {
+        await _addFix_convertSingleQuotes();
+      }
       if (errorCode.name == LintNames.slash_for_doc_comments) {
         await _addFix_convertDocumentationIntoLine();
       }
+      if (name == LintNames.prefer_spread_collections) {
+        await _addFix_convertAddAllToSpread();
+      }
       if (name == LintNames.type_init_formals) {
         await _addFix_removeTypeAnnotation();
       }
@@ -738,11 +747,6 @@
     _addFixFromBuilder(changeBuilder, DartFixKind.ADD_CURLY_BRACES);
   }
 
-  Future<void> _addFix_convertToNullAware() async {
-    final changeBuilder = await createBuilder_convertToNullAware();
-    _addFixFromBuilder(changeBuilder, DartFixKind.CONVERT_TO_NULL_AWARE);
-  }
-
   Future<void> _addFix_addExplicitCast() async {
     if (coveredNode is! Expression) {
       return;
@@ -1368,6 +1372,12 @@
     _addFixFromBuilder(changeBuilder, DartFixKind.CONVERT_TO_FOR_ELEMENT);
   }
 
+  Future<void> _addFix_convertSingleQuotes() async {
+    final changeBuilder = await createBuilder_convertQuotes(true);
+    _addFixFromBuilder(
+        changeBuilder, DartFixKind.CONVERT_TO_SINGLE_QUOTED_STRING);
+  }
+
   Future<void> _addFix_convertToExpressionBody() async {
     final changeBuilder = await createBuilder_convertToExpressionFunctionBody();
     _addFixFromBuilder(changeBuilder, DartFixKind.CONVERT_INTO_EXPRESSION_BODY);
@@ -1449,6 +1459,16 @@
     }
   }
 
+  Future<void> _addFix_convertToNullAware() async {
+    final changeBuilder = await createBuilder_convertToNullAware();
+    _addFixFromBuilder(changeBuilder, DartFixKind.CONVERT_TO_NULL_AWARE);
+  }
+
+  Future<void> _addFix_convertToPackageImport() async {
+    final changeBuilder = await createBuilder_convertToPackageImport();
+    _addFixFromBuilder(changeBuilder, DartFixKind.CONVERT_TO_PACKAGE_IMPORT);
+  }
+
   Future<void> _addFix_createClass() async {
     Element prefixElement = null;
     String name = null;
@@ -1857,6 +1877,16 @@
     }
   }
 
+  Future<void> _addFix_convertAddAllToSpread() async {
+    final change = await createBuilder_convertAddAllToSpread();
+    if (change != null) {
+      final kind = change.isLineInvocation
+          ? DartFixKind.INLINE_INVOCATION
+          : DartFixKind.CONVERT_TO_SPREAD;
+      _addFixFromBuilder(change.builder, kind, args: change.args);
+    }
+  }
+
   Future<void> _addFix_createField() async {
     if (node is! SimpleIdentifier) {
       return;
diff --git a/pkg/analysis_server/lib/src/services/linter/lint_names.dart b/pkg/analysis_server/lib/src/services/linter/lint_names.dart
index c52000b..b935e7f 100644
--- a/pkg/analysis_server/lib/src/services/linter/lint_names.dart
+++ b/pkg/analysis_server/lib/src/services/linter/lint_names.dart
@@ -12,6 +12,7 @@
       'avoid_annotating_with_dynamic';
   static const String avoid_empty_else = 'avoid_empty_else';
   static const String avoid_init_to_null = 'avoid_init_to_null';
+  static const String avoid_relative_lib_imports = 'avoid_relative_lib_imports';
   static const String avoid_return_types_on_setters =
       'avoid_return_types_on_setters';
   static const String avoid_types_on_closure_parameters =
@@ -46,7 +47,9 @@
   static const String prefer_is_not_empty = 'prefer_is_not_empty';
   static const String prefer_null_aware_operators =
       'prefer_null_aware_operators';
+  static const String prefer_single_quotes = 'prefer_single_quotes';
   static const String slash_for_doc_comments = 'slash_for_doc_comments';
+  static const String prefer_spread_collections = 'prefer_spread_collections';
   static const String type_annotate_public_apis = 'type_annotate_public_apis';
   static const String type_init_formals = 'type_init_formals';
   static const String unawaited_futures = 'unawaited_futures';
diff --git a/pkg/analysis_server/test/src/domains/completion/get_suggestions_available_test.dart b/pkg/analysis_server/test/src/domains/completion/get_suggestions_available_test.dart
index e6704f8..d9f168d 100644
--- a/pkg/analysis_server/test/src/domains/completion/get_suggestions_available_test.dart
+++ b/pkg/analysis_server/test/src/domains/completion/get_suggestions_available_test.dart
@@ -181,6 +181,7 @@
         ElementKind.CONSTRUCTOR,
         ElementKind.ENUM,
         ElementKind.ENUM_CONSTANT,
+        ElementKind.EXTENSION,
         ElementKind.FUNCTION,
         ElementKind.FUNCTION_TYPE_ALIAS,
         ElementKind.MIXIN,
diff --git a/pkg/analysis_server/test/src/services/correction/assist/convert_to_package_import_test.dart b/pkg/analysis_server/test/src/services/correction/assist/convert_to_package_import_test.dart
index 84df167..9da35b6 100644
--- a/pkg/analysis_server/test/src/services/correction/assist/convert_to_package_import_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/assist/convert_to_package_import_test.dart
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:analysis_server/src/services/correction/assist.dart';
+import 'package:analysis_server/src/services/linter/lint_names.dart';
 import 'package:analyzer_plugin/utilities/assist/assist.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
@@ -52,7 +53,7 @@
 
   test_nonPackage_Uri() async {
     addSource('/home/test/lib/foo.dart', '');
-
+    testFile = convertPath('/home/test/lib/src/test.dart');
     await resolveTestUnit('''
 import 'dart:core';
 ''');
@@ -83,4 +84,15 @@
 import 'package:test/foo/bar.dart';
 ''');
   }
+
+  test_relativeImport_noAssistWithLint() async {
+    createAnalysisOptionsFile(lints: [LintNames.avoid_relative_lib_imports]);
+    verifyNoTestUnitErrors = false;
+    addSource('/home/test/lib/foo.dart', '');
+
+    await resolveTestUnit('''
+import '../lib/foo.dart';
+''');
+    await assertNoAssist();
+  }
 }
diff --git a/pkg/analysis_server/test/src/services/correction/assist/convert_to_single_quoted_string_test.dart b/pkg/analysis_server/test/src/services/correction/assist/convert_to_single_quoted_string_test.dart
index 161f62c..6c34598 100644
--- a/pkg/analysis_server/test/src/services/correction/assist/convert_to_single_quoted_string_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/assist/convert_to_single_quoted_string_test.dart
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:analysis_server/src/services/correction/assist.dart';
+import 'package:analysis_server/src/services/linter/lint_names.dart';
 import 'package:analyzer_plugin/utilities/assist/assist.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
@@ -80,6 +81,17 @@
 ''');
   }
 
+  test_one_simple_noAssistWithLint() async {
+    createAnalysisOptionsFile(lints: [LintNames.prefer_single_quotes]);
+    verifyNoTestUnitErrors = false;
+    await resolveTestUnit('''
+main() {
+  print("abc");
+}
+''');
+    await assertNoAssist();
+  }
+
   test_three_embeddedTarget() async {
     await resolveTestUnit('''
 main() {
diff --git a/pkg/analysis_server/test/src/services/correction/assist/convert_to_spread_test.dart b/pkg/analysis_server/test/src/services/correction/assist/convert_to_spread_test.dart
index 6242b56..4e354c7 100644
--- a/pkg/analysis_server/test/src/services/correction/assist/convert_to_spread_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/assist/convert_to_spread_test.dart
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:analysis_server/src/services/correction/assist.dart';
+import 'package:analysis_server/src/services/linter/lint_names.dart';
 import 'package:analyzer/src/dart/analysis/experiments.dart';
 import 'package:analyzer_plugin/utilities/assist/assist.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
@@ -41,6 +42,18 @@
 ''');
   }
 
+  test_addAll_expression_noAssistWithLint() async {
+    createAnalysisOptionsFile(lints: [LintNames.prefer_spread_collections]);
+    verifyNoTestUnitErrors = false;
+    await resolveTestUnit('''
+f() {
+  var ints = [1, 2, 3];
+  print(['a']..addAl/*caret*/l(ints.map((i) => i.toString()))..addAll(['c']));
+}
+''');
+    await assertNoAssist();
+  }
+
   test_addAll_expression_toEmptyList() async {
     await resolveTestUnit('''
 f() {
diff --git a/pkg/analysis_server/test/src/services/correction/fix/convert_to_package_import_test.dart b/pkg/analysis_server/test/src/services/correction/fix/convert_to_package_import_test.dart
new file mode 100644
index 0000000..dfa4706
--- /dev/null
+++ b/pkg/analysis_server/test/src/services/correction/fix/convert_to_package_import_test.dart
@@ -0,0 +1,38 @@
+// 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:analysis_server/src/services/correction/fix.dart';
+import 'package:analysis_server/src/services/linter/lint_names.dart';
+import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import 'fix_processor.dart';
+
+main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(ConvertToPackageImportTest);
+  });
+}
+
+@reflectiveTest
+class ConvertToPackageImportTest extends FixProcessorLintTest {
+  @override
+  FixKind get kind => DartFixKind.CONVERT_TO_PACKAGE_IMPORT;
+
+  @override
+  String get lintCode => LintNames.avoid_relative_lib_imports;
+
+  /// More coverage in the `convert_to_package_import_test.dart` assist test.
+  test_relativeImport() async {
+    addSource('/home/test/lib/foo.dart', '');
+    testFile = convertPath('/home/test/lib/src/test.dart');
+    await resolveTestUnit('''
+import /*LINT*/'../lib/foo.dart';
+''');
+
+    await assertHasFix('''
+import /*LINT*/'package:test/lib/foo.dart';
+''');
+  }
+}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/convert_to_single_quoted_string_test.dart b/pkg/analysis_server/test/src/services/correction/fix/convert_to_single_quoted_string_test.dart
new file mode 100644
index 0000000..97e2746
--- /dev/null
+++ b/pkg/analysis_server/test/src/services/correction/fix/convert_to_single_quoted_string_test.dart
@@ -0,0 +1,39 @@
+// 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:analysis_server/src/services/correction/fix.dart';
+import 'package:analysis_server/src/services/linter/lint_names.dart';
+import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import 'fix_processor.dart';
+
+main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(ConvertToSingleQuotedStringTest);
+  });
+}
+
+@reflectiveTest
+class ConvertToSingleQuotedStringTest extends FixProcessorLintTest {
+  @override
+  FixKind get kind => DartFixKind.CONVERT_TO_SINGLE_QUOTED_STRING;
+
+  @override
+  String get lintCode => LintNames.prefer_single_quotes;
+
+  /// More coverage in the `convert_to_single_quoted_string_test.dart` assist test.
+  test_one_simple() async {
+    await resolveTestUnit('''
+main() {
+  print(/*LINT*/"abc");
+}
+''');
+    await assertHasFix('''
+main() {
+  print(/*LINT*/'abc');
+}
+''');
+  }
+}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/convert_to_spread_test.dart b/pkg/analysis_server/test/src/services/correction/fix/convert_to_spread_test.dart
new file mode 100644
index 0000000..a2cf96e
--- /dev/null
+++ b/pkg/analysis_server/test/src/services/correction/fix/convert_to_spread_test.dart
@@ -0,0 +1,41 @@
+// 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:analysis_server/src/services/correction/fix.dart';
+import 'package:analysis_server/src/services/linter/lint_names.dart';
+import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import 'fix_processor.dart';
+
+main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(ConvertToSpreadTest);
+  });
+}
+
+@reflectiveTest
+class ConvertToSpreadTest extends FixProcessorLintTest {
+  @override
+  FixKind get kind => DartFixKind.CONVERT_TO_SPREAD;
+
+  @override
+  String get lintCode => LintNames.prefer_spread_collections;
+
+  /// More coverage in the `convert_to_spread_test.dart` assist test.
+  test_addAll_expression() async {
+    await resolveTestUnit('''
+f() {
+  var ints = [1, 2, 3];
+  print(['a']../*LINT*/addAll(ints.map((i) => i.toString()))..addAll(['c']));
+}
+''');
+    await assertHasFix('''
+f() {
+  var ints = [1, 2, 3];
+  print(['a', ...ints.map((i) => i.toString())]..addAll(['c']));
+}
+''');
+  }
+}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/test_all.dart b/pkg/analysis_server/test/src/services/correction/fix/test_all.dart
index 67efef9..4e74718 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/test_all.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/test_all.dart
@@ -43,6 +43,10 @@
 import 'convert_to_int_literal_test.dart' as convert_to_int_literal;
 import 'convert_to_named_arguments_test.dart' as convert_to_named_arguments;
 import 'convert_to_null_aware_test.dart' as convert_to_null_aware;
+import 'convert_to_package_import_test.dart' as convert_to_package_import;
+import 'convert_to_single_quoted_string_test.dart'
+    as convert_to_single_quoted_string;
+import 'convert_to_spread_test.dart' as convert_to_spread;
 import 'create_class_test.dart' as create_class;
 import 'create_constructor_for_final_fields_test.dart'
     as create_constructor_for_final_field;
@@ -156,6 +160,9 @@
     convert_to_int_literal.main();
     convert_to_named_arguments.main();
     convert_to_null_aware.main();
+    convert_to_package_import.main();
+    convert_to_single_quoted_string.main();
+    convert_to_spread.main();
     create_class.main();
     create_constructor_for_final_field.main();
     create_constructor_super.main();
diff --git a/pkg/analyzer/lib/dart/ast/ast.dart b/pkg/analyzer/lib/dart/ast/ast.dart
index 1b18be9..02fdde9 100644
--- a/pkg/analyzer/lib/dart/ast/ast.dart
+++ b/pkg/analyzer/lib/dart/ast/ast.dart
@@ -825,7 +825,8 @@
 ///        [Expression] cascadeSection*
 ///
 ///    cascadeSection ::=
-///        '..'  (cascadeSelector arguments*) (assignableSelector arguments*)*
+///        ('..' | '?..') (cascadeSelector arguments*)
+///        (assignableSelector arguments*)*
 ///        (assignmentOperator expressionWithoutCascade)?
 ///
 ///    cascadeSelector ::=
diff --git a/pkg/analyzer/lib/src/dart/ast/ast.dart b/pkg/analyzer/lib/src/dart/ast/ast.dart
index 2b09546..0d75a23 100644
--- a/pkg/analyzer/lib/src/dart/ast/ast.dart
+++ b/pkg/analyzer/lib/src/dart/ast/ast.dart
@@ -2396,6 +2396,8 @@
     ErrorCode errorCode = error.errorCode;
     if (errorCode is CompileTimeErrorCode) {
       switch (errorCode) {
+        case CompileTimeErrorCode
+            .CONST_CONSTRUCTOR_WITH_FIELD_INITIALIZED_BY_NON_CONST:
         case CompileTimeErrorCode.CONST_EVAL_TYPE_BOOL:
         case CompileTimeErrorCode.CONST_EVAL_TYPE_BOOL_INT:
         case CompileTimeErrorCode.CONST_EVAL_TYPE_BOOL_NUM_STRING:
@@ -2405,8 +2407,7 @@
         case CompileTimeErrorCode.CONST_EVAL_THROWS_IDBZE:
         case CompileTimeErrorCode.CONST_WITH_NON_CONST:
         case CompileTimeErrorCode.CONST_WITH_NON_CONSTANT_ARGUMENT:
-        case CompileTimeErrorCode
-            .CONST_CONSTRUCTOR_WITH_FIELD_INITIALIZED_BY_NON_CONST:
+        case CompileTimeErrorCode.CONST_WITH_TYPE_PARAMETERS:
         case CompileTimeErrorCode.INVALID_CONSTANT:
         case CompileTimeErrorCode.MISSING_CONST_IN_LIST_LITERAL:
         case CompileTimeErrorCode.MISSING_CONST_IN_MAP_LITERAL:
@@ -5912,8 +5913,8 @@
   /// index expression is part of a cascade expression.
   ExpressionImpl _target;
 
-  /// The period ("..") before a cascaded index expression, or `null` if this
-  /// index expression is not part of a cascade expression.
+  /// The period (".." | "?..") before a cascaded index expression,
+  /// or `null` if this index expression is not part of a cascade expression.
   @override
   Token period;
 
@@ -7130,7 +7131,7 @@
   /// The operator that separates the target from the method name, or `null`
   /// if there is no target. In an ordinary method invocation this will be a
   /// period ('.'). In a cascade section this will be the cascade operator
-  /// ('..').
+  /// ('..' | '?..').
   @override
   Token operator;
 
@@ -7179,7 +7180,9 @@
 
   @override
   bool get isCascaded =>
-      operator != null && operator.type == TokenType.PERIOD_PERIOD;
+      operator != null &&
+      (operator.type == TokenType.PERIOD_PERIOD ||
+          operator.type == TokenType.QUESTION_PERIOD_PERIOD);
 
   @override
   SimpleIdentifier get methodName => _methodName;
@@ -8436,7 +8439,9 @@
 
   @override
   bool get isCascaded =>
-      operator != null && operator.type == TokenType.PERIOD_PERIOD;
+      operator != null &&
+      (operator.type == TokenType.PERIOD_PERIOD ||
+          operator.type == TokenType.QUESTION_PERIOD_PERIOD);
 
   @override
   Precedence get precedence => Precedence.postfix;
diff --git a/pkg/analyzer/lib/src/dart/ast/utilities.dart b/pkg/analyzer/lib/src/dart/ast/utilities.dart
index bbff1e7..86d5b66 100644
--- a/pkg/analyzer/lib/src/dart/ast/utilities.dart
+++ b/pkg/analyzer/lib/src/dart/ast/utilities.dart
@@ -7526,7 +7526,7 @@
   @override
   void visitIndexExpression(IndexExpression node) {
     if (node.isCascaded) {
-      _writer.print("..");
+      _writer.print(node.period.lexeme);
     } else {
       _visitNode(node.target);
     }
@@ -7635,7 +7635,7 @@
   @override
   void visitMethodInvocation(MethodInvocation node) {
     if (node.isCascaded) {
-      _writer.print("..");
+      _writer.print(node.operator.lexeme);
     } else {
       if (node.target != null) {
         node.target.accept(this);
@@ -7735,7 +7735,7 @@
   @override
   void visitPropertyAccess(PropertyAccess node) {
     if (node.isCascaded) {
-      _writer.print("..");
+      _writer.print(node.operator.lexeme);
     } else {
       _visitNode(node.target);
       _writer.print(node.operator.lexeme);
@@ -8833,7 +8833,7 @@
   @override
   void visitIndexExpression(IndexExpression node) {
     if (node.isCascaded) {
-      sink.write("..");
+      sink.write(node.period.lexeme);
     } else {
       safelyVisitNode(node.target);
     }
@@ -8942,7 +8942,7 @@
   @override
   void visitMethodInvocation(MethodInvocation node) {
     if (node.isCascaded) {
-      sink.write("..");
+      sink.write(node.operator.lexeme);
     } else {
       if (node.target != null) {
         node.target.accept(this);
@@ -9042,7 +9042,7 @@
   @override
   void visitPropertyAccess(PropertyAccess node) {
     if (node.isCascaded) {
-      sink.write("..");
+      sink.write(node.operator.lexeme);
     } else {
       safelyVisitNode(node.target);
       sink.write(node.operator.lexeme);
diff --git a/pkg/analyzer/lib/src/dart/error/hint_codes.dart b/pkg/analyzer/lib/src/dart/error/hint_codes.dart
index 76ba63d..0d8b1c2 100644
--- a/pkg/analyzer/lib/src/dart/error/hint_codes.dart
+++ b/pkg/analyzer/lib/src/dart/error/hint_codes.dart
@@ -734,7 +734,7 @@
    */
   static const HintCode SDK_VERSION_EXTENSION_METHODS = const HintCode(
       'SDK_VERSION_EXTENSION_METHODS',
-      "Extension methods weren't supported until version 2.X.0, "
+      "Extension methods weren't supported until version 2.6.0, "
           "but this code is required to be able to run on earlier versions.",
       correction: "Try updating the SDK constraints.");
 
diff --git a/pkg/analyzer/lib/src/error/literal_element_verifier.dart b/pkg/analyzer/lib/src/error/literal_element_verifier.dart
index 5e2e26c..fb2cced 100644
--- a/pkg/analyzer/lib/src/error/literal_element_verifier.dart
+++ b/pkg/analyzer/lib/src/error/literal_element_verifier.dart
@@ -4,7 +4,6 @@
 
 import 'package:analyzer/dart/analysis/features.dart';
 import 'package:analyzer/dart/ast/ast.dart';
-import 'package:analyzer/dart/ast/token.dart';
 import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer/error/listener.dart';
 import 'package:analyzer/src/dart/element/type.dart';
diff --git a/pkg/analyzer/lib/src/fasta/ast_builder.dart b/pkg/analyzer/lib/src/fasta/ast_builder.dart
index f45a35a..fa944a9 100644
--- a/pkg/analyzer/lib/src/fasta/ast_builder.dart
+++ b/pkg/analyzer/lib/src/fasta/ast_builder.dart
@@ -169,7 +169,7 @@
   }
 
   void beginCascade(Token token) {
-    assert(optional('..', token));
+    assert(optional('..', token) || optional('?..', token));
     debugEvent("beginCascade");
 
     Expression expression = pop();
@@ -577,12 +577,14 @@
     assert(operatorToken.isOperator ||
         optional('.', operatorToken) ||
         optional('?.', operatorToken) ||
-        optional('..', operatorToken));
+        optional('..', operatorToken) ||
+        optional('?..', operatorToken));
     debugEvent("BinaryExpression");
 
     if (identical(".", operatorToken.stringValue) ||
         identical("?.", operatorToken.stringValue) ||
-        identical("..", operatorToken.stringValue)) {
+        identical("..", operatorToken.stringValue) ||
+        identical("?..", operatorToken.stringValue)) {
       doDotExpression(operatorToken);
     } else {
       Expression right = pop();
diff --git a/pkg/analyzer/lib/src/generated/element_resolver.dart b/pkg/analyzer/lib/src/generated/element_resolver.dart
index 8518284..e91190e 100644
--- a/pkg/analyzer/lib/src/generated/element_resolver.dart
+++ b/pkg/analyzer/lib/src/generated/element_resolver.dart
@@ -173,8 +173,8 @@
         String methodName = operatorType.lexeme;
         // TODO(brianwilkerson) Change the [methodNameNode] from the left hand
         //  side to the operator.
-        ResolutionResult result =
-            _lookUpMethod(leftHandSide, staticType, methodName, leftHandSide);
+        var result = _newPropertyResolver().resolveOperator(
+            leftHandSide, staticType, methodName, leftHandSide);
         node.staticElement = result.function;
         if (_shouldReportInvalidMember(staticType, result)) {
           _recordUndefinedToken(
@@ -266,20 +266,11 @@
         }
         if (node.newKeyword == null) {
           if (element is ClassElement) {
-            Element memberElement =
-                _lookupGetterOrMethod(element.type, name.name);
-            if (memberElement == null) {
-              memberElement = element.getNamedConstructor(name.name);
-              if (memberElement == null) {
-                memberElement =
-                    _lookUpSetter(prefix, element.type, name.name, name).setter;
-              }
-            }
-            if (memberElement == null) {
-//              reportGetterOrSetterNotFound(identifier, name, element.getDisplayName());
-            } else {
-              name.staticElement = memberElement;
-            }
+            var propertyResolver = _newPropertyResolver();
+            propertyResolver.resolve(prefix, element.type, name.name, name);
+            name.staticElement = propertyResolver.getterResult.getter ??
+                propertyResolver.setterResult.setter ??
+                element.getNamedConstructor(name.name);
           } else {
             // TODO(brianwilkerson) Report this error.
           }
@@ -481,16 +472,16 @@
     bool isInSetterContext = node.inSetterContext();
     if (isInGetterContext && isInSetterContext) {
       // lookup setter
-      ResolutionResult setterResult =
-          _lookUpMethod(target, staticType, setterMethodName, target);
+      ResolutionResult setterResult = _newPropertyResolver()
+          .resolveOperator(target, staticType, setterMethodName, target);
       // set setter element
       node.staticElement = setterResult.function;
       // generate undefined method warning
       _checkForUndefinedIndexOperator(
           node, target, setterMethodName, setterResult, staticType);
       // lookup getter method
-      ResolutionResult getterResult =
-          _lookUpMethod(target, staticType, getterMethodName, target);
+      ResolutionResult getterResult = _newPropertyResolver()
+          .resolveOperator(target, staticType, getterMethodName, target);
       // set getter element
       AuxiliaryElements auxiliaryElements =
           new AuxiliaryElements(getterResult.function, null);
@@ -500,8 +491,8 @@
           node, target, getterMethodName, getterResult, staticType);
     } else if (isInGetterContext) {
       // lookup getter method
-      ResolutionResult methodResult =
-          _lookUpMethod(target, staticType, getterMethodName, target);
+      ResolutionResult methodResult = _newPropertyResolver()
+          .resolveOperator(target, staticType, getterMethodName, target);
       // set getter element
       node.staticElement = methodResult.function;
       // generate undefined method warning
@@ -509,8 +500,8 @@
           node, target, getterMethodName, methodResult, staticType);
     } else if (isInSetterContext) {
       // lookup setter method
-      ResolutionResult methodResult =
-          _lookUpMethod(target, staticType, setterMethodName, target);
+      ResolutionResult methodResult = _newPropertyResolver()
+          .resolveOperator(target, staticType, setterMethodName, target);
       // set setter element
       node.staticElement = methodResult.function;
       // generate undefined method warning
@@ -566,10 +557,8 @@
     }
     String methodName = _getPostfixOperator(node);
     DartType staticType = _getStaticType(operand);
-    // TODO(brianwilkerson) Change the [methodNameNode] from the operand to
-    //  the operator.
-    ResolutionResult result =
-        _lookUpMethod(operand, staticType, methodName, operand);
+    var result = _newPropertyResolver()
+        .resolveOperator(operand, staticType, methodName, operand);
     node.staticElement = result.function;
     if (_shouldReportInvalidMember(staticType, result)) {
       if (operand is SuperExpression) {
@@ -674,10 +663,8 @@
       Expression operand = node.operand;
       String methodName = _getPrefixOperator(node);
       DartType staticType = _getStaticType(operand, read: true);
-      // TODO(brianwilkerson) Change the [methodNameNode] from the operand to
-      //  the operator.
-      ResolutionResult result =
-          _lookUpMethod(operand, staticType, methodName, operand);
+      var result = _newPropertyResolver()
+          .resolveOperator(operand, staticType, methodName, operand);
       node.staticElement = result.function;
       if (_shouldReportInvalidMember(staticType, result)) {
         if (operand is SuperExpression) {
@@ -874,9 +861,12 @@
         node.inGetterContext() &&
         enclosingClass != null) {
       InterfaceType enclosingType = enclosingClass.type;
-      AuxiliaryElements auxiliaryElements = new AuxiliaryElements(
-          _lookUpGetter(null, enclosingType, node.name, node).getter, null);
-      node.auxiliaryElements = auxiliaryElements;
+      var propertyResolver = _newPropertyResolver();
+      propertyResolver.resolve(null, enclosingType, node.name, node);
+      node.auxiliaryElements = AuxiliaryElements(
+        propertyResolver.getterResult.getter,
+        null,
+      );
     }
     //
     // Validate annotation element.
@@ -1090,8 +1080,10 @@
       parameterizableType = invokeType;
       parameters = invokeType.typeFormals;
     } else if (invokeType is InterfaceType) {
-      MethodElement callMethod =
-          _lookUpCallMethod(invokeType, invocation.function);
+      var propertyResolver = _newPropertyResolver();
+      propertyResolver.resolve(null, invokeType,
+          FunctionElement.CALL_METHOD_NAME, invocation.function);
+      MethodElement callMethod = propertyResolver.getterResult.function;
       invocation.staticElement = callMethod;
       parameterizableType = callMethod?.type;
       parameters = (parameterizableType as FunctionType)?.typeFormals;
@@ -1210,135 +1202,9 @@
     }
   }
 
-  /**
-   * Return the element representing the `call` method that is defined for the
-   * given [type]. If there are multiple `call` methods defined by extensions,
-   * use the given [node] to report the error.
-   */
-  MethodElement _lookUpCallMethod(InterfaceType type, Expression node) {
-    var callMethod = type.lookUpMethod(
-      FunctionElement.CALL_METHOD_NAME,
-      _resolver.definingLibrary,
-    );
-    if (callMethod != null) {
-      return callMethod;
-    }
-
-    var result = _extensionResolver.findExtension(
-        type, FunctionElement.CALL_METHOD_NAME, node);
-    var instantiatedMember = result.function;
-    if (instantiatedMember is MethodElement) {
-      return instantiatedMember;
-    }
-
-    return null;
-  }
-
-  /**
-   * Look up the getter with the given [name] in the given [type]. Return a
-   * result representing the result of that lookup. The [target] is the target
-   * of the invocation, or `null` if there is no target.
-   */
-  ResolutionResult _lookUpGetter(
-      Expression target, DartType type, String name, Expression nameNode) {
-    type = _resolveTypeParameter(type);
-    ResolutionResult result = ResolutionResult.none;
-
-    void lookupIn(InterfaceType type) {
-      var getter = type.lookUpInheritedGetter(name,
-          library: _definingLibrary, thisType: target is! SuperExpression);
-      if (getter != null) {
-        result = ResolutionResult(property: getter.variable);
-      }
-    }
-
-    if (type is InterfaceType) {
-      lookupIn(type);
-    } else if (type is FunctionType) {
-      lookupIn(_resolver.typeProvider.functionType);
-    } else {
-      return ResolutionResult.none;
-    }
-    if (result.isNone) {
-      result = _extensionResolver.findExtension(type, name, nameNode);
-    }
-    return result;
-  }
-
-  /**
-   * Look up the method or getter with the given [name] in the given
-   * [type]. Return the element representing the method or getter that was
-   * found, or `null` if there is no method or getter with the given name.
-   */
-  ExecutableElement _lookupGetterOrMethod(DartType type, String name) {
-    type = _resolveTypeParameter(type);
-    if (type is InterfaceType) {
-      return type.lookUpInheritedGetterOrMethod(name,
-          library: _definingLibrary);
-    }
-    return null;
-  }
-
-  /**
-   * Look up the method with the given [name] in the given [type]. Return a
-   * result representing the result of that lookup. The [target] is the target
-   * of the invocation, or `null` if there is no target.
-   */
-  ResolutionResult _lookUpMethod(
-      Expression target, DartType type, String name, Expression nameNode) {
-    type = _resolveTypeParameter(type);
-    ResolutionResult result = ResolutionResult.none;
-
-    void lookupIn(InterfaceType type) {
-      var method = type.lookUpInheritedMethod(name,
-          library: _definingLibrary, thisType: target is! SuperExpression);
-      if (method != null) {
-        result = ResolutionResult(function: method);
-      }
-    }
-
-    if (type is InterfaceType) {
-      lookupIn(type);
-    } else if (type is FunctionType) {
-      lookupIn(_resolver.typeProvider.functionType);
-    } else {
-      return ResolutionResult.none;
-    }
-    if (result.isNone) {
-      result = _extensionResolver.findExtension(type, name, nameNode);
-    }
-    return result;
-  }
-
-  /**
-   * Look up the setter with the given [name] in the given [type]. Return a
-   * result representing the result of that lookup. The [target] is the target
-   * of the invocation, or `null` if there is no target.
-   */
-  ResolutionResult _lookUpSetter(
-      Expression target, DartType type, String name, Expression nameNode) {
-    type = _resolveTypeParameter(type);
-    ResolutionResult result = ResolutionResult.none;
-
-    void lookupIn(InterfaceType type) {
-      var setter = type.lookUpInheritedSetter(name,
-          library: _definingLibrary, thisType: target is! SuperExpression);
-      if (setter != null) {
-        result = ResolutionResult(property: setter.variable);
-      }
-    }
-
-    if (type is InterfaceType) {
-      lookupIn(type);
-    } else if (type is FunctionType) {
-      lookupIn(_resolver.typeProvider.functionType);
-    } else {
-      return ResolutionResult.none;
-    }
-    if (result.isNone) {
-      result = _extensionResolver.findExtension(type, name, nameNode);
-    }
-    return result;
+  _PropertyResolver _newPropertyResolver() {
+    return _PropertyResolver(_resolver.typeProvider, _inheritance,
+        _definingLibrary, _extensionResolver);
   }
 
   /**
@@ -1573,35 +1439,13 @@
         return;
       }
       DartType leftType = _getStaticType(leftOperand);
-      var isSuper = leftOperand is SuperExpression;
-
-      ResolutionResult result = ResolutionResult.none;
-
-      void lookupIn(InterfaceType type) {
-        ExecutableElement invokeElement = _inheritance.getMember(
-          type,
-          new Name(_definingLibrary.source.uri, methodName),
-          forSuper: isSuper,
-        );
-        if (invokeElement != null) {
-          result = ResolutionResult(function: invokeElement);
-        }
-      }
-
-      if (leftType is InterfaceType) {
-        lookupIn(leftType);
-      } else if (leftType is FunctionType) {
-        lookupIn(_resolver.typeProvider.functionType);
-      }
-
-      if (result.isNone) {
-        result = _extensionResolver.findExtension(leftType, methodName, node);
-      }
+      ResolutionResult result = _newPropertyResolver()
+          .resolveOperator(leftOperand, leftType, methodName, node);
 
       node.staticElement = result.function;
       node.staticInvokeType = result.function?.type;
       if (_shouldReportInvalidMember(leftType, result)) {
-        if (isSuper) {
+        if (leftOperand is SuperExpression) {
           _recordUndefinedToken(
               leftType.element,
               StaticTypeWarningCode.UNDEFINED_SUPER_OPERATOR,
@@ -1699,18 +1543,15 @@
    */
   ResolutionResult _resolveProperty(
       Expression target, DartType targetType, SimpleIdentifier propertyName) {
+    var propertyResolver = _newPropertyResolver();
+    propertyResolver.resolve(
+        target, targetType, propertyName.name, propertyName);
     ResolutionResult result = ResolutionResult.none;
     if (propertyName.inSetterContext()) {
-      result =
-          _lookUpSetter(target, targetType, propertyName.name, propertyName);
+      result = propertyResolver.setterResult;
     }
     if (result.isNone) {
-      result =
-          _lookUpGetter(target, targetType, propertyName.name, propertyName);
-    }
-    if (result.isNone) {
-      result =
-          _lookUpMethod(target, targetType, propertyName.name, propertyName);
+      result = propertyResolver.getterResult;
     }
     return result;
   }
@@ -1907,9 +1748,10 @@
           //
           ClassElement enclosingClass = _resolver.enclosingClass;
           if (enclosingClass != null) {
-            setter = _lookUpSetter(
-                    null, enclosingClass.type, identifier.name, identifier)
-                .setter;
+            var propertyResolver = _newPropertyResolver();
+            propertyResolver.resolve(
+                null, enclosingClass.type, identifier.name, identifier);
+            setter = propertyResolver.setterResult.setter;
           }
         }
         if (setter != null) {
@@ -1943,24 +1785,15 @@
       } else {
         enclosingType = enclosingClass.type;
       }
-      if (enclosingType != null) {
-        if (element == null &&
-            (identifier.inSetterContext() ||
-                identifier.parent is CommentReference)) {
-          element =
-              _lookUpSetter(null, enclosingType, identifier.name, identifier)
-                  .setter;
+      if (element == null && enclosingType != null) {
+        var propertyResolver = _newPropertyResolver();
+        propertyResolver.resolve(
+            null, enclosingType, identifier.name, identifier);
+        if (identifier.inSetterContext() ||
+            identifier.parent is CommentReference) {
+          element = propertyResolver.setterResult.setter;
         }
-        if (element == null && identifier.inGetterContext()) {
-          element =
-              _lookUpGetter(null, enclosingType, identifier.name, identifier)
-                  .getter;
-        }
-        if (element == null) {
-          element =
-              _lookUpMethod(null, enclosingType, identifier.name, identifier)
-                  .getter;
-        }
+        element ??= propertyResolver.getterResult.getter;
       }
     }
     return element;
@@ -2114,3 +1947,98 @@
   @override
   void visitChildren(AstVisitor visitor) {}
 }
+
+/// Helper for resolving properties (getters, setters, or methods).
+class _PropertyResolver {
+  final TypeProvider _typeProvider;
+  final InheritanceManager3 _inheritance;
+  final LibraryElement _definingLibrary;
+  final ExtensionMemberResolver _extensionResolver;
+
+  ResolutionResult getterResult = ResolutionResult.none;
+  ResolutionResult setterResult = ResolutionResult.none;
+
+  _PropertyResolver(
+    this._typeProvider,
+    this._inheritance,
+    this._definingLibrary,
+    this._extensionResolver,
+  );
+
+  /// Look up the getter and the setter with the given [name] in the [type].
+  /// Set results into [getterResult] or [setterResult] correspondingly.
+  /// Methods are considered getters for this purpose.
+  ///
+  /// The [target] is optional, and used to identify `super`.
+  ///
+  /// The [errorNode] is used to report the ambiguous extension issue.
+  void resolve(
+    Expression target,
+    DartType type,
+    String name,
+    Expression errorNode,
+  ) {
+    type = _resolveTypeParameter(type);
+
+    PropertyAccessorElement typeGetter;
+    PropertyAccessorElement typeSetter;
+    ExecutableElement typeMethod;
+
+    void lookupIn(InterfaceType type) {
+      var isSuper = target is SuperExpression;
+
+      typeGetter = type.lookUpInheritedGetter(name,
+          library: _definingLibrary, thisType: !isSuper);
+
+      typeSetter = type.lookUpInheritedSetter(name,
+          library: _definingLibrary, thisType: !isSuper);
+
+      typeMethod = type.lookUpInheritedMethod(name,
+          library: _definingLibrary, thisType: !isSuper);
+    }
+
+    if (type is InterfaceType) {
+      lookupIn(type);
+    } else if (type is FunctionType) {
+      lookupIn(_typeProvider.functionType);
+    } else {
+      return;
+    }
+
+    if (typeGetter != null) {
+      getterResult = ResolutionResult(property: typeGetter.variable);
+    } else if (typeMethod != null) {
+      getterResult = ResolutionResult(function: typeMethod);
+    }
+    if (typeSetter != null) {
+      setterResult = ResolutionResult(property: typeSetter.variable);
+    }
+
+    if (getterResult.isNone && setterResult.isNone) {
+      var result = _extensionResolver.findExtension(type, name, errorNode);
+      if (result.isSingle) {
+        if (result.getter != null) {
+          getterResult = result;
+        } else {
+          assert(result.setter != null);
+          setterResult = result;
+        }
+      } else if (result.isAmbiguous) {
+        getterResult = ResolutionResult.ambiguous;
+        setterResult = ResolutionResult.ambiguous;
+      }
+    }
+  }
+
+  ResolutionResult resolveOperator(
+      Expression target, DartType type, String name, Expression nameNode) {
+    resolve(target, type, name, nameNode);
+    return getterResult;
+  }
+
+  /// If the given [type] is a type parameter, replace it with its bound.
+  /// Otherwise, return the original type.
+  DartType _resolveTypeParameter(DartType type) {
+    return type?.resolveToBound(_typeProvider.objectType);
+  }
+}
diff --git a/pkg/analyzer/lib/src/hint/sdk_constraint_verifier.dart b/pkg/analyzer/lib/src/hint/sdk_constraint_verifier.dart
index 9a559a5..cfb7917 100644
--- a/pkg/analyzer/lib/src/hint/sdk_constraint_verifier.dart
+++ b/pkg/analyzer/lib/src/hint/sdk_constraint_verifier.dart
@@ -34,6 +34,10 @@
   /// field.
   bool _checkConstantUpdate2018;
 
+  /// A cached flag indicating whether uses of extension method features need to
+  /// be checked. Use [checkExtensionMethods] to access this field.
+  bool _checkExtensionMethods;
+
   /// A cached flag indicating whether references to Future and Stream need to
   /// be checked. Use [checkFutureAndStream] to access this field.
   bool _checkFutureAndStream;
@@ -76,6 +80,10 @@
   VersionRange get before_2_5_0 =>
       new VersionRange(max: Version.parse('2.5.0'), includeMax: false);
 
+  /// Return a range covering every version up to, but not including, 2.6.0.
+  VersionRange get before_2_6_0 =>
+      new VersionRange(max: Version.parse('2.6.0'), includeMax: false);
+
   /// Return `true` if references to the constant-update-2018 features need to
   /// be checked.
   bool get checkConstantUpdate2018 => _checkConstantUpdate2018 ??=
@@ -83,9 +91,8 @@
 
   /// Return `true` if references to the extension method features need to
   /// be checked.
-  // TODO(brianwilkerson) Implement this as a version check when a version has
-  //  been selected.
-  bool get checkExtensionMethods => true;
+  bool get checkExtensionMethods => _checkExtensionMethods ??=
+      !before_2_6_0.intersect(_versionConstraint).isEmpty;
 
   /// Return `true` if references to Future and Stream need to be checked.
   bool get checkFutureAndStream => _checkFutureAndStream ??=
diff --git a/pkg/analyzer/lib/src/summary/format.dart b/pkg/analyzer/lib/src/summary/format.dart
index 2ac377b..00c787a 100644
--- a/pkg/analyzer/lib/src/summary/format.dart
+++ b/pkg/analyzer/lib/src/summary/format.dart
@@ -23610,6 +23610,7 @@
         kind == idl.LinkedNodeKind.compilationUnit ||
         kind == idl.LinkedNodeKind.constructorDeclaration ||
         kind == idl.LinkedNodeKind.defaultFormalParameter ||
+        kind == idl.LinkedNodeKind.enumConstantDeclaration ||
         kind == idl.LinkedNodeKind.enumDeclaration ||
         kind == idl.LinkedNodeKind.extensionDeclaration ||
         kind == idl.LinkedNodeKind.fieldFormalParameter ||
@@ -23631,6 +23632,7 @@
         kind == idl.LinkedNodeKind.compilationUnit ||
         kind == idl.LinkedNodeKind.constructorDeclaration ||
         kind == idl.LinkedNodeKind.defaultFormalParameter ||
+        kind == idl.LinkedNodeKind.enumConstantDeclaration ||
         kind == idl.LinkedNodeKind.enumDeclaration ||
         kind == idl.LinkedNodeKind.extensionDeclaration ||
         kind == idl.LinkedNodeKind.fieldFormalParameter ||
@@ -23654,6 +23656,7 @@
         kind == idl.LinkedNodeKind.compilationUnit ||
         kind == idl.LinkedNodeKind.constructorDeclaration ||
         kind == idl.LinkedNodeKind.defaultFormalParameter ||
+        kind == idl.LinkedNodeKind.enumConstantDeclaration ||
         kind == idl.LinkedNodeKind.enumDeclaration ||
         kind == idl.LinkedNodeKind.extensionDeclaration ||
         kind == idl.LinkedNodeKind.fieldFormalParameter ||
@@ -23675,6 +23678,7 @@
         kind == idl.LinkedNodeKind.compilationUnit ||
         kind == idl.LinkedNodeKind.constructorDeclaration ||
         kind == idl.LinkedNodeKind.defaultFormalParameter ||
+        kind == idl.LinkedNodeKind.enumConstantDeclaration ||
         kind == idl.LinkedNodeKind.enumDeclaration ||
         kind == idl.LinkedNodeKind.extensionDeclaration ||
         kind == idl.LinkedNodeKind.fieldFormalParameter ||
@@ -23944,9 +23948,13 @@
         _variantField_10 = defaultFormalParameter_defaultValueCode;
 
   UnlinkedInformativeDataBuilder.enumConstantDeclaration({
+    int codeLength,
+    int codeOffset,
     int nameOffset,
     List<String> documentationComment_tokens,
   })  : _kind = idl.LinkedNodeKind.enumConstantDeclaration,
+        _variantField_2 = codeLength,
+        _variantField_3 = codeOffset,
         _variantField_1 = nameOffset,
         _variantField_4 = documentationComment_tokens;
 
@@ -24219,6 +24227,8 @@
     } else if (kind == idl.LinkedNodeKind.enumConstantDeclaration) {
       signature.addInt(this.kind == null ? 0 : this.kind.index);
       signature.addInt(this.nameOffset ?? 0);
+      signature.addInt(this.codeLength ?? 0);
+      signature.addInt(this.codeOffset ?? 0);
       if (this.documentationComment_tokens == null) {
         signature.addInt(0);
       } else {
@@ -24486,6 +24496,7 @@
         kind == idl.LinkedNodeKind.compilationUnit ||
         kind == idl.LinkedNodeKind.constructorDeclaration ||
         kind == idl.LinkedNodeKind.defaultFormalParameter ||
+        kind == idl.LinkedNodeKind.enumConstantDeclaration ||
         kind == idl.LinkedNodeKind.enumDeclaration ||
         kind == idl.LinkedNodeKind.extensionDeclaration ||
         kind == idl.LinkedNodeKind.fieldFormalParameter ||
@@ -24509,6 +24520,7 @@
         kind == idl.LinkedNodeKind.compilationUnit ||
         kind == idl.LinkedNodeKind.constructorDeclaration ||
         kind == idl.LinkedNodeKind.defaultFormalParameter ||
+        kind == idl.LinkedNodeKind.enumConstantDeclaration ||
         kind == idl.LinkedNodeKind.enumDeclaration ||
         kind == idl.LinkedNodeKind.extensionDeclaration ||
         kind == idl.LinkedNodeKind.fieldFormalParameter ||
@@ -24688,6 +24700,8 @@
             defaultFormalParameter_defaultValueCode;
     }
     if (kind == idl.LinkedNodeKind.enumConstantDeclaration) {
+      if (codeLength != 0) _result["codeLength"] = codeLength;
+      if (codeOffset != 0) _result["codeOffset"] = codeOffset;
       if (nameOffset != 0) _result["nameOffset"] = nameOffset;
       if (documentationComment_tokens.isNotEmpty)
         _result["documentationComment_tokens"] = documentationComment_tokens;
@@ -24863,6 +24877,8 @@
     }
     if (kind == idl.LinkedNodeKind.enumConstantDeclaration) {
       return {
+        "codeLength": codeLength,
+        "codeOffset": codeOffset,
         "nameOffset": nameOffset,
         "documentationComment_tokens": documentationComment_tokens,
         "kind": kind,
diff --git a/pkg/analyzer/lib/src/summary/idl.dart b/pkg/analyzer/lib/src/summary/idl.dart
index 5e71b0e..0ada341 100644
--- a/pkg/analyzer/lib/src/summary/idl.dart
+++ b/pkg/analyzer/lib/src/summary/idl.dart
@@ -3645,6 +3645,7 @@
     LinkedNodeKind.compilationUnit,
     LinkedNodeKind.constructorDeclaration,
     LinkedNodeKind.defaultFormalParameter,
+    LinkedNodeKind.enumConstantDeclaration,
     LinkedNodeKind.enumDeclaration,
     LinkedNodeKind.extensionDeclaration,
     LinkedNodeKind.fieldFormalParameter,
@@ -3666,6 +3667,7 @@
     LinkedNodeKind.compilationUnit,
     LinkedNodeKind.constructorDeclaration,
     LinkedNodeKind.defaultFormalParameter,
+    LinkedNodeKind.enumConstantDeclaration,
     LinkedNodeKind.enumDeclaration,
     LinkedNodeKind.extensionDeclaration,
     LinkedNodeKind.fieldFormalParameter,
diff --git a/pkg/analyzer/lib/src/summary2/informative_data.dart b/pkg/analyzer/lib/src/summary2/informative_data.dart
index 1bf085d..c26e114 100644
--- a/pkg/analyzer/lib/src/summary2/informative_data.dart
+++ b/pkg/analyzer/lib/src/summary2/informative_data.dart
@@ -116,6 +116,8 @@
     setData(
       node,
       UnlinkedInformativeDataBuilder.enumConstantDeclaration(
+        codeOffset: node.offset,
+        codeLength: node.length,
         documentationComment_tokens: _nodeCommentTokens(node),
         nameOffset: node.name.offset,
       ),
diff --git a/pkg/analyzer/lib/src/summary2/lazy_ast.dart b/pkg/analyzer/lib/src/summary2/lazy_ast.dart
index 97fd87a..1ab9a95 100644
--- a/pkg/analyzer/lib/src/summary2/lazy_ast.dart
+++ b/pkg/analyzer/lib/src/summary2/lazy_ast.dart
@@ -574,6 +574,28 @@
     return node.getProperty(_key);
   }
 
+  static int getCodeLength(
+    LinkedUnitContext context,
+    EnumConstantDeclaration node,
+  ) {
+    var lazy = get(node);
+    if (lazy != null) {
+      return context.getInformativeData(lazy.data)?.codeLength ?? 0;
+    }
+    return node.length;
+  }
+
+  static int getCodeOffset(
+    LinkedUnitContext context,
+    EnumConstantDeclaration node,
+  ) {
+    var lazy = get(node);
+    if (lazy != null) {
+      return context.getInformativeData(lazy.data)?.codeOffset ?? 0;
+    }
+    return node.offset;
+  }
+
   static void readDocumentationComment(
     LinkedUnitContext context,
     EnumConstantDeclaration node,
diff --git a/pkg/analyzer/lib/src/summary2/linked_unit_context.dart b/pkg/analyzer/lib/src/summary2/linked_unit_context.dart
index 801f3b0..823fef5 100644
--- a/pkg/analyzer/lib/src/summary2/linked_unit_context.dart
+++ b/pkg/analyzer/lib/src/summary2/linked_unit_context.dart
@@ -148,6 +148,8 @@
       }
     } else if (node is ConstructorDeclaration) {
       return LazyConstructorDeclaration.getCodeLength(this, node);
+    } else if (node is EnumConstantDeclaration) {
+      return LazyEnumConstantDeclaration.getCodeLength(this, node);
     } else if (node is EnumDeclaration) {
       return LazyEnumDeclaration.getCodeLength(this, node);
     } else if (node is ExtensionDeclaration) {
@@ -181,6 +183,8 @@
       return 0;
     } else if (node is ConstructorDeclaration) {
       return LazyConstructorDeclaration.getCodeOffset(this, node);
+    } else if (node is EnumConstantDeclaration) {
+      return LazyEnumConstantDeclaration.getCodeOffset(this, node);
     } else if (node is EnumDeclaration) {
       return LazyEnumDeclaration.getCodeOffset(this, node);
     } else if (node is ExtensionDeclaration) {
diff --git a/pkg/analyzer/lib/src/summary2/reference_resolver.dart b/pkg/analyzer/lib/src/summary2/reference_resolver.dart
index 3187ffa..6392ba2 100644
--- a/pkg/analyzer/lib/src/summary2/reference_resolver.dart
+++ b/pkg/analyzer/lib/src/summary2/reference_resolver.dart
@@ -145,6 +145,9 @@
     LinkingNodeContext(node, functionScope);
 
     node.parameters?.accept(this);
+    node.initializers.accept(
+      _SetGenericFunctionTypeIdVisitor(this),
+    );
 
     scope = outerScope;
     reference = outerReference;
@@ -153,6 +156,9 @@
   @override
   void visitDefaultFormalParameter(DefaultFormalParameter node) {
     node.parameter.accept(this);
+    node.defaultValue?.accept(
+      _SetGenericFunctionTypeIdVisitor(this),
+    );
   }
 
   @override
diff --git a/pkg/analyzer/test/generated/parser_fasta_test.dart b/pkg/analyzer/test/generated/parser_fasta_test.dart
index 0bc30b6..42e45f2 100644
--- a/pkg/analyzer/test/generated/parser_fasta_test.dart
+++ b/pkg/analyzer/test/generated/parser_fasta_test.dart
@@ -2544,6 +2544,16 @@
     parseCompilationUnit('D? foo(X? x) { X? x1; X? x2 = x + bar(7); }');
   }
 
+  void test_assignment_complex2() {
+    parseCompilationUnit(r'''
+main() {
+  A? a;
+  String? s = '';
+  a?..foo().length..x27 = s!..toString().length;
+}
+''');
+  }
+
   void test_assignment_simple() {
     parseCompilationUnit('D? foo(X? x) { X? x1; X? x2 = x; }');
   }
@@ -2561,6 +2571,39 @@
     expect(rhs.name, 'x2');
   }
 
+  void test_cascade_withNullCheck_indexExpression() {
+    var unit = parseCompilationUnit('main() { a?..[27]; }');
+    FunctionDeclaration funct = unit.declarations[0];
+    BlockFunctionBody body = funct.functionExpression.body;
+    ExpressionStatement statement = body.block.statements[0];
+    CascadeExpression cascade = statement.expression;
+    IndexExpression indexExpression = cascade.cascadeSections[0];
+    expect(indexExpression.period.lexeme, '?..');
+    expect(indexExpression.toSource(), '?..[27]');
+  }
+
+  void test_cascade_withNullCheck_methodInvocation() {
+    var unit = parseCompilationUnit('main() { a?..foo(); }');
+    FunctionDeclaration funct = unit.declarations[0];
+    BlockFunctionBody body = funct.functionExpression.body;
+    ExpressionStatement statement = body.block.statements[0];
+    CascadeExpression cascade = statement.expression;
+    MethodInvocation invocation = cascade.cascadeSections[0];
+    expect(invocation.operator.lexeme, '?..');
+    expect(invocation.toSource(), '?..foo()');
+  }
+
+  void test_cascade_withNullCheck_propertyAccess() {
+    var unit = parseCompilationUnit('main() { a?..x27; }');
+    FunctionDeclaration funct = unit.declarations[0];
+    BlockFunctionBody body = funct.functionExpression.body;
+    ExpressionStatement statement = body.block.statements[0];
+    CascadeExpression cascade = statement.expression;
+    PropertyAccess propertyAccess = cascade.cascadeSections[0];
+    expect(propertyAccess.operator.lexeme, '?..');
+    expect(propertyAccess.toSource(), '?..x27');
+  }
+
   void test_conditional() {
     parseCompilationUnit('D? foo(X? x) { X ? 7 : y; }');
   }
diff --git a/pkg/analyzer/test/src/diagnostics/assignment_to_final_no_setter_test.dart b/pkg/analyzer/test/src/diagnostics/assignment_to_final_no_setter_test.dart
index a5f6427..238174f 100644
--- a/pkg/analyzer/test/src/diagnostics/assignment_to_final_no_setter_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/assignment_to_final_no_setter_test.dart
@@ -2,7 +2,9 @@
 // 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:analyzer/dart/analysis/features.dart';
 import 'package:analyzer/src/error/codes.dart';
+import 'package:analyzer/src/generated/engine.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
 import '../dart/resolution/driver_resolution.dart';
@@ -43,3 +45,25 @@
     ]);
   }
 }
+
+@reflectiveTest
+class AssignmentToMethodWithExtensionMethodsTest
+    extends AssignmentToFinalNoSetterTest {
+  @override
+  AnalysisOptionsImpl get analysisOptions => AnalysisOptionsImpl()
+    ..contextFeatures = new FeatureSet.forTesting(
+        sdkVersion: '2.3.0', additionalFeatures: [Feature.extension_methods]);
+
+  test_instance_undefined_hasGetter() async {
+    await assertErrorsInCode('''
+extension E on int {
+  int get foo => 0;
+}
+f() {
+  0.foo = 1;
+}
+''', [
+      error(CompileTimeErrorCode.UNDEFINED_EXTENSION_SETTER, 53, 3),
+    ]);
+  }
+}
diff --git a/pkg/analyzer/test/src/diagnostics/assignment_to_method_test.dart b/pkg/analyzer/test/src/diagnostics/assignment_to_method_test.dart
index 0a24297..912eefe 100644
--- a/pkg/analyzer/test/src/diagnostics/assignment_to_method_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/assignment_to_method_test.dart
@@ -2,7 +2,9 @@
 // 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:analyzer/dart/analysis/features.dart';
 import 'package:analyzer/src/error/codes.dart';
+import 'package:analyzer/src/generated/engine.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
 import '../dart/resolution/driver_resolution.dart';
@@ -10,6 +12,7 @@
 main() {
   defineReflectiveSuite(() {
     defineReflectiveTests(AssignmentToMethodTest);
+    defineReflectiveTests(AssignmentToMethodWithExtensionMethodsTest);
   });
 }
 
@@ -27,3 +30,50 @@
     ]);
   }
 }
+
+@reflectiveTest
+class AssignmentToMethodWithExtensionMethodsTest
+    extends AssignmentToMethodTest {
+  @override
+  AnalysisOptionsImpl get analysisOptions => AnalysisOptionsImpl()
+    ..contextFeatures = new FeatureSet.forTesting(
+        sdkVersion: '2.3.0', additionalFeatures: [Feature.extension_methods]);
+
+  test_instance_extendedHasMethod_extensionHasSetter() async {
+    await assertErrorsInCode('''
+class C {
+  void foo() {}
+}
+
+extension E on C {
+  void set foo(int _) {}
+}
+
+f(C c) {
+  c.foo = 0;
+}
+''', [
+      error(StaticWarningCode.ASSIGNMENT_TO_METHOD, 87, 5),
+      error(StaticTypeWarningCode.INVALID_ASSIGNMENT, 95, 1),
+    ]);
+  }
+
+  test_this_extendedHasMethod_extensionHasSetter() async {
+    await assertErrorsInCode('''
+class C {
+  void foo() {}
+}
+
+extension E on C {
+  void set foo(int _) {}
+
+  f() {
+    this.foo = 0;
+  }
+}
+''', [
+      error(StaticWarningCode.ASSIGNMENT_TO_METHOD, 86, 8),
+      error(StaticTypeWarningCode.INVALID_ASSIGNMENT, 97, 1),
+    ]);
+  }
+}
diff --git a/pkg/analyzer/test/src/diagnostics/sdk_version_extension_methods_test.dart b/pkg/analyzer/test/src/diagnostics/sdk_version_extension_methods_test.dart
index 9afa451..e10751d 100644
--- a/pkg/analyzer/test/src/diagnostics/sdk_version_extension_methods_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/sdk_version_extension_methods_test.dart
@@ -21,7 +21,6 @@
   AnalysisOptionsImpl get analysisOptions => AnalysisOptionsImpl()
     ..enabledExperiments = [EnableString.extension_methods];
 
-  @failingTest
   test_extension_equals() async {
     await verifyVersion('2.6.0', '''
 extension E on int {}
@@ -36,7 +35,6 @@
     ]);
   }
 
-  @failingTest
   test_extensionOverride_equals() async {
     await verifyVersion('2.6.0', '''
 extension E on int {
diff --git a/pkg/analyzer/test/src/diagnostics/undefined_extension_getter_test.dart b/pkg/analyzer/test/src/diagnostics/undefined_extension_getter_test.dart
index dc99786..1917d08 100644
--- a/pkg/analyzer/test/src/diagnostics/undefined_extension_getter_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/undefined_extension_getter_test.dart
@@ -22,7 +22,7 @@
     ..contextFeatures = new FeatureSet.forTesting(
         sdkVersion: '2.3.0', additionalFeatures: [Feature.extension_methods]);
 
-  test_instance_defined() async {
+  test_override_defined() async {
     await assertNoErrorsInCode('''
 extension E on String {
   int get g => 0;
@@ -33,7 +33,7 @@
 ''');
   }
 
-  test_instance_withoutSetter() async {
+  test_override_undefined() async {
     await assertErrorsInCode('''
 extension E on String {}
 f() {
@@ -44,7 +44,7 @@
     ]);
   }
 
-  test_instance_withSetter() async {
+  test_override_undefined_hasSetter() async {
     await assertErrorsInCode('''
 extension E on String {
   void set s(int x) {}
diff --git a/pkg/analyzer/test/src/diagnostics/undefined_extension_setter_test.dart b/pkg/analyzer/test/src/diagnostics/undefined_extension_setter_test.dart
index 9c38d0c..f6c2f65 100644
--- a/pkg/analyzer/test/src/diagnostics/undefined_extension_setter_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/undefined_extension_setter_test.dart
@@ -22,36 +22,49 @@
     ..contextFeatures = new FeatureSet.forTesting(
         sdkVersion: '2.3.0', additionalFeatures: [Feature.extension_methods]);
 
-  test_instance_defined() async {
+  test_override_defined() async {
     await assertNoErrorsInCode('''
-extension E on String {
-  void set s(int x) {}
+extension E on int {
+  void set foo(int _) {}
 }
 f() {
-  E('a').s = 1;
+  E(0).foo = 1;
 }
 ''');
   }
 
-  test_instance_undefined() async {
+  test_override_undefined() async {
     await assertErrorsInCode('''
-extension E on String {}
+extension E on int {}
 f() {
-  E('a').s = 1;
+  E(0).foo = 1;
 }
 ''', [
-      error(CompileTimeErrorCode.UNDEFINED_EXTENSION_SETTER, 40, 1),
+      error(CompileTimeErrorCode.UNDEFINED_EXTENSION_SETTER, 35, 3),
+    ]);
+  }
+
+  test_override_undefined_hasGetter() async {
+    await assertErrorsInCode('''
+extension E on int {
+  int get foo => 0;
+}
+f() {
+  E(0).foo = 1;
+}
+''', [
+      error(CompileTimeErrorCode.UNDEFINED_EXTENSION_SETTER, 56, 3),
     ]);
   }
 
   test_static_undefined() async {
     await assertErrorsInCode('''
-extension E on Object {}
+extension E on int {}
 void f() {
-  E.s = 3;
+  E.foo = 3;
 }
 ''', [
-      error(CompileTimeErrorCode.UNDEFINED_EXTENSION_SETTER, 40, 1),
+      error(CompileTimeErrorCode.UNDEFINED_EXTENSION_SETTER, 37, 3),
     ]);
   }
 }
diff --git a/pkg/analyzer/test/src/diagnostics/undefined_getter_test.dart b/pkg/analyzer/test/src/diagnostics/undefined_getter_test.dart
index d56ebb7..5f3050e 100644
--- a/pkg/analyzer/test/src/diagnostics/undefined_getter_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/undefined_getter_test.dart
@@ -125,6 +125,37 @@
     ..contextFeatures = new FeatureSet.forTesting(
         sdkVersion: '2.3.0', additionalFeatures: [Feature.extension_methods]);
 
+  test_instance_extendedHasSetter_extensionHasGetter() async {
+    await assertErrorsInCode('''
+class C {
+  void set foo(int _) {}
+}
+
+extension E on C {
+  int get foo => 0;
+
+  f() {
+    this.foo;
+  }
+}
+''', [
+      error(StaticTypeWarningCode.UNDEFINED_GETTER, 95, 3),
+    ]);
+  }
+
+  test_instance_undefined_hasSetter() async {
+    await assertErrorsInCode('''
+extension E on int {
+  void set foo(int _) {}
+}
+f() {
+  0.foo;
+}
+''', [
+      error(StaticTypeWarningCode.UNDEFINED_GETTER, 58, 3),
+    ]);
+  }
+
   test_instance_withInference() async {
     await assertErrorsInCode(r'''
 extension E on int {}
@@ -147,4 +178,22 @@
       error(StaticTypeWarningCode.UNDEFINED_GETTER, 46, 1),
     ]);
   }
+
+  test_this_extendedHasSetter_extensionHasGetter() async {
+    await assertErrorsInCode('''
+class C {
+  void set foo(int _) {}
+}
+
+extension E on C {
+  int get foo => 0;
+}
+
+f(C c) {
+  c.foo;
+}
+''', [
+      error(StaticTypeWarningCode.UNDEFINED_GETTER, 93, 3),
+    ]);
+  }
 }
diff --git a/pkg/analyzer/test/src/diagnostics/unused_import_test.dart b/pkg/analyzer/test/src/diagnostics/unused_import_test.dart
index 0a78364..19a7be4 100644
--- a/pkg/analyzer/test/src/diagnostics/unused_import_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/unused_import_test.dart
@@ -328,14 +328,14 @@
   test_instance_setter() async {
     newFile('/test/lib/lib1.dart', content: r'''
 extension E on String {
-  void set length(int i) {}
+  void set foo(int i) {}
 }
 ''');
     await assertNoErrorsInCode('''
 import 'lib1.dart';
 
 f() {
-  'abc'.length = 2;
+  'abc'.foo = 2;
 }
 ''');
   }
diff --git a/pkg/analyzer/test/src/lint/linter/linter_context_impl_test.dart b/pkg/analyzer/test/src/lint/linter/linter_context_impl_test.dart
index befdee3..2d07417 100644
--- a/pkg/analyzer/test/src/lint/linter/linter_context_impl_test.dart
+++ b/pkg/analyzer/test/src/lint/linter/linter_context_impl_test.dart
@@ -184,6 +184,16 @@
     assertCanBeConst("A(", false);
   }
 
+  void test_false_typeParameter() async {
+    await resolve('''
+class A<T> {
+  const A();
+}
+f<U>() => A<U>();
+''');
+    assertCanBeConst("A<U>", false);
+  }
+
   void test_true_constConstructorArg() async {
     await resolve('''
 class A {
diff --git a/pkg/analyzer/test/src/summary/resynthesize_common.dart b/pkg/analyzer/test/src/summary/resynthesize_common.dart
index 38ce11b..e68375d 100644
--- a/pkg/analyzer/test/src/summary/resynthesize_common.dart
+++ b/pkg/analyzer/test/src/summary/resynthesize_common.dart
@@ -2075,6 +2075,28 @@
         withConstElements: false);
   }
 
+  test_codeRange_enum() async {
+    var library = await checkLibrary('''
+enum E {
+  aaa, bbb, ccc
+}
+''');
+    checkElementText(
+        library,
+        r'''
+enum E/*codeOffset=0, codeLength=26*/ {
+  synthetic final int index/*codeOffset=null, codeLength=null*/;
+  synthetic static const List<E> values/*codeOffset=null, codeLength=null*/;
+  static const E aaa/*codeOffset=11, codeLength=3*/;
+  static const E bbb/*codeOffset=16, codeLength=3*/;
+  static const E ccc/*codeOffset=21, codeLength=3*/;
+  String toString/*codeOffset=null, codeLength=null*/() {}
+}
+''',
+        withCodeRanges: true,
+        withConstElements: false);
+  }
+
   test_codeRange_extensions() async {
     featureSet = enableExtensionMethods;
     var library = await checkLibrary('''
@@ -4617,6 +4639,31 @@
 ''');
   }
 
+  test_constructor_initializers_genericFunctionType() async {
+    var library = await checkLibrary('''
+class A<T> {
+  const A();
+}
+class B {
+  const B(dynamic x);
+  const B.f()
+   : this(A<Function()>());
+}
+''');
+    if (isAstBasedSummary) {
+      checkElementText(library, r'''
+class A<T> {
+  const A();
+}
+class B {
+  const B(dynamic x);
+  const B.f() = B : this(
+        A/*location: test.dart;A*/<Function()>());
+}
+''');
+    }
+  }
+
   test_constructor_initializers_superInvocation_named() async {
     var library = await checkLibrary('''
 class A {
@@ -5261,6 +5308,28 @@
 ''');
   }
 
+  test_defaultValue_genericFunctionType() async {
+    var library = await checkLibrary('''
+class A<T> {
+  const A();
+}
+class B {
+  void foo({a: const A<Function()>()}) {}
+}
+''');
+    if (isAstBasedSummary) {
+      checkElementText(library, r'''
+class A<T> {
+  const A();
+}
+class B {
+  void foo({dynamic a: const
+        A/*location: test.dart;A*/<Function()>()}) {}
+}
+''');
+    }
+  }
+
   test_defaultValue_refersToExtension_method_inside() async {
     featureSet = enableExtensionMethods;
     var library = await checkLibrary('''
diff --git a/pkg/front_end/lib/src/fasta/kernel/body_builder.dart b/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
index bf7c912..e9bb860 100644
--- a/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
@@ -1479,7 +1479,9 @@
   @override
   void endBinaryExpression(Token token) {
     debugEvent("BinaryExpression");
-    if (optional(".", token) || optional("..", token)) {
+    if (optional(".", token) ||
+        optional("..", token) ||
+        optional("?..", token)) {
       return doDotOrCascadeExpression(token);
     }
     if (optional("&&", token) || optional("||", token)) {
diff --git a/pkg/front_end/lib/src/fasta/parser/parser.dart b/pkg/front_end/lib/src/fasta/parser/parser.dart
index a296c652..9ad4e92 100644
--- a/pkg/front_end/lib/src/fasta/parser/parser.dart
+++ b/pkg/front_end/lib/src/fasta/parser/parser.dart
@@ -4285,7 +4285,7 @@
 
   Token parseCascadeExpression(Token token) {
     Token cascadeOperator = token = token.next;
-    assert(optional('..', cascadeOperator));
+    assert(optional('..', cascadeOperator) || optional('?..', cascadeOperator));
     listener.beginCascade(cascadeOperator);
     if (optional('[', token.next)) {
       token = parseArgumentOrIndexStar(token, noTypeParamOrArg);
diff --git a/pkg/front_end/lib/src/fasta/scanner/abstract_scanner.dart b/pkg/front_end/lib/src/fasta/scanner/abstract_scanner.dart
index 50fedf3..e34362d 100644
--- a/pkg/front_end/lib/src/fasta/scanner/abstract_scanner.dart
+++ b/pkg/front_end/lib/src/fasta/scanner/abstract_scanner.dart
@@ -877,16 +877,22 @@
   }
 
   int tokenizeQuestion(int next) {
-    // ? ?. ?? ??=
+    // ? ?. ?.. ?? ??=
     next = advance();
     if (identical(next, $QUESTION)) {
       return select(
           $EQ, TokenType.QUESTION_QUESTION_EQ, TokenType.QUESTION_QUESTION);
     } else if (identical(next, $PERIOD)) {
       next = advance();
-      if (_enableNonNullable && identical($OPEN_SQUARE_BRACKET, next)) {
-        appendBeginGroup(TokenType.QUESTION_PERIOD_OPEN_SQUARE_BRACKET);
-        return advance();
+      if (_enableNonNullable) {
+        if (identical($PERIOD, next)) {
+          appendPrecedenceToken(TokenType.QUESTION_PERIOD_PERIOD);
+          return advance();
+        }
+        if (identical($OPEN_SQUARE_BRACKET, next)) {
+          appendBeginGroup(TokenType.QUESTION_PERIOD_OPEN_SQUARE_BRACKET);
+          return advance();
+        }
       }
       appendPrecedenceToken(TokenType.QUESTION_PERIOD);
       return next;
diff --git a/pkg/front_end/lib/src/fasta/scanner/token_constants.dart b/pkg/front_end/lib/src/fasta/scanner/token_constants.dart
index e468145..f8cc645 100644
--- a/pkg/front_end/lib/src/fasta/scanner/token_constants.dart
+++ b/pkg/front_end/lib/src/fasta/scanner/token_constants.dart
@@ -90,3 +90,5 @@
 const int PERIOD_PERIOD_PERIOD_QUESTION_TOKEN = GT_GT_GT_TOKEN + 1;
 const int GT_GT_GT_EQ_TOKEN = PERIOD_PERIOD_PERIOD_QUESTION_TOKEN + 1;
 const int QUESTION_PERIOD_OPEN_SQUARE_BRACKET_TOKEN = GT_GT_GT_EQ_TOKEN + 1;
+const int QUESTION_PERIOD_PERIOD_TOKEN =
+    QUESTION_PERIOD_OPEN_SQUARE_BRACKET_TOKEN + 1;
diff --git a/pkg/front_end/lib/src/fasta/type_inference/type_constraint_gatherer.dart b/pkg/front_end/lib/src/fasta/type_inference/type_constraint_gatherer.dart
index dab1b69..3912f27 100644
--- a/pkg/front_end/lib/src/fasta/type_inference/type_constraint_gatherer.dart
+++ b/pkg/front_end/lib/src/fasta/type_inference/type_constraint_gatherer.dart
@@ -259,12 +259,6 @@
     // identical().  If P and Q are equal but not identical, recursing through
     // the types will give the proper result.
     if (identical(subtype, supertype)) return true;
-    // Any type `P` is a subtype match for `dynamic`, `Object`, or `void` under
-    // no constraints.
-    if (_isTop(supertype)) return true;
-    // `Null` is a subtype match for any type `Q` under no constraints.
-    // Note that nullable types will change this.
-    if (_isNull(subtype)) return true;
 
     // Handle FutureOr<T> union type.
     if (subtype is InterfaceType &&
@@ -302,11 +296,34 @@
       //   - And `P` is a subtype match for `Q` with respect to `L` under
       //     constraints `C`
       DartType supertypeArg = supertype.typeArguments[0];
-      InterfaceType supertypeFuture = futureType(supertypeArg);
-      return trySubtypeMatch(subtype, supertypeFuture) ||
-          _isSubtypeMatch(subtype, supertypeArg);
+      DartType supertypeFuture = futureType(supertypeArg);
+
+      // The outcome of both trySubtypeMatch and _isSubtypeMatch is includes the
+      // returned boolean value and the added constraints to _protoConstraints.
+      // Here we need to match 'subtype' against both possibilities of the
+      // FutureOr<X> which is 'supertype,' that is, we need to match 'subtype'
+      // against Future<X> and X.  However, if the first matching against
+      // Future<X> finds any new constraints and adds them to _protoConstraints,
+      // we should prefer them over the constraints possibly found while
+      // matching against X.  Note that if matching against Future<X> returned
+      // true, but didn't find any new constraints, then matching against X
+      // should still be done and the new constraints should still be added to
+      // _protoConstraints.
+      int oldProtoConstraintsLength = _protoConstraints.length;
+      bool matchesFuture = trySubtypeMatch(subtype, supertypeFuture);
+      bool matchesArg = oldProtoConstraintsLength != _protoConstraints.length
+          ? false
+          : _isSubtypeMatch(subtype, supertypeArg);
+      return matchesFuture || matchesArg;
     }
 
+    // Any type `P` is a subtype match for `dynamic`, `Object`, or `void` under
+    // no constraints.
+    if (_isTop(supertype)) return true;
+    // `Null` is a subtype match for any type `Q` under no constraints.
+    // Note that nullable types will change this.
+    if (_isNull(subtype)) return true;
+
     // A type variable `T` not in `L` with bound `P` is a subtype match for the
     // same type variable `T` with bound `Q` with respect to `L` under
     // constraints `C`:
diff --git a/pkg/front_end/lib/src/scanner/token.dart b/pkg/front_end/lib/src/scanner/token.dart
index f7429c3..d16d2d4 100644
--- a/pkg/front_end/lib/src/scanner/token.dart
+++ b/pkg/front_end/lib/src/scanner/token.dart
@@ -1450,6 +1450,12 @@
       SELECTOR_PRECEDENCE,
       QUESTION_PERIOD_OPEN_SQUARE_BRACKET_TOKEN);
 
+  static const TokenType QUESTION_PERIOD_PERIOD = const TokenType(
+      '?..',
+      'QUESTION_PERIOD_PERIOD',
+      CASCADE_PRECEDENCE,
+      QUESTION_PERIOD_PERIOD_TOKEN);
+
   static const TokenType AS = Keyword.AS;
 
   static const TokenType IS = Keyword.IS;
diff --git a/pkg/front_end/test/spell_checking_list_common.txt b/pkg/front_end/test/spell_checking_list_common.txt
index 056b0f5..f27e950 100644
--- a/pkg/front_end/test/spell_checking_list_common.txt
+++ b/pkg/front_end/test/spell_checking_list_common.txt
@@ -97,6 +97,7 @@
 also
 alternating
 alternative
+alternatives
 alternatively
 although
 always
@@ -1984,6 +1985,7 @@
 positions
 positive
 positives
+possibilities
 possible
 possibly
 post
diff --git a/pkg/front_end/test/static_types/data/constraint_gatherer_for_future_or.dart b/pkg/front_end/test/static_types/data/constraint_gatherer_for_future_or.dart
new file mode 100644
index 0000000..8e74122
--- /dev/null
+++ b/pkg/front_end/test/static_types/data/constraint_gatherer_for_future_or.dart
@@ -0,0 +1,74 @@
+// 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.
+
+// The test checks the gathering of the constraints during type inference in
+// case the supertype of the match is a FutureOr<X> or one of its alternatives
+// (either Future<X> or X).
+
+import 'dart:async';
+
+// -----------------------------------------------------------------------------
+
+// Gathering constraints for S from comparison Null <: FutureOr<S>.
+void func1() {
+  void foo<S>(FutureOr<S> bar) {}
+
+  /*invoke: void*/ foo/*<Null>*/(/*Null*/ null);
+}
+
+// -----------------------------------------------------------------------------
+
+// Gathering constraints for S from comparison Null <: Future<S>.
+void func2() {
+  void foo<S>(Future<S> bar) {}
+
+  /*invoke: void*/ foo/*<dynamic>*/(/*Null*/ null);
+}
+
+// -----------------------------------------------------------------------------
+
+// Gathering constraints for S from comparison Null <: S.
+void func3() {
+  void foo<S>(S bar) {}
+
+  /*invoke: void*/ foo/*<Null>*/(/*Null*/ null);
+}
+
+// -----------------------------------------------------------------------------
+
+void func4() {
+  void foo<S>(FutureOr<FutureOr<S>> bar) {}
+
+  /*invoke: void*/ foo/*<Null>*/(/*Null*/ null);
+}
+
+// -----------------------------------------------------------------------------
+
+// Gathering constraints for S from comparison int <: FutureOr<S>.
+void func5() {
+  void foo<S>(FutureOr<S> bar) {}
+
+  /*invoke: void*/ foo/*<int>*/(/*int*/ 42);
+}
+
+// -----------------------------------------------------------------------------
+
+// Gathering constraints for S from comparison int <: S.
+void func6() {
+  void foo<S>(S bar) {}
+
+  /*invoke: void*/ foo/*<int>*/(/*int*/ 42);
+}
+
+// -----------------------------------------------------------------------------
+
+void func7() {
+  void foo<S>(FutureOr<FutureOr<S>> bar) {}
+
+  /*invoke: void*/ foo/*<int>*/(/*int*/ 42);
+}
+
+// -----------------------------------------------------------------------------
+
+main() {}
diff --git a/pkg/nnbd_migration/lib/src/edge_builder.dart b/pkg/nnbd_migration/lib/src/edge_builder.dart
index 5a73336..f802599 100644
--- a/pkg/nnbd_migration/lib/src/edge_builder.dart
+++ b/pkg/nnbd_migration/lib/src/edge_builder.dart
@@ -274,15 +274,17 @@
   @override
   DecoratedType visitAssignmentExpression(AssignmentExpression node) {
     _CompoundOperatorInfo compoundOperatorInfo;
+    bool isQuestionAssign = false;
     if (node.operator.type == TokenType.QUESTION_QUESTION_EQ) {
-      _unimplemented(node, 'Assignment with operator ??=');
+      isQuestionAssign = true;
     } else if (node.operator.type != TokenType.EQ) {
       compoundOperatorInfo = _CompoundOperatorInfo(
           node.staticElement, node.operator.offset, node.staticType);
     }
     var expressionType = _handleAssignment(node.rightHandSide,
         destinationExpression: node.leftHandSide,
-        compoundOperatorInfo: compoundOperatorInfo);
+        compoundOperatorInfo: compoundOperatorInfo,
+        questionAssignNode: isQuestionAssign ? node : null);
     var conditionalNode = _conditionalNodes[node.leftHandSide];
     if (conditionalNode != null) {
       expressionType = expressionType.withNode(
@@ -369,13 +371,17 @@
           (callee.enclosingElement as ClassElement)
               .typeParameters
               .isNotEmpty)); // TODO(paulberry)
-      assert(callee != null); // TODO(paulberry)
-      var calleeType = getOrComputeElementType(callee);
-      // TODO(paulberry): substitute if necessary
-      assert(calleeType.positionalParameters.length > 0); // TODO(paulberry)
-      _handleAssignment(node.rightOperand,
-          destinationType: calleeType.positionalParameters[0]);
-      return _fixNumericTypes(calleeType.returnType, node.staticType);
+      if (callee == null) {
+        node.rightOperand.accept(this);
+        return _dynamicType;
+      } else {
+        var calleeType = getOrComputeElementType(callee);
+        // TODO(paulberry): substitute if necessary
+        assert(calleeType.positionalParameters.length > 0); // TODO(paulberry)
+        _handleAssignment(node.rightOperand,
+            destinationType: calleeType.positionalParameters[0]);
+        return _fixNumericTypes(calleeType.returnType, node.staticType);
+      }
     } else {
       // TODO(paulberry)
       node.leftOperand.accept(this);
@@ -662,9 +668,8 @@
   @override
   DecoratedType visitFunctionExpressionInvocation(
       FunctionExpressionInvocation node) {
-    DecoratedType calleeType = node.function.accept(this);
-    return _handleInvocationArguments(node, node.argumentList.arguments,
-        node.typeArguments, node.typeArgumentTypes, calleeType, null);
+    return _handleFunctionExpressionInvocation(node, node.function,
+        node.argumentList, node.typeArguments, node.typeArgumentTypes);
   }
 
   @override
@@ -901,7 +906,13 @@
       // Dynamic dispatch.  The return type is `dynamic`.
       // TODO(paulberry): would it be better to assume a return type of `Never`
       // so that we don't unnecessarily propagate nullabilities everywhere?
+      node.typeArguments?.accept(this);
+      node.argumentList.accept(this);
       return _dynamicType;
+    } else if (callee is VariableElement) {
+      // Function expression invocation that looks like a method invocation.
+      return _handleFunctionExpressionInvocation(node, node.methodName,
+          node.argumentList, node.typeArguments, node.typeArgumentTypes);
     }
     var calleeType = getOrComputeElementType(callee, targetType: targetType);
     if (callee is PropertyAccessorElement) {
@@ -1184,7 +1195,7 @@
 
   @override
   DecoratedType visitSuperExpression(SuperExpression node) {
-    return DecoratedType(node.staticType, _graph.never);
+    return _handleThisOrSuper(node);
   }
 
   @override
@@ -1214,7 +1225,7 @@
 
   @override
   DecoratedType visitThisExpression(ThisExpression node) {
-    return DecoratedType(node.staticType, _graph.never);
+    return _handleThisOrSuper(node);
   }
 
   @override
@@ -1535,6 +1546,7 @@
       {DecoratedType destinationType,
       Expression destinationExpression,
       _CompoundOperatorInfo compoundOperatorInfo,
+      Expression questionAssignNode,
       bool canInsertChecks = true}) {
     assert(
         (destinationExpression == null) != (destinationType == null),
@@ -1554,47 +1566,64 @@
         destinationType = destinationExpression.accept(this);
       }
     }
-    var sourceType = expression.accept(this);
-    if (sourceType == null) {
-      throw StateError('No type computed for ${expression.runtimeType} '
-          '(${expression.toSource()}) offset=${expression.offset}');
+    if (questionAssignNode != null) {
+      _guards.add(destinationType.node);
     }
-    ExpressionChecks expressionChecks;
-    if (canInsertChecks && !sourceType.type.isDynamic) {
-      expressionChecks = ExpressionChecks(expression.end);
-      _variables.recordExpressionChecks(source, expression, expressionChecks);
-    }
-    if (compoundOperatorInfo != null) {
-      var compoundOperatorMethod = compoundOperatorInfo.method;
-      if (compoundOperatorMethod != null) {
-        _checkAssignment(
-            CompoundAssignmentOrigin(source, compoundOperatorInfo.offset),
-            source: destinationType,
-            destination: _notNullType,
-            hard:
-                _postDominatedLocals.isReferenceInScope(destinationExpression));
-        DecoratedType compoundOperatorType =
-            getOrComputeElementType(compoundOperatorMethod);
-        assert(compoundOperatorType.positionalParameters.length > 0);
+    DecoratedType sourceType;
+    try {
+      sourceType = expression.accept(this);
+      if (sourceType == null) {
+        throw StateError('No type computed for ${expression.runtimeType} '
+            '(${expression.toSource()}) offset=${expression.offset}');
+      }
+      ExpressionChecks expressionChecks;
+      if (canInsertChecks && !sourceType.type.isDynamic) {
+        expressionChecks = ExpressionChecks(expression.end);
+        _variables.recordExpressionChecks(source, expression, expressionChecks);
+      }
+      if (compoundOperatorInfo != null) {
+        var compoundOperatorMethod = compoundOperatorInfo.method;
+        if (compoundOperatorMethod != null) {
+          _checkAssignment(
+              CompoundAssignmentOrigin(source, compoundOperatorInfo.offset),
+              source: destinationType,
+              destination: _notNullType,
+              hard: _postDominatedLocals
+                  .isReferenceInScope(destinationExpression));
+          DecoratedType compoundOperatorType =
+              getOrComputeElementType(compoundOperatorMethod);
+          assert(compoundOperatorType.positionalParameters.length > 0);
+          _checkAssignment(expressionChecks,
+              source: sourceType,
+              destination: compoundOperatorType.positionalParameters[0],
+              hard: _postDominatedLocals.isReferenceInScope(expression));
+          sourceType = _fixNumericTypes(compoundOperatorType.returnType,
+              compoundOperatorInfo.undecoratedType);
+          _checkAssignment(
+              CompoundAssignmentOrigin(source, compoundOperatorInfo.offset),
+              source: sourceType,
+              destination: destinationType,
+              hard: false);
+        } else {
+          sourceType = _dynamicType;
+        }
+      } else {
         _checkAssignment(expressionChecks,
             source: sourceType,
-            destination: compoundOperatorType.positionalParameters[0],
-            hard: _postDominatedLocals.isReferenceInScope(expression));
-        sourceType = _fixNumericTypes(compoundOperatorType.returnType,
-            compoundOperatorInfo.undecoratedType);
-        _checkAssignment(
-            CompoundAssignmentOrigin(source, compoundOperatorInfo.offset),
-            source: sourceType,
             destination: destinationType,
-            hard: false);
-      } else {
-        sourceType = _dynamicType;
+            hard: _postDominatedLocals.isReferenceInScope(expression));
       }
-    } else {
-      _checkAssignment(expressionChecks,
-          source: sourceType,
-          destination: destinationType,
-          hard: _postDominatedLocals.isReferenceInScope(expression));
+      if (questionAssignNode != null) {
+        // a ??= b is only nullable if both a and b are nullable.
+        sourceType = destinationType.withNode(_nullabilityNodeForGLB(
+            questionAssignNode, sourceType.node, destinationType.node));
+        _variables.recordDecoratedExpressionType(
+            questionAssignNode, sourceType);
+      }
+    } finally {
+      if (questionAssignNode != null) {
+        _guards.removeLast();
+      }
     }
     if (destinationExpression != null) {
       _postDominatedLocals.removeReferenceFromAllScopes(destinationExpression);
@@ -1647,9 +1676,9 @@
     assert(_currentFunctionType == null);
     metadata.accept(this);
     returnType?.accept(this);
+    _createFlowAnalysis(body);
     parameters?.accept(this);
     _currentFunctionType = _variables.decoratedElementType(declaredElement);
-    _createFlowAnalysis(body);
     _addParametersToFlowAnalysis(parameters);
     // Push a scope of post-dominated declarations on the stack.
     _postDominatedLocals.pushScope(elements: declaredElement.parameters);
@@ -1780,6 +1809,24 @@
     });
   }
 
+  DecoratedType _handleFunctionExpressionInvocation(
+      AstNode node,
+      Expression function,
+      ArgumentList argumentList,
+      TypeArgumentList typeArguments,
+      List<DartType> typeArgumentTypes) {
+    DecoratedType calleeType = _checkExpressionNotNull(function);
+    if (calleeType.type is FunctionType) {
+      return _handleInvocationArguments(node, argumentList.arguments,
+          typeArguments, typeArgumentTypes, calleeType, null);
+    } else {
+      // Invocation of type `dynamic` or `Function`.
+      typeArguments?.accept(this);
+      argumentList.accept(this);
+      return _dynamicType;
+    }
+  }
+
   /// Creates the necessary constraint(s) for an [argumentList] when invoking an
   /// executable element whose type is [calleeType].
   ///
@@ -1913,6 +1960,19 @@
     }
   }
 
+  DecoratedType _handleThisOrSuper(Expression node) {
+    var type = node.staticType as InterfaceType;
+    // Instantiate the type, and any type arguments, with `_graph.never`,
+    // because the type of `this` is always `ClassName<Param, Param, ...>` with
+    // no `?`s.  (Even if some of the type parameters are allowed to be
+    // instantiated with nullable types at runtime, a reference to `this` can't
+    // be migrated in such a way that forces them to be nullable).
+    return DecoratedType(type, _graph.never,
+        typeArguments: type.typeArguments
+            .map((t) => DecoratedType(t, _graph.never))
+            .toList());
+  }
+
   bool _isConditionalExpression(Expression expression) {
     Token token;
     if (expression is MethodInvocation) {
@@ -2037,6 +2097,35 @@
       {@required DecoratedType source, @required DecoratedType destination}) {
     var sourceType = source.type;
     var destinationType = destination.type;
+    if (!_typeSystem.isSubtypeOf(sourceType, destinationType)) {
+      // Not a proper upcast assignment.  It is either an implicit downcast or
+      // some illegal code.  It's handled on a "best effort" basis.
+      if (destinationType is TypeParameterType &&
+          sourceType is! TypeParameterType) {
+        // Assume an assignment to the type parameter's bound.
+        _checkAssignment(origin,
+            source: source,
+            destination:
+                _getTypeParameterTypeBound(destination).withNode(_graph.always),
+            hard: false);
+        return;
+      }
+      if (sourceType is InterfaceType && destinationType is InterfaceType) {
+        if (_typeSystem.isSubtypeOf(destinationType, sourceType)) {
+          var rewrittenDestination = _decoratedClassHierarchy.asInstanceOf(
+              destination, sourceType.element);
+          assert(rewrittenDestination.typeArguments.length ==
+              source.typeArguments.length);
+          for (int i = 0; i < rewrittenDestination.typeArguments.length; i++) {
+            _checkAssignment(origin,
+                source: source.typeArguments[i],
+                destination: rewrittenDestination.typeArguments[i],
+                hard: false);
+          }
+        }
+      }
+      return;
+    }
     if (destinationType.isDartAsyncFutureOr) {
       // (From the subtyping spec):
       // if T1 is FutureOr<S1> then T0 <: T1 iff any of the following hold:
@@ -2059,8 +2148,9 @@
       else if (sourceType is TypeParameterType) {
         throw UnimplementedError('TODO(paulberry)');
       } else {
-        // Not a subtype; this must be a downcast.
-        throw UnimplementedError('TODO(paulberry)');
+        // Not a subtype.  This should never happen, since we handle the
+        // implicit downcast case above.
+        assert(false, 'not a subtype');
       }
     }
     if (sourceType.isBottom || sourceType.isDartCoreNull) {
@@ -2083,44 +2173,17 @@
             hard: false);
         return;
       }
-    } else if (destinationType is TypeParameterType) {
-      // Effectively this is a downcast assignment from the source type to the
-      // type parameter's bound.
-      _checkAssignment(origin,
-          source: source,
-          destination:
-              _getTypeParameterTypeBound(destination).withNode(_graph.always),
-          hard: false);
     } else if (sourceType is InterfaceType &&
         destinationType is InterfaceType) {
-      if (_typeSystem.isSubtypeOf(sourceType, destinationType)) {
-        // Ordinary (upcast) assignment.  No cast necessary.
-        var rewrittenSource = _decoratedClassHierarchy.asInstanceOf(
-            source, destinationType.element);
-        assert(rewrittenSource.typeArguments.length ==
-            destination.typeArguments.length);
-        for (int i = 0; i < rewrittenSource.typeArguments.length; i++) {
-          _checkAssignment(origin,
-              source: rewrittenSource.typeArguments[i],
-              destination: destination.typeArguments[i],
-              hard: false);
-        }
-      } else if (_typeSystem.isSubtypeOf(destinationType, sourceType)) {
-        // Implicit downcast assignment.
-        // TODO(paulberry): the migration tool should insert a cast.
-        var rewrittenDestination = _decoratedClassHierarchy.asInstanceOf(
-            destination, sourceType.element);
-        assert(rewrittenDestination.typeArguments.length ==
-            source.typeArguments.length);
-        for (int i = 0; i < rewrittenDestination.typeArguments.length; i++) {
-          _checkAssignment(origin,
-              source: source.typeArguments[i],
-              destination: rewrittenDestination.typeArguments[i],
-              hard: false);
-        }
-      } else {
-        // This should never arise for correct code; if it does arise, recover
-        // from the error by just not creating any additional edges.
+      var rewrittenSource = _decoratedClassHierarchy.asInstanceOf(
+          source, destinationType.element);
+      assert(rewrittenSource.typeArguments.length ==
+          destination.typeArguments.length);
+      for (int i = 0; i < rewrittenSource.typeArguments.length; i++) {
+        _checkAssignment(origin,
+            source: rewrittenSource.typeArguments[i],
+            destination: destination.typeArguments[i],
+            hard: false);
       }
     } else if (sourceType is FunctionType && destinationType is FunctionType) {
       _checkAssignment(origin,
diff --git a/pkg/nnbd_migration/test/edge_builder_test.dart b/pkg/nnbd_migration/test/edge_builder_test.dart
index 079cf85..1db66dc 100644
--- a/pkg/nnbd_migration/test/edge_builder_test.dart
+++ b/pkg/nnbd_migration/test/edge_builder_test.dart
@@ -375,6 +375,16 @@
     return variables.decoratedExpressionType(findNode.expression(text));
   }
 
+  test_already_migrated_field() async {
+    await analyze('''
+double f() => double.NAN;
+''');
+    var nanElement = typeProvider.doubleType.element.getField('NAN');
+    assertEdge(variables.decoratedElementType(nanElement).node,
+        decoratedTypeAnnotation('double f').node,
+        hard: false);
+  }
+
   test_as_dynamic() async {
     await analyze('''
 void f(Object o) {
@@ -401,16 +411,6 @@
     assertEdge(decoratedTypeAnnotation('int').node, never, hard: false);
   }
 
-  test_already_migrated_field() async {
-    await analyze('''
-double f() => double.NAN;
-''');
-    var nanElement = typeProvider.doubleType.element.getField('NAN');
-    assertEdge(variables.decoratedElementType(nanElement).node,
-        decoratedTypeAnnotation('double f').node,
-        hard: false);
-  }
-
   test_assert_demonstrates_non_null_intent() async {
     await analyze('''
 void f(int i) {
@@ -747,6 +747,48 @@
         hard: true);
   }
 
+  test_assignmentExpression_nullAware_complex_contravariant() async {
+    await analyze('''
+void Function(int) f(void Function(int) x, void Function(int) y) => x ??= y;
+''');
+    var xNullable =
+        decoratedGenericFunctionTypeAnnotation('void Function(int) x').node;
+    var xParamNullable = decoratedTypeAnnotation('int) x').node;
+    var yParamNullable = decoratedTypeAnnotation('int) y').node;
+    var returnParamNullable = decoratedTypeAnnotation('int) f').node;
+    assertEdge(xParamNullable, yParamNullable,
+        hard: false, guards: [xNullable]);
+    assertEdge(returnParamNullable, xParamNullable, hard: false);
+  }
+
+  test_assignmentExpression_nullAware_complex_covariant() async {
+    await analyze('''
+List<int> f(List<int> x, List<int> y) => x ??= y;
+''');
+    var xNullable = decoratedTypeAnnotation('List<int> x').node;
+    var xElementNullable = decoratedTypeAnnotation('int> x').node;
+    var yElementNullable = decoratedTypeAnnotation('int> y').node;
+    var returnElementNullable = decoratedTypeAnnotation('int> f').node;
+    assertEdge(yElementNullable, xElementNullable,
+        hard: false, guards: [xNullable]);
+    assertEdge(xElementNullable, returnElementNullable, hard: false);
+  }
+
+  test_assignmentExpression_nullAware_simple() async {
+    await analyze('''
+int f(int x, int y) => (x ??= y);
+''');
+    var yNullable = decoratedTypeAnnotation('int y').node;
+    var xNullable = decoratedTypeAnnotation('int x').node;
+    var returnNullable = decoratedTypeAnnotation('int f').node;
+    var glbNode = decoratedExpressionType('(x ??= y)').node;
+    assertEdge(yNullable, xNullable, hard: true, guards: [xNullable]);
+    assertEdge(yNullable, glbNode, hard: false, guards: [xNullable]);
+    assertEdge(glbNode, xNullable, hard: false);
+    assertEdge(glbNode, yNullable, hard: false);
+    assertEdge(glbNode, returnNullable, hard: false);
+  }
+
   test_assignmentExpression_operands() async {
     await analyze('''
 void f(int i, int j) {
@@ -939,6 +981,18 @@
     assertNoUpstreamNullability(decoratedTypeAnnotation('int f').node);
   }
 
+  test_binaryExpression_left_dynamic() async {
+    await analyze('''
+Object f(dynamic x, int y) => x + g(y);
+int g(int z) => z;
+''');
+    assertEdge(decoratedTypeAnnotation('int y').node,
+        decoratedTypeAnnotation('int z').node,
+        hard: true);
+    assertNoEdge(decoratedTypeAnnotation('int g').node, anyNode);
+    assertEdge(always, decoratedTypeAnnotation('Object f').node, hard: false);
+  }
+
   test_binaryExpression_lt_result_not_null() async {
     await analyze('''
 bool f(int i, int j) => i < j;
@@ -1088,6 +1142,20 @@
     assertEdge(right, expression, guards: [left], hard: false);
   }
 
+  test_binaryExpression_right_dynamic() async {
+    await analyze('''
+class C {
+  C operator+(C other) => other;
+}
+C f(C x, dynamic y) => x + y;
+''');
+    assertNullCheck(checkExpression('x +'),
+        assertEdge(decoratedTypeAnnotation('C x').node, never, hard: true));
+    assertEdge(decoratedTypeAnnotation('C operator').node,
+        decoratedTypeAnnotation('C f').node,
+        hard: false);
+  }
+
   test_binaryExpression_slash_result_not_null() async {
     await analyze('''
 double f(int i, int j) => i / j;
@@ -1439,6 +1507,15 @@
     assertLUB(nullable_conditional, nullable_i, always);
   }
 
+  test_constructor_default_parameter_value_bool() async {
+    await analyze('''
+class C {
+  C([bool b = true]);
+}
+''');
+    assertNoUpstreamNullability(decoratedTypeAnnotation('bool b').node);
+  }
+
   test_constructor_named() async {
     await analyze('''
 class C {
@@ -2486,6 +2563,92 @@
     assertNoUpstreamNullability(decoratedTypeAnnotation('int').node);
   }
 
+  test_invocation_arguments() async {
+    await analyze('''
+int f(Function g, int i, int j) => g(h(i), named: h(j));
+int h(int x) => 0;
+''');
+    // Make sure the appropriate edges get created for the calls to h().
+    assertEdge(decoratedTypeAnnotation('int i').node,
+        decoratedTypeAnnotation('int x').node,
+        hard: true);
+    assertEdge(decoratedTypeAnnotation('int j').node,
+        decoratedTypeAnnotation('int x').node,
+        hard: true);
+  }
+
+  test_invocation_arguments_parenthesized() async {
+    await analyze('''
+int f(Function g, int i, int j) => (g)(h(i), named: h(j));
+int h(int x) => 0;
+''');
+    // Make sure the appropriate edges get created for the calls to h().
+    assertEdge(decoratedTypeAnnotation('int i').node,
+        decoratedTypeAnnotation('int x').node,
+        hard: true);
+    assertEdge(decoratedTypeAnnotation('int j').node,
+        decoratedTypeAnnotation('int x').node,
+        hard: true);
+  }
+
+  test_invocation_dynamic() async {
+    await analyze('''
+int f(dynamic g) => g();
+''');
+    assertEdge(always, decoratedTypeAnnotation('int f').node, hard: false);
+  }
+
+  test_invocation_dynamic_parenthesized() async {
+    await analyze('''
+int f(dynamic g) => (g)();
+''');
+    assertEdge(always, decoratedTypeAnnotation('int f').node, hard: false);
+  }
+
+  test_invocation_function() async {
+    await analyze('''
+int f(Function g) => g();
+''');
+    assertEdge(always, decoratedTypeAnnotation('int f').node, hard: false);
+    assertNullCheck(
+        checkExpression('g('),
+        assertEdge(decoratedTypeAnnotation('Function g').node, never,
+            hard: true));
+  }
+
+  test_invocation_function_parenthesized() async {
+    await analyze('''
+int f(Function g) => (g)();
+''');
+    assertEdge(always, decoratedTypeAnnotation('int f').node, hard: false);
+    assertNullCheck(
+        checkExpression('g)('),
+        assertEdge(decoratedTypeAnnotation('Function g').node, never,
+            hard: true));
+  }
+
+  test_invocation_type_arguments() async {
+    await analyze('''
+int f(Function g) => g<C<int>>();
+class C<T extends num> {}
+''');
+    // Make sure the appropriate edge gets created for the instantiation of C.
+    assertEdge(decoratedTypeAnnotation('int>').node,
+        decoratedTypeAnnotation('num>').node,
+        hard: true);
+  }
+
+  test_invocation_type_arguments_parenthesized() async {
+    await analyze('''
+int f(Function g) => (g)<C<int>>();
+class C<T extends num> {}
+''');
+    // Make sure the appropriate edge gets created for the instantiation of C.
+    assertEdge(decoratedTypeAnnotation('int>').node,
+        decoratedTypeAnnotation('num>').node,
+        hard: true);
+  }
+
   @failingTest
   test_isExpression_genericFunctionType() async {
     await analyze('''
@@ -2691,6 +2854,35 @@
     assertEdge(always, decoratedTypeAnnotation('int f').node, hard: false);
   }
 
+  test_methodInvocation_dynamic_arguments() async {
+    await analyze('''
+int f(dynamic d, int i, int j) {
+  return d.g(h(i), named: h(j));
+}
+int h(int x) => 0;
+''');
+    // Make sure the appropriate edges get created for the calls to h().
+    assertEdge(decoratedTypeAnnotation('int i').node,
+        decoratedTypeAnnotation('int x').node,
+        hard: true);
+    assertEdge(decoratedTypeAnnotation('int j').node,
+        decoratedTypeAnnotation('int x').node,
+        hard: true);
+  }
+
+  test_methodInvocation_dynamic_type_arguments() async {
+    await analyze('''
+int f(dynamic d, int i, int j) {
+  return d.g<C<int>>();
+}
+class C<T extends num> {}
+''');
+    // Make sure the appropriate edge gets created for the instantiation of C.
+    assertEdge(decoratedTypeAnnotation('int>').node,
+        decoratedTypeAnnotation('num>').node,
+        hard: true);
+  }
+
   test_methodInvocation_object_method() async {
     await analyze('''
 String f(int i) => i.toString();
@@ -4601,12 +4793,36 @@
 
   test_superExpression() async {
     await analyze('''
-class C {
-  C f() => super;
+class B {
+  void f(int/*1*/ i, int/*2*/ j) {}
+}
+class C extends B {
+  void f(int/*3*/ i, int/*4*/ j) => super.f(j, i);
 }
 ''');
+    assertEdge(decoratedTypeAnnotation('int/*3*/').node,
+        decoratedTypeAnnotation('int/*2*/').node,
+        hard: true);
+    assertEdge(decoratedTypeAnnotation('int/*4*/').node,
+        decoratedTypeAnnotation('int/*1*/').node,
+        hard: true);
+  }
 
-    assertNoUpstreamNullability(decoratedTypeAnnotation('C f').node);
+  test_superExpression_generic() async {
+    await analyze('''
+class B<U> {
+  U g() => null;
+}
+class C<T> extends B<T> {
+  T f() => super.g();
+}
+''');
+    assertEdge(
+        substitutionNode(
+            substitutionNode(never, decoratedTypeAnnotation('T> {').node),
+            decoratedTypeAnnotation('U g').node),
+        decoratedTypeAnnotation('T f').node,
+        hard: false);
   }
 
   test_symbolLiteral() async {
@@ -4624,10 +4840,19 @@
   C f() => this;
 }
 ''');
-
     assertNoUpstreamNullability(decoratedTypeAnnotation('C f').node);
   }
 
+  test_thisExpression_generic() async {
+    await analyze('''
+class C<T> {
+  C<T> f() => this;
+}
+''');
+    assertNoUpstreamNullability(decoratedTypeAnnotation('C<T> f').node);
+    assertNoUpstreamNullability(decoratedTypeAnnotation('T> f').node);
+  }
+
   test_throwExpression() async {
     await analyze('''
 int f() {
diff --git a/pkg/smith/lib/configuration.dart b/pkg/smith/lib/configuration.dart
index fc7883a..07653eb 100644
--- a/pkg/smith/lib/configuration.dart
+++ b/pkg/smith/lib/configuration.dart
@@ -908,7 +908,7 @@
 
   /// Opted in to NNBD features, but only static checking and weak runtime
   /// checks.
-  static const optedIn = NnbdMode._('opted-in');
+  static const weak = NnbdMode._('weak');
 
   /// Opted in to NNBD features and with full sound runtime checks.
   static const strong = NnbdMode._('strong');
@@ -916,7 +916,7 @@
   static final List<String> names = _all.keys.toList();
 
   static final _all = {
-    for (var mode in [legacy, optedIn, strong]) mode.name: mode
+    for (var mode in [legacy, weak, strong]) mode.name: mode
   };
 
   static NnbdMode find(String name) {
diff --git a/pkg/smith/test/configuration_test.dart b/pkg/smith/test/configuration_test.dart
index fcbbebf..4f5736e 100644
--- a/pkg/smith/test/configuration_test.dart
+++ b/pkg/smith/test/configuration_test.dart
@@ -198,7 +198,7 @@
       test("other options from map", () {
         expect(
             Configuration.parse("dart2js", {
-              "nnbd": "opted-in",
+              "nnbd": "weak",
               "builder-tag": "the tag",
               "vm-options": ["vm stuff", "more vm stuff"],
               "dart2js-options": ["dart2js stuff", "more dart2js stuff"],
@@ -214,7 +214,7 @@
             }),
             equals(Configuration("dart2js", Architecture.x64, Compiler.dart2js,
                 Mode.release, Runtime.d8, System.host,
-                nnbdMode: NnbdMode.optedIn,
+                nnbdMode: NnbdMode.weak,
                 builderTag: "the tag",
                 vmOptions: ["vm stuff", "more vm stuff"],
                 dart2jsOptions: ["dart2js stuff", "more dart2js stuff"],
diff --git a/pkg/test_runner/bin/test_runner.dart b/pkg/test_runner/bin/test_runner.dart
index 491e10b..3f5e048 100644
--- a/pkg/test_runner/bin/test_runner.dart
+++ b/pkg/test_runner/bin/test_runner.dart
@@ -1,6 +1,7 @@
 // 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';
 
 /// This file is the entrypoint of the Dart repository's custom test system.
 /// It is used to test:
@@ -28,11 +29,16 @@
 void main(List<String> arguments) {
   // Parse the command line arguments to a configuration.
   var parser = OptionsParser();
-  var configurations = parser.parse(arguments);
-  if (configurations == null || configurations.isEmpty) return;
+  try {
+    var configurations = parser.parse(arguments);
+    if (configurations == null || configurations.isEmpty) return;
 
-  // Run all of the configured tests.
-  // TODO(26372): Ensure that all tasks complete and return a future from this
-  // function.
-  testConfigurations(configurations);
+    // Run all of the configured tests.
+    // TODO(26372): Ensure that all tasks complete and return a future from this
+    // function.
+    testConfigurations(configurations);
+  } on OptionParseException catch (exception) {
+    print(exception.message);
+    exit(1);
+  }
 }
diff --git a/pkg/test_runner/lib/src/options.dart b/pkg/test_runner/lib/src/options.dart
index 9de4b81..ed972e7 100644
--- a/pkg/test_runner/lib/src/options.dart
+++ b/pkg/test_runner/lib/src/options.dart
@@ -37,11 +37,16 @@
   // TODO(rnystrom): Some string options use "" to mean "no value" and others
   // use null. Clean that up.
   _Option(this.name, this.description,
-      {String abbr, List<String> values, String defaultsTo, bool hide})
+      {String abbr,
+      List<String> values,
+      String defaultsTo,
+      bool allowMultiple,
+      bool hide})
       : abbreviation = abbr,
         values = values ?? [],
         defaultValue = defaultsTo,
         type = _OptionValueType.string,
+        allowMultiple = allowMultiple ?? true,
         verboseOnly = hide ?? false;
 
   _Option.bool(this.name, this.description, {String abbr, bool hide})
@@ -49,6 +54,7 @@
         values = [],
         defaultValue = false,
         type = _OptionValueType.bool,
+        allowMultiple = false,
         verboseOnly = hide ?? false;
 
   _Option.int(this.name, this.description,
@@ -57,6 +63,7 @@
         values = [],
         defaultValue = defaultsTo,
         type = _OptionValueType.int,
+        allowMultiple = false,
         verboseOnly = hide ?? false;
 
   final String name;
@@ -66,14 +73,16 @@
   final Object defaultValue;
   final _OptionValueType type;
 
+  /// Whether a comma-separated list of values is permitted.
+  final bool allowMultiple;
+
   /// Only show this option in the verbose help.
   final bool verboseOnly;
 
-  /// Gets the shortest command line argument used to refer to this option.
+  /// The shortest command line argument used to refer to this option.
   String get shortCommand => abbreviation != null ? "-$abbreviation" : command;
 
-  /// Gets the canonical long command line argument used to refer to this
-  /// option.
+  /// The canonical long command line argument used to refer to this option.
   String get command => "--${name.replaceAll('_', '-')}";
 }
 
@@ -151,7 +160,6 @@
 test options, specifying how tests should be run.''',
         abbr: 'n',
         hide: true),
-    _Option.bool('strong', 'Deprecated, no-op.', hide: true),
     // TODO(sigmund): rename flag once we migrate all dart2js bots to the test
     // matrix.
     _Option.bool('host_checked', 'Run compiler with assertions enabled.',
@@ -189,7 +197,8 @@
 compact, color, line, verbose, silent, status, buildbot, diff''',
         abbr: 'p',
         values: Progress.names,
-        defaultsTo: Progress.compact.name),
+        defaultsTo: Progress.compact.name,
+        allowMultiple: false),
     _Option('step_name', 'Step name for use by -pbuildbot.', hide: true),
     _Option.bool('report',
         'Print a summary report of the number of tests, by expectation.',
@@ -230,9 +239,14 @@
     _Option('chrome', 'Path to chrome browser executable.', hide: true),
     _Option('safari', 'Path to safari browser executable.', hide: true),
     _Option.bool('use_sdk', '''Use compiler or runtime from the SDK.'''),
-    _Option.bool('nnbd', '''Opt tests into non-nullable types.'''),
-    _Option.bool('nnbd_strong_checking',
-        '''Enable strong runtime checks of non-nullable types.'''),
+    _Option(
+        'nnbd',
+        '''Which set of non-nullable type features to use.
+
+Allowed values are: legacy, weak, strong''',
+        values: NnbdMode.names,
+        defaultsTo: NnbdMode.legacy.name,
+        allowMultiple: false),
     // TODO(rnystrom): This does not appear to be used. Remove?
     _Option('build_directory',
         'The name of the build directory, where products are placed.',
@@ -380,6 +394,7 @@
           verbose: arguments.contains("--verbose") || arguments.contains("-v"));
       return null;
     }
+
     if (arguments.contains("--list-configurations")) {
       var testMatrixFile = "tools/bots/test_matrix.json";
       var testMatrix = TestMatrix.fromPath(testMatrixFile);
@@ -476,11 +491,20 @@
         case _OptionValueType.string:
           // Validate against the allowed values.
           if (!option.values.isEmpty) {
-            for (var v in value.split(",")) {
-              if (!option.values.contains(v)) {
-                _fail('Unknown value "$v" for command line option "$command".');
+            validate(String value) {
+              if (!option.values.contains(value)) {
+                _fail('Unknown value "$value" for option "$command".');
               }
             }
+
+            if (option.allowMultiple) {
+              value.split(",").forEach(validate);
+            } else {
+              if (value.contains(",")) {
+                _fail('Only a single value is allowed for option "$command".');
+              }
+              validate(value);
+            }
           }
 
           // TODO(rnystrom): Store as a list instead of a comma-delimited
@@ -493,9 +517,9 @@
     // If a named configuration was specified ensure no other options, which are
     // implied by the named configuration, were specified.
     if (configuration['named_configuration'] is String) {
-      for (final optionName in _namedConfigurationOptions) {
+      for (var optionName in _namedConfigurationOptions) {
         if (configuration.containsKey(optionName)) {
-          final namedConfig = configuration['named_configuration'];
+          var namedConfig = configuration['named_configuration'];
           _fail("The named configuration '$namedConfig' implies "
               "'$optionName'. Try removing '$optionName'.");
         }
@@ -654,6 +678,9 @@
       compilers.addAll(runtimes.map((runtime) => runtime.defaultCompiler));
     }
 
+    var progress = Progress.find(data["progress"] as String);
+    var nnbdMode = NnbdMode.find(data["nnbd"] as String);
+
     // Expand runtimes.
     for (var runtime in runtimes) {
       // Start installing the runtime if needed.
@@ -676,10 +703,11 @@
             var mode = Mode.find(modeName);
             var system = System.find(data["system"] as String);
             var namedConfiguration =
-                getNamedConfiguration(data["named_configuration"] as String);
+                _namedConfiguration(data["named_configuration"] as String);
             var innerConfiguration = namedConfiguration ??
                 Configuration("custom configuration", architecture, compiler,
                     mode, runtime, system,
+                    nnbdMode: nnbdMode,
                     timeout: data["timeout"] as int,
                     enableAsserts: data["enable_asserts"] as bool,
                     useAnalyzerCfe: data["use_cfe"] as bool,
@@ -700,7 +728,7 @@
                     builderTag: data["builder_tag"] as String);
             var configuration = TestConfiguration(
                 configuration: innerConfiguration,
-                progress: Progress.find(data["progress"] as String),
+                progress: progress,
                 selectors: selectors,
                 testList: data["test_list_contents"] as List<String>,
                 repeat: data["repeat"] as int,
@@ -903,14 +931,22 @@
   }
 }
 
-Configuration getNamedConfiguration(String template) {
+/// Exception thrown when the arguments could not be parsed.
+class OptionParseException implements Exception {
+  final String message;
+
+  OptionParseException(this.message);
+}
+
+Configuration _namedConfiguration(String template) {
   if (template == null) return null;
-  final testMatrixFile = "tools/bots/test_matrix.json";
-  TestMatrix testMatrix = TestMatrix.fromPath(testMatrixFile);
-  final configuration = testMatrix.configurations
+
+  var testMatrixFile = "tools/bots/test_matrix.json";
+  var testMatrix = TestMatrix.fromPath(testMatrixFile);
+  var configuration = testMatrix.configurations
       .singleWhere((c) => c.name == template, orElse: () => null);
   if (configuration == null) {
-    final names = testMatrix.configurations
+    var names = testMatrix.configurations
         .map((configuration) => configuration.name)
         .toList();
     names.sort();
@@ -921,8 +957,7 @@
   return configuration;
 }
 
-/// Prints [message] and exits with a non-zero exit code.
+/// Throws an [OptionParseException] with [message].
 void _fail(String message) {
-  print(message);
-  exit(1);
+  throw OptionParseException(message);
 }
diff --git a/pkg/test_runner/lib/src/process_queue.dart b/pkg/test_runner/lib/src/process_queue.dart
index 72ab4c2..01a2fb1 100644
--- a/pkg/test_runner/lib/src/process_queue.dart
+++ b/pkg/test_runner/lib/src/process_queue.dart
@@ -1131,7 +1131,7 @@
     }
     var processFuture =
         io.Process.start(executable, arguments, environment: environment);
-    processFuture.then((io.Process p) {
+    processFuture.then<dynamic>((io.Process p) {
       _process = p;
 
       Stream<String> _stdoutStream = _process.stdout
diff --git a/pkg/test_runner/lib/src/static_error.dart b/pkg/test_runner/lib/src/static_error.dart
index 518d91b..e339a5e 100644
--- a/pkg/test_runner/lib/src/static_error.dart
+++ b/pkg/test_runner/lib/src/static_error.dart
@@ -2,6 +2,9 @@
 // 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.
 
+// Only needed so that [TestFile] can be referenced in doc comments.
+import 'test_file.dart';
+
 /// Describes a static error.
 ///
 /// These can be parsed from comments in [TestFile]s, in which case they
diff --git a/pkg/test_runner/lib/src/test_case.dart b/pkg/test_runner/lib/src/test_case.dart
index 4e7e080..2b153eaa 100644
--- a/pkg/test_runner/lib/src/test_case.dart
+++ b/pkg/test_runner/lib/src/test_case.dart
@@ -269,7 +269,7 @@
       var processFuture = io.Process.start(command.executable, args,
           environment: processEnvironment,
           workingDirectory: command.workingDirectory);
-      processFuture.then((io.Process process) {
+      processFuture.then<dynamic>((io.Process process) {
         var stdoutFuture = process.stdout.pipe(stdout);
         var stderrFuture = process.stderr.pipe(stderr);
         pid = process.pid;
diff --git a/pkg/test_runner/test/options_test.dart b/pkg/test_runner/test/options_test.dart
new file mode 100644
index 0000000..cf1b98e
--- /dev/null
+++ b/pkg/test_runner/test/options_test.dart
@@ -0,0 +1,80 @@
+// 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:expect/expect.dart';
+
+import 'package:test_runner/src/configuration.dart';
+import 'package:test_runner/src/options.dart';
+
+void main() {
+  testDefaults();
+  testOptions();
+  testValidation();
+}
+
+void testDefaults() {
+  // TODO(rnystrom): Test other options.
+  var configuration = parseConfiguration([]);
+  Expect.equals(Progress.compact, configuration.progress);
+  Expect.equals(NnbdMode.legacy, configuration.nnbdMode);
+}
+
+void testOptions() {
+  // TODO(rnystrom): Test other options.
+  var configurations = parseConfigurations(['--mode=debug,release']);
+  Expect.equals(2, configurations.length);
+  Expect.equals(Mode.debug, configurations[0].mode);
+  Expect.equals(Mode.release, configurations[1].mode);
+
+  var configuration = parseConfiguration(['--nnbd=weak']);
+  Expect.equals(NnbdMode.weak, configuration.nnbdMode);
+}
+
+void testValidation() {
+  // TODO(rnystrom): Test other options.
+  expectValidationError(
+      ['--timeout=notint'], 'Integer value expected for option "--timeout".');
+  expectValidationError(
+      ['--timeout=1,2'], 'Integer value expected for option "--timeout".');
+
+  expectValidationError(['--progress=unknown'],
+      'Unknown value "unknown" for option "--progress".');
+  // Don't allow multiple.
+  expectValidationError(['--progress=compact,silent'],
+      'Only a single value is allowed for option "--progress".');
+
+  expectValidationError(
+      ['--nnbd=unknown'], 'Unknown value "unknown" for option "--nnbd".');
+  // Don't allow multiple.
+  expectValidationError(['--nnbd=weak,strong'],
+      'Only a single value is allowed for option "--nnbd".');
+}
+
+TestConfiguration parseConfiguration(List<String> arguments) {
+  var configurations = parseConfigurations(arguments);
+  Expect.equals(1, configurations.length);
+  return configurations.first;
+}
+
+List<TestConfiguration> parseConfigurations(List<String> arguments) {
+  var parser = OptionsParser();
+  var configurations = parser.parse(arguments);
+
+  // By default, without an explicit selector, you get two configurations, one
+  // for observatory_ui, and one for all the other selectors. Discard the
+  // observatory one to keep things simpler.
+  configurations
+      .removeWhere((config) => config.selectors.containsKey('observatory_ui'));
+  return configurations;
+}
+
+void expectValidationError(List<String> arguments, String error) {
+  try {
+    OptionsParser().parse(arguments);
+    Expect.fail('Should have thrown an exception, but did not.');
+  } on OptionParseException catch (exception) {
+    Expect.equals(error, exception.message);
+  } catch (exception) {
+    Expect.fail('Wrong exception: $exception');
+  }
+}
diff --git a/runtime/bin/main.cc b/runtime/bin/main.cc
index f23de40..2ff8888 100644
--- a/runtime/bin/main.cc
+++ b/runtime/bin/main.cc
@@ -1154,7 +1154,7 @@
 
   char* error = nullptr;
   if (!dart::embedder::InitOnce(&error)) {
-    Syslog::PrintErr("Stanalone embedder initialization failed: %s\n", error);
+    Syslog::PrintErr("Standalone embedder initialization failed: %s\n", error);
     free(error);
     Platform::Exit(kErrorExitCode);
   }
diff --git a/runtime/observatory/tests/service/external_service_asynchronous_invocation_test.dart b/runtime/observatory/tests/service/external_service_asynchronous_invocation_test.dart
index 3157090..4feafac 100644
--- a/runtime/observatory/tests/service/external_service_asynchronous_invocation_test.dart
+++ b/runtime/observatory/tests/service/external_service_asynchronous_invocation_test.dart
@@ -145,7 +145,7 @@
       completions.forEach((complete) => complete());
 
       final errors = await Future.wait(results.map((future) {
-        return future.then((_) {
+        return future.then<dynamic>((_) {
           expect(false, isTrue, reason: 'shouldn\'t get here');
         }).catchError((e) => e);
       }));
diff --git a/runtime/observatory/tests/service/service_kernel.status b/runtime/observatory/tests/service/service_kernel.status
index 3c70570..4a4cf8f 100644
--- a/runtime/observatory/tests/service/service_kernel.status
+++ b/runtime/observatory/tests/service/service_kernel.status
@@ -35,7 +35,6 @@
 rewind_optimized_out_test: SkipByDesign # No incremental compiler available.
 rewind_test: SkipByDesign # No incremental compiler available.
 simple_reload_test: RuntimeError, Timeout # Issue 35506
-unused_changes_in_last_reload_test: RuntimeError
 
 [ $compiler == dartkp ]
 *: SkipByDesign # Non-kernel also skips precompiled mode.
@@ -157,7 +156,6 @@
 rewind_test: Pass, RuntimeError
 set_name_rpc_test: RuntimeError # Please triage.
 simple_reload_test: RuntimeError, Timeout
-unused_changes_in_last_reload_test: Skip # Times out on sim architectures.
 valid_source_locations_test: Pass, Slow, Timeout # Issue 34736
 
 # Kernel works slightly different. There are kernel specific versions.
@@ -171,4 +169,3 @@
 evaluate_activation_test/scope: RuntimeError # http://dartbug.com/20047
 get_source_report_test: RuntimeError # Should pass again when constant evaluation is relanded, see http://dartbug.com/36600
 pause_on_unhandled_async_exceptions2_test: Pass, Slow
-unused_changes_in_last_reload_test: RuntimeError
diff --git a/runtime/observatory/tests/service/unused_changes_in_last_reload/v1/main.dart b/runtime/observatory/tests/service/unused_changes_in_last_reload/v1/main.dart
deleted file mode 100644
index 28f600c..0000000
--- a/runtime/observatory/tests/service/unused_changes_in_last_reload/v1/main.dart
+++ /dev/null
@@ -1,35 +0,0 @@
-// 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:isolate';
-
-unchangedFunction() => "unchanged";
-var unchangedField = "unchanged".toString();
-
-removedFunction() => "removed";
-var removedField = "removed".toString();
-
-function() => "original value";
-var uninitializedField = "original initializer".toString();
-var fieldLiteralInitializer = "original initializer";
-var initializedField = "original initializer".toString();
-var neverReferencedField = "original initializer".toString();
-
-// Not initially finalized.
-class C {
-  function() => "original value";
-}
-
-class S {}
-class M {}
-class MA1 extends S with M {}
-class MA2 = S with M;
-
-main() {
-  new RawReceivePort();  // Keep alive.
-  print(function());
-  print(initializedField);
-  print(new MA1());
-  print(new MA2());
-}
diff --git a/runtime/observatory/tests/service/unused_changes_in_last_reload/v2/main.dart b/runtime/observatory/tests/service/unused_changes_in_last_reload/v2/main.dart
deleted file mode 100644
index 910904f..0000000
--- a/runtime/observatory/tests/service/unused_changes_in_last_reload/v2/main.dart
+++ /dev/null
@@ -1,42 +0,0 @@
-// 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.
-
-unchangedFunction() => "unchanged";
-var unchangedField = "unchanged".toString();
-
-function() => "new value";
-var uninitializedField = "new initializer".toString();
-var fieldLiteralInitializer = "new initializer";
-var initializedField = "new initializer".toString();
-var neverReferencedField = "new initializer".toString();
-
-// Not initially finalized.
-class C {
-  function() => "new value";
-}
-
-class S {}
-class M {
-  newFunction() => "new value";
-}
-class MA1 extends S with M {
-  newFunction2() => "new value";
-}
-class MA2 = S with M;
-
-class NewClass {
-  function() => "new value";
-}
-
-typedef bool NewTypedef(Object obj);
-
-main2() {
-  print(function());
-  print(uninitializedField);
-  print(initializedField);
-  print(new C().function());
-  print(new NewClass().function());
-  print(new MA1().newFunction());
-  print(new MA1().newFunction2());
-}
diff --git a/runtime/observatory/tests/service/unused_changes_in_last_reload_test.dart b/runtime/observatory/tests/service/unused_changes_in_last_reload_test.dart
deleted file mode 100644
index 223ac40..0000000
--- a/runtime/observatory/tests/service/unused_changes_in_last_reload_test.dart
+++ /dev/null
@@ -1,126 +0,0 @@
-// 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 'test_helper.dart';
-import 'dart:developer';
-import 'dart:isolate' as I;
-import 'dart:io';
-import 'service_test_common.dart';
-import 'package:observatory/service.dart';
-import 'package:path/path.dart' as path;
-import 'package:unittest/unittest.dart';
-
-// Chop off the file name.
-String baseDirectory = path.dirname(Platform.script.path) + '/';
-
-Uri baseUri = Platform.script.replace(path: baseDirectory);
-Uri v1Uri = baseUri.resolveUri(Uri.parse('unused_changes_in_last_reload/v1/main.dart'));
-Uri v2Uri = baseUri.resolveUri(Uri.parse('unused_changes_in_last_reload/v2/main.dart'));
-
-testMain() async {
-  print(baseUri);
-  debugger(); // Stop here.
-  // Spawn the child isolate.
-  I.Isolate isolate = await I.Isolate.spawnUri(v1Uri, [], null);
-  print(isolate);
-  debugger();
-}
-
-var tests = <IsolateTest>[
-  // Stopped at 'debugger' statement.
-  hasStoppedAtBreakpoint,
-  // Resume the isolate into the while loop.
-  resumeIsolate,
-  // Stop at 'debugger' statement.
-  hasStoppedAtBreakpoint,
-  (Isolate mainIsolate) async {
-    // Grab the VM.
-    VM vm = mainIsolate.vm;
-    await vm.reloadIsolates();
-    expect(vm.isolates.length, 2);
-
-    // Find the child isolate.
-    Isolate childIsolate =
-        vm.isolates.firstWhere((Isolate i) => i != mainIsolate);
-    expect(childIsolate, isNotNull);
-
-    // Fetch unused.
-    await childIsolate.invokeRpc("_getUnusedChangesInLastReload", {}).then((v) {
-      print(v);
-      throw "MissingError";
-    }, onError: (e) {
-      print(e);
-    });
-
-    // Reload to v1 (null change).
-    var response = await childIsolate.reloadSources(
-      rootLibUri: v1Uri.toString(),
-    );
-    print(response);
-    expect(response['success'], isTrue);
-
-    // Fetch unused.
-    response = await childIsolate.invokeRpc("_getUnusedChangesInLastReload", {});
-    print(response);
-    var unused = response['unused'].map((ea) => ea.toString());
-    expect(unused, unorderedEquals([]));
-
-    // Reload to v2.
-    response = await childIsolate.reloadSources(
-      rootLibUri: v2Uri.toString(),
-    );
-    print(response);
-    expect(response['success'], isTrue);
-
-    // Fetch unused.
-    response = await childIsolate.invokeRpc("_getUnusedChangesInLastReload", {});
-    print(response);
-    unused = response['unused'].map((ea) => ea.toString());
-    expect(unused, unorderedEquals([
-      'Class(C)',
-      'Class(NewClass)',
-      'Field(main.dart.uninitializedField)',
-      'Field(main.dart.fieldLiteralInitializer)',
-      'Field(main.dart.initializedField)',
-      'Field(main.dart.neverReferencedField)',
-      'ServiceFunction(M.newFunction)',
-      'ServiceFunction(MA1.newFunction2)',
-      'ServiceFunction(function)',
-      'ServiceFunction(main2)',
-    ]));
-
-    // Invoke next main.
-    Library lib = childIsolate.rootLibrary;
-    await lib.load();
-    Instance result = await lib.evaluate('main2()');
-    expect(result.valueAsString, equals('null'));
-
-    // Fetch unused.
-    response = await childIsolate.invokeRpc("_getUnusedChangesInLastReload", {});
-    print(response);
-    unused = response['unused'].map((ea) => ea.toString());
-    expect(unused, unorderedEquals([
-      'Field(main.dart.fieldLiteralInitializer)',
-      'Field(main.dart.initializedField)',
-      'Field(main.dart.neverReferencedField)',
-      // TODO(31265): M.newFunction should be considered used.
-      'ServiceFunction(M.newFunction)',
-    ]));
-
-    // Reload to v2 again.
-    response = await childIsolate.reloadSources(
-      rootLibUri: v2Uri.toString(),
-    );
-    print(response);
-    expect(response['success'], isTrue);
-
-    // Fetch unused.
-    response = await childIsolate.invokeRpc("_getUnusedChangesInLastReload", {});
-    print(response);
-    unused = response['unused'].map((ea) => ea.toString());
-    expect(unused, unorderedEquals([]));
-  }
-];
-
-main(args) => runIsolateTests(args, tests, testeeConcurrent: testMain);
diff --git a/runtime/tools/bin_to_coff.py b/runtime/tools/bin_to_coff.py
index c8a8ebc..1925bcd 100644
--- a/runtime/tools/bin_to_coff.py
+++ b/runtime/tools/bin_to_coff.py
@@ -4,8 +4,6 @@
 # for details. All rights reserved. Use of this source code is governed by a
 # BSD-style license that can be found in the LICENSE file.
 
-# See also "PE Format" at https://docs.microsoft.com/en-us/windows/win32/debug/pe-format
-
 import argparse
 from ctypes import create_string_buffer
 from struct import *
@@ -21,7 +19,6 @@
 SECTION_HEADER_TEXT = 0x20  # Contains executable code
 SECTION_HEADER_DATA = 0x40  # Contains only initialized data
 SECTION_HEADER_BSS = 0x80  # Contains uninitialized data
-SECTION_HEADER_ALIGN_32BYTES = 0x600000
 
 # FILE HEADER FORMAT
 # typedef struct {
@@ -179,18 +176,17 @@
     offset += FILE_HEADER_SIZE
 
     section_name = SECTION_NAME_RODATA
-    section_flags = SECTION_HEADER_DATA
+    section_type = SECTION_HEADER_DATA
     if args.executable:
         section_name = SECTION_NAME_TEXT
-        section_flags = SECTION_HEADER_TEXT
-    section_flags |= SECTION_HEADER_ALIGN_32BYTES
+        section_type = SECTION_HEADER_TEXT
 
     # Populate the section header for a single section.
     pack_into(SECTION_HEADER_FORMAT, buff, offset, section_name, SECTION_PADDR,
               SECTION_VADDR, section_size + size_symbol_size,
               SECTION_RAW_DATA_PTR, SECTION_RELOCATION_PTR,
               SECTION_LINE_NUMS_PTR, SECTION_NUM_RELOCATION,
-              SECTION_NUM_LINE_NUMS, section_flags)
+              SECTION_NUM_LINE_NUMS, section_type)
     offset += SECTION_HEADER_SIZE
 
     # Copy the binary data.
diff --git a/runtime/tools/dartfuzz/collect_data.py b/runtime/tools/dartfuzz/collect_data.py
index 25b5f5d..6ce118f 100755
--- a/runtime/tools/dartfuzz/collect_data.py
+++ b/runtime/tools/dartfuzz/collect_data.py
@@ -87,8 +87,8 @@
         for i in range(len(s)):
             s[i] += int(test[i])
     print(
-        "Tests: %d Success: %d (Rerun: %d) Skipped: %d Timeout: %d Divergences: %d"
-        "(failing shards: %s)    \r" %
+        "Tests: %d Success: %d (Rerun: %d) Skipped: %d Timeout: %d "
+        "Divergences: %d (failing shards: %s)    \r" %
         tuple(s + [", ".join(divs) if divs else "none"]),
         end="")
 
diff --git a/runtime/tools/dartfuzz/dartfuzz.dart b/runtime/tools/dartfuzz/dartfuzz.dart
index cc97ad8..8a02ff3 100644
--- a/runtime/tools/dartfuzz/dartfuzz.dart
+++ b/runtime/tools/dartfuzz/dartfuzz.dart
@@ -14,7 +14,7 @@
 // Version of DartFuzz. Increase this each time changes are made
 // to preserve the property that a given version of DartFuzz yields
 // the same fuzzed program for a deterministic random seed.
-const String version = '1.39';
+const String version = '1.42';
 
 // Restriction on statements and expressions.
 const int stmtLength = 2;
@@ -167,45 +167,74 @@
     emitLn(').cast<ffi.NativeFunction<${typeName}>>().asFunction();');
   }
 
+  void emitMethod(
+      String name, int index, List<DartType> method, bool isFfiMethod) {
+    if (isFfiMethod) {
+      emitFfiTypedef("${name}Ffi${index}Type", method);
+      emitLn('${method[0].name} ${name}Ffi$index(', newline: false);
+    } else {
+      emitLn('${method[0].name} $name$index(', newline: false);
+    }
+    emitParDecls(method);
+    if (!isFfiMethod && rand.nextInt(10) == 0) {
+      // Emit a method using "=>" syntax.
+      emit(') => ');
+      emitExpr(0, method[0]);
+      emit(';', newline: true);
+      return;
+    }
+    emit(') {', newline: true);
+    indent += 2;
+    assert(localVars.isEmpty);
+    if (emitStatements(0)) {
+      emitReturn();
+    }
+    assert(localVars.isEmpty);
+    indent -= 2;
+    emitLn('}');
+    if (isFfiMethod) {
+      emitFfiCast("${name}${index}", "${name}Ffi${index}",
+          "${name}Ffi${index}Type", method);
+    }
+    emit('', newline: true);
+  }
+
   void emitMethods(String name, List<List<DartType>> methods,
       [List<bool> ffiStatus]) {
     for (int i = 0; i < methods.length; i++) {
       List<DartType> method = methods[i];
       currentMethod = i;
       final bool isFfiMethod = ffiStatus != null && ffiStatus[i];
-      if (isFfiMethod) {
-        emitFfiTypedef("${name}Ffi${i}Type", method);
-        emitLn('${method[0].name} ${name}Ffi$i(', newline: false);
-      } else {
-        emitLn('${method[0].name} $name$i(', newline: false);
-      }
-      emitParDecls(method);
-      if (!isFfiMethod && rand.nextInt(10) == 0) {
-        // Emit a method using "=>" syntax.
-        emit(') => ');
-        emitExpr(0, method[0]);
-        emit(';', newline: true);
-        currentMethod = null;
-        continue;
-      }
-      emit(') {', newline: true);
-      indent += 2;
-      assert(localVars.isEmpty);
-      if (emitStatements(0)) {
-        emitReturn();
-      }
-      assert(localVars.isEmpty);
-      indent -= 2;
-      emitLn('}');
-      if (isFfiMethod) {
-        emitFfiCast(
-            "${name}${i}", "${name}Ffi${i}", "${name}Ffi${i}Type", method);
-      }
-      emit('', newline: true);
+      emitMethod(name, i, method, isFfiMethod);
       currentMethod = null;
     }
   }
 
+  // Randomly overwrite some methods from the parent classes.
+  void emitVirtualMethods() {
+    final currentClassTmp = currentClass;
+    int parentClass = classParents[currentClass];
+    // Chase randomly up in class hierarchy.
+    while (parentClass >= 0) {
+      for (int j = 0, n = classMethods[parentClass].length; j < n; j++) {
+        if (rand.nextInt(8) == 0) {
+          currentClass = parentClass;
+          currentMethod = j;
+          emitMethod('$methodName${parentClass}_', j,
+              classMethods[parentClass][j], false);
+          currentMethod = null;
+          currentClass = null;
+        }
+      }
+      if (rand.nextInt(2) == 0 || classParents.length > parentClass) {
+        break;
+      } else {
+        parentClass = classParents[parentClass];
+      }
+    }
+    currentClass = currentClassTmp;
+  }
+
   void emitClasses() {
     assert(classFields.length == classMethods.length);
     for (int i = 0; i < classFields.length; i++) {
@@ -231,6 +260,7 @@
       indent += 2;
       emitVarDecls('$fieldName${i}_', classFields[i]);
       currentClass = i;
+      emitVirtualMethods();
       emitMethods('$methodName${i}_', classMethods[i]);
       emitLn('void run() {');
       indent += 2;
@@ -768,12 +798,16 @@
 
   void emitCollectionElement(int depth, DartType tp) {
     int r = depth <= exprDepth ? rand.nextInt(10) : 10;
-    // TODO(ajcbik): renable, https://github.com/dart-lang/sdk/issues/38231
-    switch (r + 3) {
+    switch (r) {
       // Favors elements over control-flow collections.
       case 0:
-        emit('...'); // spread
-        emitCollection(depth + 1, tp);
+        // TODO (ajcbik): Remove restriction once compiler is fixed.
+        if (depth < 2) {
+          emit('...'); // spread
+          emitCollection(depth + 1, tp);
+        } else {
+          emitElement(depth, tp);
+        }
         break;
       case 1:
         emit('if (');
diff --git a/runtime/tools/dartfuzz/dartfuzz_test.dart b/runtime/tools/dartfuzz/dartfuzz_test.dart
index e5cce1d..3dc78e3 100644
--- a/runtime/tools/dartfuzz/dartfuzz_test.dart
+++ b/runtime/tools/dartfuzz/dartfuzz_test.dart
@@ -239,8 +239,10 @@
   }
 
   void printReproductionCommand() {
-    print(
-        [generate, '--gen-bytecode', platform, '-o', dill, fileName].join(" "));
+    if (generate != null) {
+      print([generate, '--gen-bytecode', platform, '-o', dill, fileName]
+          .join(" "));
+    }
     print(cmd.join(" "));
   }
 
@@ -485,7 +487,7 @@
 
   void showReproduce() {
     print("\n-- BEGIN REPRODUCE  --\n");
-    print("dartfuzz.dart --${ffi ? "" : "no-"}ffi --${fp ? "" : "no-"}fp"
+    print("dartfuzz.dart --${ffi ? "" : "no-"}ffi --${fp ? "" : "no-"}fp "
         "--seed ${seed} $fileName");
     print("\n-- RUN 1 --\n");
     runner1.printReproductionCommand();
diff --git a/runtime/vm/benchmark_test.cc b/runtime/vm/benchmark_test.cc
index db49703..a95642a 100644
--- a/runtime/vm/benchmark_test.cc
+++ b/runtime/vm/benchmark_test.cc
@@ -511,13 +511,25 @@
   return reinterpret_cast<uint8_t*>(realloc(ptr, new_size));
 }
 
-// Start an Isolate, load a script and create a full snapshot.
-static void BenchmarkSnapshotSize(Benchmark* benchmark, const char* script) {
+BENCHMARK_SIZE(CoreSnapshotSize) {
+  const char* kScriptChars =
+      "import 'dart:async';\n"
+      "import 'dart:core';\n"
+      "import 'dart:collection';\n"
+      "import 'dart:_internal';\n"
+      "import 'dart:math';\n"
+      "import 'dart:isolate';\n"
+      "import 'dart:mirrors';\n"
+      "import 'dart:typed_data';\n"
+      "\n";
+
+  // Start an Isolate, load a script and create a full snapshot.
+  uint8_t* vm_snapshot_data_buffer;
+  uint8_t* isolate_snapshot_data_buffer;
   // Need to load the script into the dart: core library due to
   // the import of dart:_internal.
-  TestCase::LoadCoreTestScript(script, nullptr);
+  TestCase::LoadCoreTestScript(kScriptChars, NULL);
 
-  Thread* thread = Thread::Current();
   TransitionNativeToVM transition(thread);
   StackZone zone(thread);
   HANDLESCOPE(thread);
@@ -525,63 +537,58 @@
   Api::CheckAndFinalizePendingClasses(thread);
 
   // Write snapshot with object content.
-  uint8_t* vm_snapshot_data_buffer = nullptr;
-  uint8_t* isolate_snapshot_data_buffer = nullptr;
-  uint8_t* vm_snapshot_text_buffer = nullptr;
-  uint8_t* isolate_snapshot_text_buffer = nullptr;
-  BlobImageWriter vm_image_writer(thread, &vm_snapshot_text_buffer,
-                                  &malloc_allocator, 2 * MB /* initial_size */,
-                                  /*shared_objects=*/nullptr,
-                                  /*shared_instructions=*/nullptr,
-                                  /*reused_instructions=*/nullptr);
-  BlobImageWriter isolate_image_writer(thread, &isolate_snapshot_text_buffer,
-                                       &malloc_allocator,
-                                       2 * MB /* initial_size */,
-                                       /*shared_objects=*/nullptr,
-                                       /*shared_instructions=*/nullptr,
-                                       /*reused_instructions=*/nullptr);
   FullSnapshotWriter writer(Snapshot::kFull, &vm_snapshot_data_buffer,
                             &isolate_snapshot_data_buffer, &malloc_allocator,
-                            &vm_image_writer, &isolate_image_writer);
+                            NULL, NULL /* image_writer */);
   writer.WriteFullSnapshot();
   const Snapshot* snapshot =
       Snapshot::SetupFromBuffer(isolate_snapshot_data_buffer);
   ASSERT(snapshot->kind() == Snapshot::kFull);
-  benchmark->set_score(writer.IsolateSnapshotSize() +
-                       isolate_image_writer.data_size());
+  benchmark->set_score(snapshot->length());
 
   free(vm_snapshot_data_buffer);
-  free(vm_snapshot_text_buffer);
   free(isolate_snapshot_data_buffer);
-  free(isolate_snapshot_text_buffer);
-}
-
-BENCHMARK_SIZE(CoreSnapshotSize) {
-  BenchmarkSnapshotSize(benchmark,
-                        "import 'dart:async';\n"
-                        "import 'dart:core';\n"
-                        "import 'dart:collection';\n"
-                        "import 'dart:_internal';\n"
-                        "import 'dart:math';\n"
-                        "import 'dart:isolate';\n"
-                        "import 'dart:mirrors';\n"
-                        "import 'dart:typed_data';\n"
-                        "\n");
 }
 
 BENCHMARK_SIZE(StandaloneSnapshotSize) {
-  BenchmarkSnapshotSize(benchmark,
-                        "import 'dart:async';\n"
-                        "import 'dart:core';\n"
-                        "import 'dart:collection';\n"
-                        "import 'dart:convert';\n"
-                        "import 'dart:math';\n"
-                        "import 'dart:isolate';\n"
-                        "import 'dart:mirrors';\n"
-                        "import 'dart:typed_data';\n"
-                        "import 'dart:io';\n"
-                        "import 'dart:cli';\n"
-                        "\n");
+  const char* kScriptChars =
+      "import 'dart:async';\n"
+      "import 'dart:core';\n"
+      "import 'dart:collection';\n"
+      "import 'dart:convert';\n"
+      "import 'dart:math';\n"
+      "import 'dart:isolate';\n"
+      "import 'dart:mirrors';\n"
+      "import 'dart:typed_data';\n"
+      "import 'dart:io';\n"
+      "import 'dart:cli';\n"
+      "\n";
+
+  // Start an Isolate, load a script and create a full snapshot.
+  uint8_t* vm_snapshot_data_buffer;
+  uint8_t* isolate_snapshot_data_buffer;
+  // Need to load the script into the dart: core library due to
+  // the import of dart:_internal.
+  TestCase::LoadCoreTestScript(kScriptChars, NULL);
+
+  TransitionNativeToVM transition(thread);
+  StackZone zone(thread);
+  HANDLESCOPE(thread);
+
+  Api::CheckAndFinalizePendingClasses(thread);
+
+  // Write snapshot with object content.
+  FullSnapshotWriter writer(Snapshot::kFull, &vm_snapshot_data_buffer,
+                            &isolate_snapshot_data_buffer, &malloc_allocator,
+                            NULL, NULL /* image_writer */);
+  writer.WriteFullSnapshot();
+  const Snapshot* snapshot =
+      Snapshot::SetupFromBuffer(isolate_snapshot_data_buffer);
+  ASSERT(snapshot->kind() == Snapshot::kFull);
+  benchmark->set_score(snapshot->length());
+
+  free(vm_snapshot_data_buffer);
+  free(isolate_snapshot_data_buffer);
 }
 
 BENCHMARK(CreateMirrorSystem) {
diff --git a/runtime/vm/class_table.cc b/runtime/vm/class_table.cc
index 7a7f898..a9d7943 100644
--- a/runtime/vm/class_table.cc
+++ b/runtime/vm/class_table.cc
@@ -16,58 +16,99 @@
 
 DEFINE_FLAG(bool, print_class_table, false, "Print initial class table.");
 
-ClassTable::ClassTable()
+SharedClassTable::SharedClassTable()
     : top_(kNumPredefinedCids),
       capacity_(0),
       table_(NULL),
-      old_tables_(new MallocGrowableArray<ClassAndSize*>()) {
-  NOT_IN_PRODUCT(class_heap_stats_table_ = NULL);
+      old_tables_(new MallocGrowableArray<intptr_t*>()) {
   if (Dart::vm_isolate() == NULL) {
-    capacity_ = initial_capacity_;
-    table_ = reinterpret_cast<ClassAndSize*>(
-        calloc(capacity_, sizeof(ClassAndSize)));  // NOLINT
+    ASSERT(kInitialCapacity >= kNumPredefinedCids);
+    capacity_ = kInitialCapacity;
+    // Note that [calloc] will zero-initialize the memory.
+    table_ = static_cast<intptr_t*>(calloc(capacity_, sizeof(intptr_t)));
   } else {
     // Duplicate the class table from the VM isolate.
-    ClassTable* vm_class_table = Dart::vm_isolate()->class_table();
-    capacity_ = vm_class_table->capacity_;
-    table_ = reinterpret_cast<ClassAndSize*>(
-        calloc(capacity_, sizeof(ClassAndSize)));  // NOLINT
+    auto vm_shared_class_table = Dart::vm_isolate()->shared_class_table();
+    capacity_ = vm_shared_class_table->capacity_;
+    // Note that [calloc] will zero-initialize the memory.
+    table_ = static_cast<intptr_t*>(calloc(capacity_, sizeof(RawClass*)));
+    // The following cids don't have a corresponding class object in Dart code.
+    // We therefore need to initialize them eagerly.
     for (intptr_t i = kObjectCid; i < kInstanceCid; i++) {
-      table_[i] = vm_class_table->PairAt(i);
+      table_[i] = vm_shared_class_table->SizeAt(i);
     }
-    table_[kTypeArgumentsCid] = vm_class_table->PairAt(kTypeArgumentsCid);
-    table_[kFreeListElement] = vm_class_table->PairAt(kFreeListElement);
-    table_[kForwardingCorpse] = vm_class_table->PairAt(kForwardingCorpse);
-    table_[kDynamicCid] = vm_class_table->PairAt(kDynamicCid);
-    table_[kVoidCid] = vm_class_table->PairAt(kVoidCid);
+    table_[kTypeArgumentsCid] =
+        vm_shared_class_table->SizeAt(kTypeArgumentsCid);
+    table_[kFreeListElement] = vm_shared_class_table->SizeAt(kFreeListElement);
+    table_[kForwardingCorpse] =
+        vm_shared_class_table->SizeAt(kForwardingCorpse);
+    table_[kDynamicCid] = vm_shared_class_table->SizeAt(kDynamicCid);
+    table_[kVoidCid] = vm_shared_class_table->SizeAt(kVoidCid);
   }
 #ifndef PRODUCT
-  class_heap_stats_table_ = reinterpret_cast<ClassHeapStats*>(
-      calloc(capacity_, sizeof(ClassHeapStats)));  // NOLINT
+  class_heap_stats_table_ = static_cast<ClassHeapStats*>(
+      malloc(capacity_ * sizeof(ClassHeapStats)));  // NOLINT
   for (intptr_t i = 0; i < capacity_; i++) {
     class_heap_stats_table_[i].Initialize();
   }
 #endif  // !PRODUCT
 }
-
-ClassTable::ClassTable(ClassTable* original)
-    : top_(original->top_),
-      capacity_(original->top_),
-      table_(original->table_),
-      old_tables_(NULL) {
-  NOT_IN_PRODUCT(class_heap_stats_table_ = NULL);
-}
-
-ClassTable::~ClassTable() {
+SharedClassTable::~SharedClassTable() {
   if (old_tables_ != NULL) {
     FreeOldTables();
     delete old_tables_;
     free(table_);
-    NOT_IN_PRODUCT(free(class_heap_stats_table_));
-  } else {
-    // This instance was a shallow copy. It doesn't own any memory.
-    NOT_IN_PRODUCT(ASSERT(class_heap_stats_table_ == NULL));
   }
+  NOT_IN_PRODUCT(free(class_heap_stats_table_));
+}
+
+ClassTable::ClassTable(SharedClassTable* shared_class_table)
+    : top_(kNumPredefinedCids),
+      capacity_(0),
+      table_(NULL),
+      old_tables_(new MallocGrowableArray<ClassAndSize*>()),
+      old_class_tables_(new MallocGrowableArray<RawClass**>()),
+      shared_class_table_(shared_class_table) {
+  if (Dart::vm_isolate() == NULL) {
+    ASSERT(kInitialCapacity >= kNumPredefinedCids);
+    capacity_ = kInitialCapacity;
+    // Note that [calloc] will zero-initialize the memory.
+    table_ = static_cast<RawClass**>(calloc(capacity_, sizeof(RawClass*)));
+  } else {
+    // Duplicate the class table from the VM isolate.
+    ClassTable* vm_class_table = Dart::vm_isolate()->class_table();
+    capacity_ = vm_class_table->capacity_;
+    // Note that [calloc] will zero-initialize the memory.
+    table_ = static_cast<RawClass**>(calloc(capacity_, sizeof(RawClass*)));
+    // The following cids don't have a corresponding class object in Dart code.
+    // We therefore need to initialize them eagerly.
+    for (intptr_t i = kObjectCid; i < kInstanceCid; i++) {
+      table_[i] = vm_class_table->At(i);
+    }
+    table_[kTypeArgumentsCid] = vm_class_table->At(kTypeArgumentsCid);
+    table_[kFreeListElement] = vm_class_table->At(kFreeListElement);
+    table_[kForwardingCorpse] = vm_class_table->At(kForwardingCorpse);
+    table_[kDynamicCid] = vm_class_table->At(kDynamicCid);
+    table_[kVoidCid] = vm_class_table->At(kVoidCid);
+  }
+}
+
+ClassTable::ClassTable(ClassTable* original,
+                       SharedClassTable* shared_class_table)
+    : top_(original->top_),
+      capacity_(original->top_),
+      table_(original->table_),
+      old_tables_(nullptr),
+      old_class_tables_(nullptr),
+      shared_class_table_(shared_class_table) {}
+
+ClassTable::~ClassTable() {
+  if (old_tables_ != nullptr || old_class_tables_ != nullptr) {
+    FreeOldTables();
+    delete old_tables_;
+    delete old_class_tables_;
+  }
+  free(table_);
 }
 
 void ClassTable::AddOldTable(ClassAndSize* old_table) {
@@ -79,17 +120,32 @@
   while (old_tables_->length() > 0) {
     free(old_tables_->RemoveLast());
   }
+  while (old_class_tables_->length() > 0) {
+    free(old_class_tables_->RemoveLast());
+  }
+}
+
+void SharedClassTable::FreeOldTables() {
+  while (old_tables_->length() > 0) {
+    free(old_tables_->RemoveLast());
+  }
 }
 
 void ClassTable::Register(const Class& cls) {
   ASSERT(Thread::Current()->IsMutatorThread());
-  intptr_t index = cls.id();
+
+  const intptr_t index = cls.id();
+
+  // During the transition period we would like [SharedClassTable] to operate in
+  // parallel to [ClassTable].
+  const intptr_t expected_cid =
+      shared_class_table_->Register(index, Class::instance_size(cls.raw()));
+
   if (index != kIllegalCid) {
-    ASSERT(index > 0);
-    ASSERT(index < kNumPredefinedCids);
-    ASSERT(table_[index].class_ == NULL);
-    ASSERT(index < capacity_);
-    table_[index] = ClassAndSize(cls.raw(), Class::instance_size(cls.raw()));
+    ASSERT(index > 0 && index < kNumPredefinedCids && index < top_);
+    ASSERT(table_[index] == nullptr);
+    table_[index] = cls.raw();
+
     // Add the vtable for this predefined class into the static vtable registry
     // if it has not been setup yet.
     cpp_vtable cls_vtable = cls.handle_vtable();
@@ -100,95 +156,141 @@
     }
   } else {
     if (top_ == capacity_) {
-      // Grow the capacity of the class table.
-      // TODO(koda): Add ClassTable::Grow to share code.
-
-#ifndef PRODUCT
-      // Wait for any marking tasks to complete. Allocation stats in the
-      // marker rely on the class table size not changing.
-      Thread* thread = Thread::Current();
-      thread->heap()->WaitForMarkerTasks(thread);
-#endif
-
-      intptr_t new_capacity = capacity_ + capacity_increment_;
-      ClassAndSize* new_table = reinterpret_cast<ClassAndSize*>(
-          malloc(new_capacity * sizeof(ClassAndSize)));  // NOLINT
-      memmove(new_table, table_, capacity_ * sizeof(ClassAndSize));
-#ifndef PRODUCT
-      ClassHeapStats* new_stats_table = reinterpret_cast<ClassHeapStats*>(
-          realloc(class_heap_stats_table_,
-                  new_capacity * sizeof(ClassHeapStats)));  // NOLINT
-#endif
-      for (intptr_t i = capacity_; i < new_capacity; i++) {
-        new_table[i] = ClassAndSize(NULL, 0);
-        NOT_IN_PRODUCT(new_stats_table[i].Initialize());
-      }
-      capacity_ = new_capacity;
-      old_tables_->Add(table_);
-      table_ = new_table;  // TODO(koda): This should use atomics.
-      NOT_IN_PRODUCT(class_heap_stats_table_ = new_stats_table);
+      const intptr_t new_capacity = capacity_ + kCapacityIncrement;
+      Grow(new_capacity);
     }
     ASSERT(top_ < capacity_);
-    if (!Class::is_valid_id(top_)) {
-      FATAL1("Fatal error in ClassTable::Register: invalid index %" Pd "\n",
-             top_);
-    }
     cls.set_id(top_);
-    table_[top_] = ClassAndSize(cls.raw());
+    table_[top_] = cls.raw();
     top_++;  // Increment next index.
   }
+  ASSERT(expected_cid == cls.id());
+}
+
+intptr_t SharedClassTable::Register(intptr_t index, intptr_t size) {
+  if (!Class::is_valid_id(top_)) {
+    FATAL1("Fatal error in SharedClassTable::Register: invalid index %" Pd "\n",
+           top_);
+  }
+
+  ASSERT(Thread::Current()->IsMutatorThread());
+  if (index != kIllegalCid) {
+    // We are registring the size of a predefined class.
+    ASSERT(index > 0 && index < kNumPredefinedCids);
+    SetSizeAt(index, size);
+    return index;
+  } else {
+    if (top_ == capacity_) {
+      const intptr_t new_capacity = capacity_ + kCapacityIncrement;
+      Grow(new_capacity);
+    }
+    ASSERT(top_ < capacity_);
+    table_[top_] = size;
+    return top_++;  // Increment next index.
+  }
 }
 
 void ClassTable::AllocateIndex(intptr_t index) {
+  // This is called by a snapshot reader.
+  shared_class_table_->AllocateIndex(index);
+  ASSERT(Class::is_valid_id(index));
+
   if (index >= capacity_) {
-    // Grow the capacity of the class table.
-    // TODO(koda): Add ClassTable::Grow to share code.
-
-#ifndef PRODUCT
-    // Wait for any marking tasks to complete. Allocation stats in the
-    // marker rely on the class table size not changing.
-    Thread* thread = Thread::Current();
-    thread->heap()->WaitForMarkerTasks(thread);
-#endif
-
-    intptr_t new_capacity = index + capacity_increment_;
-    if (!Class::is_valid_id(index) || new_capacity < capacity_) {
-      FATAL1("Fatal error in ClassTable::Register: invalid index %" Pd "\n",
-             index);
-    }
-    ClassAndSize* new_table = reinterpret_cast<ClassAndSize*>(
-        malloc(new_capacity * sizeof(ClassAndSize)));  // NOLINT
-    memmove(new_table, table_, capacity_ * sizeof(ClassAndSize));
-#ifndef PRODUCT
-    ClassHeapStats* new_stats_table = reinterpret_cast<ClassHeapStats*>(
-        realloc(class_heap_stats_table_,
-                new_capacity * sizeof(ClassHeapStats)));  // NOLINT
-#endif
-    for (intptr_t i = capacity_; i < new_capacity; i++) {
-      new_table[i] = ClassAndSize(NULL);
-      NOT_IN_PRODUCT(new_stats_table[i].Initialize());
-    }
-    capacity_ = new_capacity;
-    old_tables_->Add(table_);
-    table_ = new_table;  // TODO(koda): This should use atomics.
-    NOT_IN_PRODUCT(class_heap_stats_table_ = new_stats_table);
-    ASSERT(capacity_increment_ >= 1);
+    const intptr_t new_capacity = index + kCapacityIncrement;
+    Grow(new_capacity);
   }
 
-  ASSERT(table_[index].class_ == NULL);
+  ASSERT(table_[index] == nullptr);
+  if (index >= top_) {
+    top_ = index + 1;
+  }
+
+  ASSERT(top_ == shared_class_table_->top_);
+  ASSERT(capacity_ == shared_class_table_->capacity_);
+}
+
+void ClassTable::Grow(intptr_t new_capacity) {
+  ASSERT(new_capacity > capacity_);
+
+  auto new_table = static_cast<RawClass**>(
+      malloc(new_capacity * sizeof(RawClass*)));  // NOLINT
+  memmove(new_table, table_, top_ * sizeof(RawClass*));
+  memset(new_table + top_, 0, (new_capacity - top_) * sizeof(RawClass*));
+  capacity_ = new_capacity;
+  old_class_tables_->Add(table_);
+  table_ = new_table;  // TODO(koda): This should use atomics.
+}
+
+void SharedClassTable::AllocateIndex(intptr_t index) {
+  // This is called by a snapshot reader.
+  ASSERT(Class::is_valid_id(index));
+
+  if (index >= capacity_) {
+    const intptr_t new_capacity = index + kCapacityIncrement;
+    Grow(new_capacity);
+  }
+
+  ASSERT(table_[index] == 0);
   if (index >= top_) {
     top_ = index + 1;
   }
 }
 
+void SharedClassTable::Grow(intptr_t new_capacity) {
+  ASSERT(new_capacity >= capacity_);
+
+#ifndef PRODUCT
+  // Wait for any marking tasks to complete. Allocation stats in the
+  // marker rely on the class table size not changing.
+  Thread* thread = Thread::Current();
+  thread->heap()->WaitForMarkerTasks(thread);
+#endif
+
+  intptr_t* new_table = static_cast<intptr_t*>(
+      malloc(new_capacity * sizeof(intptr_t)));  // NOLINT
+  memmove(new_table, table_, top_ * sizeof(intptr_t));
+  memset(new_table + top_, 0, (new_capacity - top_) * sizeof(intptr_t));
+#ifndef PRODUCT
+  auto new_stats_table = static_cast<ClassHeapStats*>(
+      realloc(class_heap_stats_table_,
+              new_capacity * sizeof(ClassHeapStats)));  // NOLINT
+#endif
+  for (intptr_t i = capacity_; i < new_capacity; i++) {
+    new_table[i] = 0;
+    NOT_IN_PRODUCT(new_stats_table[i].Initialize());
+  }
+  capacity_ = new_capacity;
+  old_tables_->Add(table_);
+  table_ = new_table;  // TODO(koda): This should use atomics.
+  NOT_IN_PRODUCT(class_heap_stats_table_ = new_stats_table);
+}
+
 void ClassTable::Unregister(intptr_t index) {
-  table_[index] = ClassAndSize(NULL);
+  shared_class_table_->Unregister(index);
+  table_[index] = nullptr;
+}
+
+void SharedClassTable::Unregister(intptr_t index) {
+  table_[index] = 0;
 }
 
 void ClassTable::Remap(intptr_t* old_to_new_cid) {
   ASSERT(Thread::Current()->IsAtSafepoint());
-  intptr_t num_cids = NumCids();
-  ClassAndSize* cls_by_old_cid = new ClassAndSize[num_cids];
+  shared_class_table_->Remap(old_to_new_cid);
+
+  const intptr_t num_cids = NumCids();
+  auto cls_by_old_cid = new RawClass*[num_cids];
+  memmove(cls_by_old_cid, table_, sizeof(RawClass*) * num_cids);
+  for (intptr_t i = 0; i < num_cids; i++) {
+    table_[old_to_new_cid[i]] = cls_by_old_cid[i];
+  }
+  delete[] cls_by_old_cid;
+}
+
+void SharedClassTable::Remap(intptr_t* old_to_new_cid) {
+  ASSERT(Thread::Current()->IsAtSafepoint());
+  const intptr_t num_cids = NumCids();
+  intptr_t* cls_by_old_cid = new intptr_t[num_cids];
   for (intptr_t i = 0; i < num_cids; i++) {
     cls_by_old_cid[i] = table_[i];
   }
@@ -202,7 +304,7 @@
   ASSERT(visitor != NULL);
   visitor->set_gc_root_type("class table");
   for (intptr_t i = 0; i < top_; i++) {
-    visitor->VisitPointer(reinterpret_cast<RawObject**>(&(table_[i].class_)));
+    visitor->VisitPointer(reinterpret_cast<RawObject**>(&(table_[i])));
   }
   visitor->clear_gc_root_type();
 }
@@ -249,17 +351,11 @@
 }
 
 void ClassTable::SetAt(intptr_t index, RawClass* raw_cls) {
+  // This is called by snapshot reader and class finalizer.
   ASSERT(index < capacity_);
-  if (raw_cls == NULL) {
-    table_[index] = ClassAndSize(raw_cls, 0);
-  } else {
-    // Ensure we never change size for a given cid from one non-zero size to
-    // another non-zero size.
-    const intptr_t old_size = table_[index].size_;
-    const intptr_t new_size = Class::instance_size(raw_cls);
-    ASSERT(old_size == 0 || old_size == new_size);
-    table_[index] = ClassAndSize(raw_cls, new_size);
-  }
+  const intptr_t size = raw_cls == nullptr ? 0 : Class::instance_size(raw_cls);
+  shared_class_table_->SetSizeAt(index, size);
+  table_[index] = raw_cls;
 }
 
 ClassAndSize::ClassAndSize(RawClass* clazz) : class_(clazz) {
@@ -437,32 +533,32 @@
   obj->AddProperty64("bytesCurrent", bytes_current);
 }
 
-void ClassTable::UpdateAllocatedOldGC(intptr_t cid, intptr_t size) {
+void SharedClassTable::UpdateAllocatedOldGC(intptr_t cid, intptr_t size) {
   ClassHeapStats* stats = PreliminaryStatsAt(cid);
   ASSERT(stats != NULL);
   ASSERT(size != 0);
   stats->recent.AddOldGC(size);
 }
 
-void ClassTable::UpdateAllocatedExternalNew(intptr_t cid, intptr_t size) {
+void SharedClassTable::UpdateAllocatedExternalNew(intptr_t cid, intptr_t size) {
   ClassHeapStats* stats = PreliminaryStatsAt(cid);
   ASSERT(stats != NULL);
   stats->recent.AddNewExternal(size);
 }
 
-void ClassTable::UpdateAllocatedExternalOld(intptr_t cid, intptr_t size) {
+void SharedClassTable::UpdateAllocatedExternalOld(intptr_t cid, intptr_t size) {
   ClassHeapStats* stats = PreliminaryStatsAt(cid);
   ASSERT(stats != NULL);
   stats->recent.AddOldExternal(size);
 }
 
-bool ClassTable::ShouldUpdateSizeForClassId(intptr_t cid) {
+bool SharedClassTable::ShouldUpdateSizeForClassId(intptr_t cid) {
   return !RawObject::IsVariableSizeClassId(cid);
 }
 
 ClassHeapStats* ClassTable::StatsWithUpdatedSize(intptr_t cid) {
-  if (!HasValidClassAt(cid) || (cid == kFreeListElement) ||
-      (cid == kForwardingCorpse) || (cid == kSmiCid)) {
+  if (!HasValidClassAt(cid) || cid == kFreeListElement ||
+      cid == kForwardingCorpse || cid == kSmiCid) {
     return NULL;
   }
   Class& cls = Class::Handle(At(cid));
@@ -470,48 +566,53 @@
     // Not finalized.
     return NULL;
   }
+  return shared_class_table_->StatsWithUpdatedSize(cid, cls.instance_size());
+}
+
+ClassHeapStats* SharedClassTable::StatsWithUpdatedSize(intptr_t cid,
+                                                       intptr_t size) {
   ClassHeapStats* stats = PreliminaryStatsAt(cid);
   if (ShouldUpdateSizeForClassId(cid)) {
-    stats->UpdateSize(cls.instance_size());
+    stats->UpdateSize(size);
   }
   stats->Verify();
   return stats;
 }
 
-void ClassTable::ResetCountersOld() {
+void SharedClassTable::ResetCountersOld() {
   for (intptr_t i = 0; i < top_; i++) {
     class_heap_stats_table_[i].ResetAtOldGC();
   }
 }
 
-void ClassTable::ResetCountersNew() {
+void SharedClassTable::ResetCountersNew() {
   for (intptr_t i = 0; i < top_; i++) {
     class_heap_stats_table_[i].ResetAtNewGC();
   }
 }
 
-void ClassTable::UpdatePromoted() {
+void SharedClassTable::UpdatePromoted() {
   for (intptr_t i = 0; i < top_; i++) {
     class_heap_stats_table_[i].UpdatePromotedAfterNewGC();
   }
 }
 
-intptr_t ClassTable::ClassOffsetFor(intptr_t cid) {
+intptr_t SharedClassTable::ClassOffsetFor(intptr_t cid) {
   return cid * sizeof(ClassHeapStats);  // NOLINT
 }
 
-intptr_t ClassTable::NewSpaceCounterOffsetFor(intptr_t cid) {
+intptr_t SharedClassTable::NewSpaceCounterOffsetFor(intptr_t cid) {
   const intptr_t class_offset = ClassOffsetFor(cid);
   const intptr_t count_field_offset =
       ClassHeapStats::allocated_since_gc_new_space_offset();
   return class_offset + count_field_offset;
 }
 
-intptr_t ClassTable::StateOffsetFor(intptr_t cid) {
+intptr_t SharedClassTable::StateOffsetFor(intptr_t cid) {
   return ClassOffsetFor(cid) + ClassHeapStats::state_offset();
 }
 
-intptr_t ClassTable::NewSpaceSizeOffsetFor(intptr_t cid) {
+intptr_t SharedClassTable::NewSpaceSizeOffsetFor(intptr_t cid) {
   const uword class_offset = ClassOffsetFor(cid);
   const uword size_field_offset =
       ClassHeapStats::allocated_size_since_gc_new_space_offset();
@@ -563,16 +664,21 @@
   }
 }
 
-void ClassTable::ResetAllocationAccumulators() {
+void SharedClassTable::ResetAllocationAccumulators() {
   for (intptr_t i = 1; i < top_; i++) {
-    ClassHeapStats* stats = StatsWithUpdatedSize(i);
-    if (stats != NULL) {
-      stats->ResetAccumulator();
+    if (HasValidClassAt(i)) {
+      const intptr_t size = table_[i];
+      ClassHeapStats* stats = StatsWithUpdatedSize(i, size);
+      if (stats != NULL) {
+        stats->ResetAccumulator();
+      }
     }
   }
 }
 
-void ClassTable::UpdateLiveOld(intptr_t cid, intptr_t size, intptr_t count) {
+void SharedClassTable::UpdateLiveOld(intptr_t cid,
+                                     intptr_t size,
+                                     intptr_t count) {
   ClassHeapStats* stats = PreliminaryStatsAt(cid);
   ASSERT(stats != NULL);
   ASSERT(size >= 0);
@@ -580,28 +686,28 @@
   stats->post_gc.AddOld(size, count);
 }
 
-void ClassTable::UpdateLiveNew(intptr_t cid, intptr_t size) {
+void SharedClassTable::UpdateLiveNew(intptr_t cid, intptr_t size) {
   ClassHeapStats* stats = PreliminaryStatsAt(cid);
   ASSERT(stats != NULL);
   ASSERT(size >= 0);
   stats->post_gc.AddNew(size);
 }
 
-void ClassTable::UpdateLiveNewGC(intptr_t cid, intptr_t size) {
+void SharedClassTable::UpdateLiveNewGC(intptr_t cid, intptr_t size) {
   ClassHeapStats* stats = PreliminaryStatsAt(cid);
   ASSERT(stats != NULL);
   ASSERT(size >= 0);
   stats->post_gc.AddNewGC(size);
 }
 
-void ClassTable::UpdateLiveOldExternal(intptr_t cid, intptr_t size) {
+void SharedClassTable::UpdateLiveOldExternal(intptr_t cid, intptr_t size) {
   ClassHeapStats* stats = PreliminaryStatsAt(cid);
   ASSERT(stats != NULL);
   ASSERT(size >= 0);
   stats->post_gc.AddOldExternal(size);
 }
 
-void ClassTable::UpdateLiveNewExternal(intptr_t cid, intptr_t size) {
+void SharedClassTable::UpdateLiveNewExternal(intptr_t cid, intptr_t size) {
   ClassHeapStats* stats = PreliminaryStatsAt(cid);
   ASSERT(stats != NULL);
   ASSERT(size >= 0);
diff --git a/runtime/vm/class_table.h b/runtime/vm/class_table.h
index 3de2d46..19b13ce 100644
--- a/runtime/vm/class_table.h
+++ b/runtime/vm/class_table.h
@@ -7,7 +7,9 @@
 
 #include "platform/assert.h"
 #include "platform/atomic.h"
+
 #include "vm/bitfield.h"
+#include "vm/class_id.h"
 #include "vm/globals.h"
 
 namespace dart {
@@ -15,6 +17,8 @@
 class Class;
 class ClassStats;
 class ClassTable;
+class Isolate;
+class IsolateGroup;
 class JSONArray;
 class JSONObject;
 class JSONStream;
@@ -185,21 +189,180 @@
 };
 #endif  // !PRODUCT
 
+// Registry of all known classes and their sizes.
+//
+// The GC will only need the information in this shared class table to scan
+// object pointers.
+class SharedClassTable {
+ public:
+  SharedClassTable();
+  ~SharedClassTable();
+
+  // Thread-safe.
+  intptr_t SizeAt(intptr_t index) const {
+    ASSERT(IsValidIndex(index));
+    return table_[index];
+  }
+
+  bool HasValidClassAt(intptr_t index) const {
+    ASSERT(IsValidIndex(index));
+    ASSERT(table_[index] >= 0);
+    return table_[index] != 0;
+  }
+
+  void SetSizeAt(intptr_t index, intptr_t size) {
+    ASSERT(IsValidIndex(index));
+    // Ensure we never change size for a given cid from one non-zero size to
+    // another non-zero size.
+    RELEASE_ASSERT(table_[index] == 0 || table_[index] == size);
+    table_[index] = size;
+  }
+
+  bool IsValidIndex(intptr_t index) const { return index > 0 && index < top_; }
+
+  intptr_t NumCids() const { return top_; }
+  intptr_t Capacity() const { return capacity_; }
+
+  // Used to drop recently added classes.
+  void SetNumCids(intptr_t num_cids) {
+    ASSERT(num_cids <= top_);
+    top_ = num_cids;
+  }
+
+  // Called whenever a old GC occurs.
+  void ResetCountersOld();
+  // Called whenever a new GC occurs.
+  void ResetCountersNew();
+  // Called immediately after a new GC.
+  void UpdatePromoted();
+
+#if !defined(PRODUCT)
+  // Called whenever a class is allocated in the runtime.
+  void UpdateAllocatedNew(intptr_t cid, intptr_t size) {
+    ClassHeapStats* stats = PreliminaryStatsAt(cid);
+    ASSERT(stats != NULL);
+    ASSERT(size != 0);
+    stats->recent.AddNew(size);
+  }
+  void UpdateAllocatedOld(intptr_t cid, intptr_t size) {
+    ClassHeapStats* stats = PreliminaryStatsAt(cid);
+    ASSERT(stats != NULL);
+    ASSERT(size != 0);
+    stats->recent.AddOld(size);
+  }
+  void UpdateAllocatedOldGC(intptr_t cid, intptr_t size);
+  void UpdateAllocatedExternalNew(intptr_t cid, intptr_t size);
+  void UpdateAllocatedExternalOld(intptr_t cid, intptr_t size);
+
+  void ResetAllocationAccumulators();
+
+  void SetTraceAllocationFor(intptr_t cid, bool trace) {
+    ClassHeapStats* stats = PreliminaryStatsAt(cid);
+    stats->set_trace_allocation(trace);
+  }
+  bool TraceAllocationFor(intptr_t cid) {
+    ClassHeapStats* stats = PreliminaryStatsAt(cid);
+    return stats->trace_allocation();
+  }
+
+  ClassHeapStats* StatsWithUpdatedSize(intptr_t cid, intptr_t size);
+#endif  // !defined(PRODUCT)
+
+  // Returns the newly allocated cid.
+  //
+  // [index] is kIllegalCid or a predefined cid.
+  intptr_t Register(intptr_t index, intptr_t size);
+  void AllocateIndex(intptr_t index);
+  void Unregister(intptr_t index);
+
+  void Remap(intptr_t* old_to_new_cids);
+
+  void FreeOldTables();
+
+  // Used by the generated code.
+#ifndef PRODUCT
+  static intptr_t class_heap_stats_table_offset() {
+    return OFFSET_OF(SharedClassTable, class_heap_stats_table_);
+  }
+#endif
+
+  // Used by the generated code.
+  static intptr_t ClassOffsetFor(intptr_t cid);
+
+  // Used by the generated code.
+  static intptr_t NewSpaceCounterOffsetFor(intptr_t cid);
+
+  // Used by the generated code.
+  static intptr_t StateOffsetFor(intptr_t cid);
+
+  // Used by the generated code.
+  static intptr_t NewSpaceSizeOffsetFor(intptr_t cid);
+
+  static const int kInitialCapacity = 512;
+  static const int kCapacityIncrement = 256;
+
+ private:
+  friend class ClassTable;
+  friend class GCMarker;
+  friend class MarkingWeakVisitor;
+  friend class Scavenger;
+  friend class ScavengerWeakVisitor;
+  friend class ClassHeapStatsTestHelper;
+  friend class HeapTestsHelper;
+
+  static bool ShouldUpdateSizeForClassId(intptr_t cid);
+
+#ifndef PRODUCT
+  // May not have updated size for variable size classes.
+  ClassHeapStats* PreliminaryStatsAt(intptr_t cid) {
+    ASSERT(cid > 0);
+    ASSERT(cid < top_);
+    return &class_heap_stats_table_[cid];
+  }
+  void UpdateLiveOld(intptr_t cid, intptr_t size, intptr_t count = 1);
+  void UpdateLiveNew(intptr_t cid, intptr_t size);
+  void UpdateLiveNewGC(intptr_t cid, intptr_t size);
+  void UpdateLiveOldExternal(intptr_t cid, intptr_t size);
+  void UpdateLiveNewExternal(intptr_t cid, intptr_t size);
+
+  ClassHeapStats* class_heap_stats_table_ = nullptr;
+#endif  // !PRODUCT
+
+  void Grow(intptr_t new_capacity);
+
+  intptr_t top_;
+  intptr_t capacity_;
+
+  // Copy-on-write is used for table_, with old copies stored in old_tables_.
+  intptr_t* table_;  // Maps the cid to the instance size.
+  MallocGrowableArray<intptr_t*>* old_tables_;
+
+  DISALLOW_COPY_AND_ASSIGN(SharedClassTable);
+};
+
 class ClassTable {
  public:
-  ClassTable();
+  explicit ClassTable(SharedClassTable* shared_class_table_);
+
   // Creates a shallow copy of the original class table for some read-only
   // access, without support for stats data.
-  explicit ClassTable(ClassTable* original);
+  ClassTable(ClassTable* original, SharedClassTable* shared_class_table);
   ~ClassTable();
 
+  SharedClassTable* shared_class_table() const { return shared_class_table_; }
+
   void CopyBeforeHotReload(ClassAndSize** copy, intptr_t* copy_num_cids) {
     // The [IsolateReloadContext] will need to maintain a copy of the old class
     // table until instances have been morphed.
-    const intptr_t bytes = sizeof(ClassAndSize) * NumCids();
-    *copy_num_cids = NumCids();
-    *copy = static_cast<ClassAndSize*>(malloc(bytes));
-    memmove(*copy, table_, bytes);
+    const intptr_t num_cids = NumCids();
+    const intptr_t bytes = sizeof(ClassAndSize) * num_cids;
+    auto class_and_size = static_cast<ClassAndSize*>(malloc(bytes));
+    for (intptr_t i = 0; i < num_cids; ++i) {
+      class_and_size[i] =
+          ClassAndSize(table_[i], shared_class_table_->table_[i]);
+    }
+    *copy_num_cids = num_cids;
+    *copy = class_and_size;
   }
 
   void ResetBeforeHotReload() {
@@ -211,7 +374,7 @@
     // to find the super class (e.g. `cls.SuperClass` will cause us to come
     // here).
     for (intptr_t i = 0; i < top_; ++i) {
-      table_[i].size_ = 0;
+      shared_class_table_->table_[i] = 0;
     }
   }
 
@@ -222,7 +385,10 @@
     // return, so we restore size information for all classes.
     if (is_rollback) {
       SetNumCids(num_old_cids);
-      memmove(table_, old_table, num_old_cids * sizeof(ClassAndSize));
+      for (intptr_t i = 0; i < num_old_cids; ++i) {
+        shared_class_table_->table_[i] = old_table[i].size_;
+        table_[i] = old_table[i].class_;
+      }
     } else {
       CopySizesFromClassObjects();
     }
@@ -237,43 +403,37 @@
   // Thread-safe.
   RawClass* At(intptr_t index) const {
     ASSERT(IsValidIndex(index));
-    return table_[index].class_;
+    return table_[index];
   }
 
   intptr_t SizeAt(intptr_t index) const {
-    ASSERT(IsValidIndex(index));
-    return table_[index].size_;
-  }
-
-  ClassAndSize PairAt(intptr_t index) const {
-    ASSERT(IsValidIndex(index));
-    return table_[index];
+    return shared_class_table_->SizeAt(index);
   }
 
   void SetAt(intptr_t index, RawClass* raw_cls);
 
   bool IsValidIndex(intptr_t index) const {
-    return (index > 0) && (index < top_);
+    return shared_class_table_->IsValidIndex(index);
   }
 
   bool HasValidClassAt(intptr_t index) const {
     ASSERT(IsValidIndex(index));
-    return table_[index].class_ != NULL;
+    return table_[index] != nullptr;
   }
 
-  intptr_t NumCids() const { return top_; }
-  intptr_t Capacity() const { return capacity_; }
+  intptr_t NumCids() const { return shared_class_table_->NumCids(); }
+  intptr_t Capacity() const { return shared_class_table_->Capacity(); }
 
   // Used to drop recently added classes.
   void SetNumCids(intptr_t num_cids) {
+    shared_class_table_->SetNumCids(num_cids);
+
     ASSERT(num_cids <= top_);
     top_ = num_cids;
   }
 
   void Register(const Class& cls);
-
   void AllocateIndex(intptr_t index);
-
   void Unregister(intptr_t index);
 
   void Remap(intptr_t* old_to_new_cids);
@@ -293,7 +453,9 @@
   static intptr_t table_offset() { return OFFSET_OF(ClassTable, table_); }
 
   // Used by the generated code.
-  static intptr_t ClassOffsetFor(intptr_t cid);
+  static intptr_t shared_class_table_offset() {
+    return OFFSET_OF(ClassTable, shared_class_table_);
+  }
 
 #ifndef PRODUCT
   // Describes layout of heap stats for code generation. See offset_extractor.cc
@@ -304,76 +466,19 @@
   };
 #endif
 
-#if defined(ARCH_IS_32_BIT)
-  static constexpr int kSizeOfClassPairLog2 = 3;
-#else
-  static constexpr int kSizeOfClassPairLog2 = 4;
-#endif
-  static_assert(
-      (1 << kSizeOfClassPairLog2) == sizeof(ClassAndSize),
-      "Mismatch between sizeof(ClassAndSize) and kSizeOfClassPairLog2");
-
 #ifndef PRODUCT
-  // Called whenever a class is allocated in the runtime.
-  void UpdateAllocatedNew(intptr_t cid, intptr_t size) {
-    ClassHeapStats* stats = PreliminaryStatsAt(cid);
-    ASSERT(stats != NULL);
-    ASSERT(size != 0);
-    stats->recent.AddNew(size);
-  }
-  void UpdateAllocatedOld(intptr_t cid, intptr_t size) {
-    ClassHeapStats* stats = PreliminaryStatsAt(cid);
-    ASSERT(stats != NULL);
-    ASSERT(size != 0);
-    stats->recent.AddOld(size);
-  }
-  void UpdateAllocatedOldGC(intptr_t cid, intptr_t size);
-  void UpdateAllocatedExternalNew(intptr_t cid, intptr_t size);
-  void UpdateAllocatedExternalOld(intptr_t cid, intptr_t size);
-
-  // Called whenever a old GC occurs.
-  void ResetCountersOld();
-  // Called whenever a new GC occurs.
-  void ResetCountersNew();
-  // Called immediately after a new GC.
-  void UpdatePromoted();
-
-  // Used by the generated code.
-  static intptr_t class_heap_stats_table_offset() {
-    return OFFSET_OF(ClassTable, class_heap_stats_table_);
-  }
-
-  // Used by the generated code.
-  static intptr_t NewSpaceCounterOffsetFor(intptr_t cid);
-
-  // Used by the generated code.
-  static intptr_t StateOffsetFor(intptr_t cid);
-
-  // Used by the generated code.
-  static intptr_t NewSpaceSizeOffsetFor(intptr_t cid);
 
   ClassHeapStats* StatsWithUpdatedSize(intptr_t cid);
 
   void AllocationProfilePrintJSON(JSONStream* stream, bool internal);
-  void ResetAllocationAccumulators();
 
   void PrintToJSONObject(JSONObject* object);
-
-  void SetTraceAllocationFor(intptr_t cid, bool trace) {
-    ClassHeapStats* stats = PreliminaryStatsAt(cid);
-    stats->set_trace_allocation(trace);
-  }
-  bool TraceAllocationFor(intptr_t cid) {
-    ClassHeapStats* stats = PreliminaryStatsAt(cid);
-    return stats->trace_allocation();
-  }
 #endif  // !PRODUCT
 
   void AddOldTable(ClassAndSize* old_table);
   // Deallocates table copies. Do not call during concurrent access to table.
   void FreeOldTables();
 
-
  private:
   friend class GCMarker;
   friend class MarkingWeakVisitor;
@@ -381,33 +486,19 @@
   friend class ScavengerWeakVisitor;
   friend class ClassHeapStatsTestHelper;
   friend class HeapTestsHelper;
-  static const int initial_capacity_ = 512;
-  static const int capacity_increment_ = 256;
+  static const int kInitialCapacity = SharedClassTable::kInitialCapacity;
+  static const int kCapacityIncrement = SharedClassTable::kCapacityIncrement;
 
-  static bool ShouldUpdateSizeForClassId(intptr_t cid);
+  void Grow(intptr_t index);
 
   intptr_t top_;
   intptr_t capacity_;
 
   // Copy-on-write is used for table_, with old copies stored in old_tables_.
-  ClassAndSize* table_;
+  RawClass** table_;
   MallocGrowableArray<ClassAndSize*>* old_tables_;
-
-#ifndef PRODUCT
-  ClassHeapStats* class_heap_stats_table_;
-
-  // May not have updated size for variable size classes.
-  ClassHeapStats* PreliminaryStatsAt(intptr_t cid) {
-    ASSERT(cid > 0);
-    ASSERT(cid < top_);
-    return &class_heap_stats_table_[cid];
-  }
-  void UpdateLiveOld(intptr_t cid, intptr_t size, intptr_t count = 1);
-  void UpdateLiveNew(intptr_t cid, intptr_t size);
-  void UpdateLiveNewGC(intptr_t cid, intptr_t size);
-  void UpdateLiveOldExternal(intptr_t cid, intptr_t size);
-  void UpdateLiveNewExternal(intptr_t cid, intptr_t size);
-#endif  // !PRODUCT
+  MallocGrowableArray<RawClass**>* old_class_tables_;
+  SharedClassTable* shared_class_table_;
 
   DISALLOW_COPY_AND_ASSIGN(ClassTable);
 };
diff --git a/runtime/vm/clustered_snapshot.cc b/runtime/vm/clustered_snapshot.cc
index 1939554..a5958d6 100644
--- a/runtime/vm/clustered_snapshot.cc
+++ b/runtime/vm/clustered_snapshot.cc
@@ -3305,6 +3305,19 @@
   }
 
   void ReadFill(Deserializer* d) {}
+
+  void PostLoad(const Array& refs, Snapshot::Kind kind, Zone* zone) {
+    const Class& mint_cls =
+        Class::Handle(zone, Isolate::Current()->object_store()->mint_class());
+    mint_cls.set_constants(Object::empty_array());
+    Object& number = Object::Handle(zone);
+    for (intptr_t i = start_index_; i < stop_index_; i++) {
+      number = refs.At(i);
+      if (number.IsMint() && number.IsCanonical()) {
+        mint_cls.InsertCanonicalMint(zone, Mint::Cast(number));
+      }
+    }
+  }
 };
 
 #if !defined(DART_PRECOMPILED_RUNTIME)
@@ -4086,6 +4099,159 @@
 };
 
 #if !defined(DART_PRECOMPILED_RUNTIME)
+class OneByteStringSerializationCluster : public SerializationCluster {
+ public:
+  OneByteStringSerializationCluster() : SerializationCluster("OneByteString") {}
+  ~OneByteStringSerializationCluster() {}
+
+  void Trace(Serializer* s, RawObject* object) {
+    RawOneByteString* str = reinterpret_cast<RawOneByteString*>(object);
+    objects_.Add(str);
+  }
+
+  void WriteAlloc(Serializer* s) {
+    s->WriteCid(kOneByteStringCid);
+    intptr_t count = objects_.length();
+    s->WriteUnsigned(count);
+    for (intptr_t i = 0; i < count; i++) {
+      RawOneByteString* str = objects_[i];
+      s->AssignRef(str);
+      AutoTraceObject(str);
+      intptr_t length = Smi::Value(str->ptr()->length_);
+      s->WriteUnsigned(length);
+    }
+  }
+
+  void WriteFill(Serializer* s) {
+    intptr_t count = objects_.length();
+    for (intptr_t i = 0; i < count; i++) {
+      RawOneByteString* str = objects_[i];
+      AutoTraceObject(str);
+      intptr_t length = Smi::Value(str->ptr()->length_);
+      s->WriteUnsigned(length);
+      s->Write<bool>(str->IsCanonical());
+      intptr_t hash = String::GetCachedHash(str);
+      s->Write<int32_t>(hash);
+      s->WriteBytes(str->ptr()->data(), length);
+    }
+  }
+
+ private:
+  GrowableArray<RawOneByteString*> objects_;
+};
+#endif  // !DART_PRECOMPILED_RUNTIME
+
+class OneByteStringDeserializationCluster : public DeserializationCluster {
+ public:
+  OneByteStringDeserializationCluster() {}
+  ~OneByteStringDeserializationCluster() {}
+
+  void ReadAlloc(Deserializer* d) {
+    start_index_ = d->next_index();
+    PageSpace* old_space = d->heap()->old_space();
+    intptr_t count = d->ReadUnsigned();
+    for (intptr_t i = 0; i < count; i++) {
+      intptr_t length = d->ReadUnsigned();
+      d->AssignRef(AllocateUninitialized(old_space,
+                                         OneByteString::InstanceSize(length)));
+    }
+    stop_index_ = d->next_index();
+  }
+
+  void ReadFill(Deserializer* d) {
+    for (intptr_t id = start_index_; id < stop_index_; id++) {
+      RawOneByteString* str = reinterpret_cast<RawOneByteString*>(d->Ref(id));
+      intptr_t length = d->ReadUnsigned();
+      bool is_canonical = d->Read<bool>();
+      Deserializer::InitializeHeader(str, kOneByteStringCid,
+                                     OneByteString::InstanceSize(length),
+                                     is_canonical);
+      str->ptr()->length_ = Smi::New(length);
+      String::SetCachedHash(str, d->Read<int32_t>());
+      for (intptr_t j = 0; j < length; j++) {
+        str->ptr()->data()[j] = d->Read<uint8_t>();
+      }
+    }
+  }
+};
+
+#if !defined(DART_PRECOMPILED_RUNTIME)
+class TwoByteStringSerializationCluster : public SerializationCluster {
+ public:
+  TwoByteStringSerializationCluster() : SerializationCluster("TwoByteString") {}
+  ~TwoByteStringSerializationCluster() {}
+
+  void Trace(Serializer* s, RawObject* object) {
+    RawTwoByteString* str = reinterpret_cast<RawTwoByteString*>(object);
+    objects_.Add(str);
+  }
+
+  void WriteAlloc(Serializer* s) {
+    s->WriteCid(kTwoByteStringCid);
+    intptr_t count = objects_.length();
+    s->WriteUnsigned(count);
+    for (intptr_t i = 0; i < count; i++) {
+      RawTwoByteString* str = objects_[i];
+      s->AssignRef(str);
+      AutoTraceObject(str);
+      intptr_t length = Smi::Value(str->ptr()->length_);
+      s->WriteUnsigned(length);
+    }
+  }
+
+  void WriteFill(Serializer* s) {
+    intptr_t count = objects_.length();
+    for (intptr_t i = 0; i < count; i++) {
+      RawTwoByteString* str = objects_[i];
+      AutoTraceObject(str);
+      intptr_t length = Smi::Value(str->ptr()->length_);
+      s->WriteUnsigned(length);
+      s->Write<bool>(str->IsCanonical());
+      intptr_t hash = String::GetCachedHash(str);
+      s->Write<int32_t>(hash);
+      s->WriteBytes(reinterpret_cast<uint8_t*>(str->ptr()->data()), length * 2);
+    }
+  }
+
+ private:
+  GrowableArray<RawTwoByteString*> objects_;
+};
+#endif  // !DART_PRECOMPILED_RUNTIME
+
+class TwoByteStringDeserializationCluster : public DeserializationCluster {
+ public:
+  TwoByteStringDeserializationCluster() {}
+  ~TwoByteStringDeserializationCluster() {}
+
+  void ReadAlloc(Deserializer* d) {
+    start_index_ = d->next_index();
+    PageSpace* old_space = d->heap()->old_space();
+    intptr_t count = d->ReadUnsigned();
+    for (intptr_t i = 0; i < count; i++) {
+      intptr_t length = d->ReadUnsigned();
+      d->AssignRef(AllocateUninitialized(old_space,
+                                         TwoByteString::InstanceSize(length)));
+    }
+    stop_index_ = d->next_index();
+  }
+
+  void ReadFill(Deserializer* d) {
+    for (intptr_t id = start_index_; id < stop_index_; id++) {
+      RawTwoByteString* str = reinterpret_cast<RawTwoByteString*>(d->Ref(id));
+      intptr_t length = d->ReadUnsigned();
+      bool is_canonical = d->Read<bool>();
+      Deserializer::InitializeHeader(str, kTwoByteStringCid,
+                                     TwoByteString::InstanceSize(length),
+                                     is_canonical);
+      str->ptr()->length_ = Smi::New(length);
+      String::SetCachedHash(str, d->Read<int32_t>());
+      uint8_t* cdata = reinterpret_cast<uint8_t*>(str->ptr()->data());
+      d->ReadBytes(cdata, length * 2);
+    }
+  }
+};
+
+#if !defined(DART_PRECOMPILED_RUNTIME)
 class FakeSerializationCluster : public SerializationCluster {
  public:
   FakeSerializationCluster(const char* name, intptr_t size)
@@ -4205,10 +4371,16 @@
 
   if (Snapshot::IncludesCode(kind_)) {
     switch (cid) {
+      case kPcDescriptorsCid:
+        return new (Z) RODataSerializationCluster("(RO)PcDescriptors", cid);
       case kCodeSourceMapCid:
         return new (Z) RODataSerializationCluster("(RO)CodeSourceMap", cid);
       case kStackMapCid:
         return new (Z) RODataSerializationCluster("(RO)StackMap", cid);
+      case kOneByteStringCid:
+        return new (Z) RODataSerializationCluster("(RO)OneByteString", cid);
+      case kTwoByteStringCid:
+        return new (Z) RODataSerializationCluster("(RO)TwoByteString", cid);
     }
   }
 
@@ -4247,8 +4419,6 @@
 #endif  // !DART_PRECOMPILED_RUNTIME
     case kObjectPoolCid:
       return new (Z) ObjectPoolSerializationCluster();
-    case kPcDescriptorsCid:
-      return new (Z) RODataSerializationCluster("(RO)PcDescriptors", cid);
     case kExceptionHandlersCid:
       return new (Z) ExceptionHandlersSerializationCluster();
     case kContextCid:
@@ -4298,9 +4468,9 @@
     case kImmutableArrayCid:
       return new (Z) ArraySerializationCluster(kImmutableArrayCid);
     case kOneByteStringCid:
-      return new (Z) RODataSerializationCluster("(RO)OneByteString", cid);
+      return new (Z) OneByteStringSerializationCluster();
     case kTwoByteStringCid:
-      return new (Z) RODataSerializationCluster("(RO)TwoByteString", cid);
+      return new (Z) TwoByteStringSerializationCluster();
     default:
       break;
   }
@@ -4794,15 +4964,17 @@
       zone_(thread->zone()),
       kind_(kind),
       stream_(buffer, size),
-      image_reader_(nullptr),
-      refs_(nullptr),
+      image_reader_(NULL),
+      refs_(NULL),
       next_ref_index_(1),
-      clusters_(nullptr) {
-  ASSERT((instructions_buffer != nullptr) || !Snapshot::IncludesCode(kind));
-  ASSERT(data_buffer != nullptr);
-  image_reader_ =
-      new (zone_) ImageReader(data_buffer, instructions_buffer,
-                              shared_data_buffer, shared_instructions_buffer);
+      clusters_(NULL) {
+  if (Snapshot::IncludesCode(kind)) {
+    ASSERT(instructions_buffer != NULL);
+    ASSERT(data_buffer != NULL);
+    image_reader_ =
+        new (zone_) ImageReader(data_buffer, instructions_buffer,
+                                shared_data_buffer, shared_instructions_buffer);
+  }
   stream_.SetPosition(offset);
 }
 
@@ -4915,14 +5087,25 @@
       return new (Z) ArrayDeserializationCluster(kArrayCid);
     case kImmutableArrayCid:
       return new (Z) ArrayDeserializationCluster(kImmutableArrayCid);
-    case kOneByteStringCid:
-    case kTwoByteStringCid:
-      return new (Z) RODataDeserializationCluster();
+    case kOneByteStringCid: {
+      if (Snapshot::IncludesCode(kind_)) {
+        return new (Z) RODataDeserializationCluster();
+      } else {
+        return new (Z) OneByteStringDeserializationCluster();
+      }
+    }
+    case kTwoByteStringCid: {
+      if (Snapshot::IncludesCode(kind_)) {
+        return new (Z) RODataDeserializationCluster();
+      } else {
+        return new (Z) TwoByteStringDeserializationCluster();
+      }
+    }
     default:
       break;
   }
   FATAL1("No cluster defined for cid %" Pd, cid);
-  return nullptr;
+  return NULL;
 }
 
 RawApiError* Deserializer::VerifyImageAlignment() {
@@ -5309,8 +5492,7 @@
 intptr_t FullSnapshotWriter::WriteVMSnapshot() {
   TIMELINE_DURATION(thread(), Isolate, "WriteVMSnapshot");
 
-  ASSERT(vm_snapshot_data_buffer_ != nullptr);
-  ASSERT(vm_image_writer_ != nullptr);
+  ASSERT(vm_snapshot_data_buffer_ != NULL);
   Serializer serializer(thread(), kind_, vm_snapshot_data_buffer_, alloc_,
                         kInitialSize, vm_image_writer_, /*vm=*/true,
                         profile_writer_);
@@ -5327,12 +5509,14 @@
   serializer.FillHeader(serializer.kind());
   clustered_vm_size_ = serializer.bytes_written();
 
-  vm_image_writer_->SetProfileWriter(profile_writer_);
-  vm_image_writer_->Write(serializer.stream(), true);
-  mapped_data_size_ += vm_image_writer_->data_size();
-  mapped_text_size_ += vm_image_writer_->text_size();
-  vm_image_writer_->ResetOffsets();
-  vm_image_writer_->ClearProfileWriter();
+  if (Snapshot::IncludesCode(kind_)) {
+    vm_image_writer_->SetProfileWriter(profile_writer_);
+    vm_image_writer_->Write(serializer.stream(), true);
+    mapped_data_size_ += vm_image_writer_->data_size();
+    mapped_text_size_ += vm_image_writer_->text_size();
+    vm_image_writer_->ResetOffsets();
+    vm_image_writer_->ClearProfileWriter();
+  }
 
   // The clustered part + the direct mapped data part.
   vm_isolate_snapshot_size_ = serializer.bytes_written();
@@ -5342,13 +5526,11 @@
 void FullSnapshotWriter::WriteIsolateSnapshot(intptr_t num_base_objects) {
   TIMELINE_DURATION(thread(), Isolate, "WriteIsolateSnapshot");
 
-  ASSERT(isolate_snapshot_data_buffer_ != nullptr);
-  ASSERT(isolate_image_writer_ != nullptr);
   Serializer serializer(thread(), kind_, isolate_snapshot_data_buffer_, alloc_,
                         kInitialSize, isolate_image_writer_, /*vm=*/false,
                         profile_writer_);
   ObjectStore* object_store = isolate()->object_store();
-  ASSERT(object_store != nullptr);
+  ASSERT(object_store != NULL);
 
   serializer.ReserveHeader();
   serializer.WriteVersionAndFeatures(false);
@@ -5358,16 +5540,18 @@
   serializer.FillHeader(serializer.kind());
   clustered_isolate_size_ = serializer.bytes_written();
 
-  isolate_image_writer_->SetProfileWriter(profile_writer_);
-  isolate_image_writer_->Write(serializer.stream(), false);
+  if (Snapshot::IncludesCode(kind_)) {
+    isolate_image_writer_->SetProfileWriter(profile_writer_);
+    isolate_image_writer_->Write(serializer.stream(), false);
 #if defined(DART_PRECOMPILER)
-  isolate_image_writer_->DumpStatistics();
+    isolate_image_writer_->DumpStatistics();
 #endif
 
-  mapped_data_size_ += isolate_image_writer_->data_size();
-  mapped_text_size_ += isolate_image_writer_->text_size();
-  isolate_image_writer_->ResetOffsets();
-  isolate_image_writer_->ClearProfileWriter();
+    mapped_data_size_ += isolate_image_writer_->data_size();
+    mapped_text_size_ += isolate_image_writer_->text_size();
+    isolate_image_writer_->ResetOffsets();
+    isolate_image_writer_->ClearProfileWriter();
+  }
 
   // The clustered part + the direct mapped data part.
   isolate_snapshot_size_ = serializer.bytes_written();
@@ -5488,11 +5672,11 @@
     return api_error;
   }
 
-  ASSERT(data_image_ != nullptr);
-  thread_->isolate()->SetupImagePage(data_image_,
-                                     /* is_executable */ false);
   if (Snapshot::IncludesCode(kind_)) {
-    ASSERT(instructions_image_ != nullptr);
+    ASSERT(data_image_ != NULL);
+    thread_->isolate()->SetupImagePage(data_image_,
+                                       /* is_executable */ false);
+    ASSERT(instructions_image_ != NULL);
     thread_->isolate()->SetupImagePage(instructions_image_,
                                        /* is_executable */ true);
   }
@@ -5519,18 +5703,18 @@
     return api_error;
   }
 
-  ASSERT(data_image_ != nullptr);
-  thread_->isolate()->SetupImagePage(data_image_,
-                                     /* is_executable */ false);
   if (Snapshot::IncludesCode(kind_)) {
-    ASSERT(instructions_image_ != nullptr);
+    ASSERT(data_image_ != NULL);
+    thread_->isolate()->SetupImagePage(data_image_,
+                                       /* is_executable */ false);
+    ASSERT(instructions_image_ != NULL);
     thread_->isolate()->SetupImagePage(instructions_image_,
                                        /* is_executable */ true);
-    if (shared_data_image_ != nullptr) {
+    if (shared_data_image_ != NULL) {
       thread_->isolate()->SetupImagePage(shared_data_image_,
                                          /* is_executable */ false);
     }
-    if (shared_instructions_image_ != nullptr) {
+    if (shared_instructions_image_ != NULL) {
       thread_->isolate()->SetupImagePage(shared_instructions_image_,
                                          /* is_executable */ true);
     }
diff --git a/runtime/vm/clustered_snapshot.h b/runtime/vm/clustered_snapshot.h
index f62744a..ad04810 100644
--- a/runtime/vm/clustered_snapshot.h
+++ b/runtime/vm/clustered_snapshot.h
@@ -635,7 +635,6 @@
   ReAlloc alloc_;
   intptr_t vm_isolate_snapshot_size_;
   intptr_t isolate_snapshot_size_;
-  ForwardList* forward_list_;
   ImageWriter* vm_image_writer_;
   ImageWriter* isolate_image_writer_;
 
diff --git a/runtime/vm/compiler/asm_intrinsifier_arm.cc b/runtime/vm/compiler/asm_intrinsifier_arm.cc
index bb2cb37..ae216fa 100644
--- a/runtime/vm/compiler/asm_intrinsifier_arm.cc
+++ b/runtime/vm/compiler/asm_intrinsifier_arm.cc
@@ -1607,7 +1607,7 @@
   __ Ret();
 
   __ Bind(&use_declaration_type);
-  __ LoadClassById(R2, R1);  // Overwrites R1.
+  __ LoadClassById(R2, R1);
   __ ldrh(R3, FieldAddress(R2, target::Class::num_type_arguments_offset()));
   __ CompareImmediate(R3, 0);
   __ b(normal_ir_body, NE);
diff --git a/runtime/vm/compiler/asm_intrinsifier_arm64.cc b/runtime/vm/compiler/asm_intrinsifier_arm64.cc
index 1551dfc..d96d9fc 100644
--- a/runtime/vm/compiler/asm_intrinsifier_arm64.cc
+++ b/runtime/vm/compiler/asm_intrinsifier_arm64.cc
@@ -1668,7 +1668,7 @@
   __ ret();
 
   __ Bind(&use_declaration_type);
-  __ LoadClassById(R2, R1);  // Overwrites R1.
+  __ LoadClassById(R2, R1);
   __ ldr(R3, FieldAddress(R2, target::Class::num_type_arguments_offset()),
          kHalfword);
   __ CompareImmediate(R3, 0);
@@ -1704,7 +1704,7 @@
   // Objects have the same class and neither is a closure.
   // Check if there are no type arguments. In this case we can return true.
   // Otherwise fall through into the runtime to handle comparison.
-  __ LoadClassById(R3, R1);  // Overwrites R1.
+  __ LoadClassById(R3, R1);
   __ ldr(R3, FieldAddress(R3, target::Class::num_type_arguments_offset()),
          kHalfword);
   __ CompareImmediate(R3, 0);
diff --git a/runtime/vm/compiler/assembler/assembler_arm.cc b/runtime/vm/compiler/assembler/assembler_arm.cc
index 0e6e40c..6958b22 100644
--- a/runtime/vm/compiler/assembler/assembler_arm.cc
+++ b/runtime/vm/compiler/assembler/assembler_arm.cc
@@ -1984,12 +1984,13 @@
 
 void Assembler::LoadClassById(Register result, Register class_id) {
   ASSERT(result != class_id);
+
+  const intptr_t table_offset = target::Isolate::class_table_offset() +
+                                target::ClassTable::table_offset();
+
   LoadIsolate(result);
-  const intptr_t offset = target::Isolate::class_table_offset() +
-                          target::ClassTable::table_offset();
-  LoadFromOffset(kWord, result, result, offset);
-  ldr(result,
-      Address(result, class_id, LSL, target::ClassTable::kSizeOfClassPairLog2));
+  LoadFromOffset(kWord, result, result, table_offset);
+  ldr(result, Address(result, class_id, LSL, target::kWordSizeLog2));
 }
 
 void Assembler::CompareClassId(Register object,
@@ -3511,10 +3512,16 @@
   ASSERT(dest != kNoRegister);
   ASSERT(dest != TMP);
   ASSERT(cid > 0);
+
+  const intptr_t shared_table_offset =
+      target::Isolate::class_table_offset() +
+      target::ClassTable::shared_class_table_offset();
+  const intptr_t table_offset =
+      target::SharedClassTable::class_heap_stats_table_offset();
   const intptr_t class_offset = target::ClassTable::ClassOffsetFor(cid);
+
   LoadIsolate(dest);
-  intptr_t table_offset = target::Isolate::class_table_offset() +
-                          target::ClassTable::class_heap_stats_table_offset();
+  ldr(dest, Address(dest, shared_table_offset));
   ldr(dest, Address(dest, table_offset));
   AddImmediate(dest, class_offset);
 }
diff --git a/runtime/vm/compiler/assembler/assembler_arm64.cc b/runtime/vm/compiler/assembler/assembler_arm64.cc
index 6321133..e75fcc9 100644
--- a/runtime/vm/compiler/assembler/assembler_arm64.cc
+++ b/runtime/vm/compiler/assembler/assembler_arm64.cc
@@ -1116,12 +1116,12 @@
 
 void Assembler::LoadClassById(Register result, Register class_id) {
   ASSERT(result != class_id);
+
+  const intptr_t table_offset = target::Isolate::class_table_offset() +
+                                target::ClassTable::table_offset();
+
   LoadIsolate(result);
-  const intptr_t offset = target::Isolate::class_table_offset() +
-                          target::ClassTable::table_offset();
-  LoadFromOffset(result, result, offset);
-  ASSERT(target::ClassTable::kSizeOfClassPairLog2 == 4);
-  add(class_id, class_id, Operand(class_id));
+  LoadFromOffset(result, result, table_offset);
   ldr(result, Address(result, class_id, UXTX, Address::Scaled));
 }
 
@@ -1553,10 +1553,16 @@
                                      Register temp_reg,
                                      Label* trace) {
   ASSERT(cid > 0);
-  intptr_t state_offset = target::ClassTable::StateOffsetFor(cid);
+
+  const intptr_t shared_table_offset =
+      target::Isolate::class_table_offset() +
+      target::ClassTable::shared_class_table_offset();
+  const intptr_t table_offset =
+      target::SharedClassTable::class_heap_stats_table_offset();
+  const intptr_t state_offset = target::ClassTable::StateOffsetFor(cid);
+
   LoadIsolate(temp_reg);
-  intptr_t table_offset = target::Isolate::class_table_offset() +
-                          target::ClassTable::class_heap_stats_table_offset();
+  ldr(temp_reg, Address(temp_reg, shared_table_offset));
   ldr(temp_reg, Address(temp_reg, table_offset));
   AddImmediate(temp_reg, state_offset);
   ldr(temp_reg, Address(temp_reg, 0));
@@ -1566,10 +1572,17 @@
 
 void Assembler::UpdateAllocationStats(intptr_t cid) {
   ASSERT(cid > 0);
-  intptr_t counter_offset = target::ClassTable::NewSpaceCounterOffsetFor(cid);
+
+  const intptr_t shared_table_offset =
+      target::Isolate::class_table_offset() +
+      target::ClassTable::shared_class_table_offset();
+  const intptr_t table_offset =
+      target::SharedClassTable::class_heap_stats_table_offset();
+  const intptr_t counter_offset =
+      target::ClassTable::NewSpaceCounterOffsetFor(cid);
+
   LoadIsolate(TMP2);
-  intptr_t table_offset = target::Isolate::class_table_offset() +
-                          target::ClassTable::class_heap_stats_table_offset();
+  ldr(TMP2, Address(TMP2, shared_table_offset));
   ldr(TMP, Address(TMP2, table_offset));
   AddImmediate(TMP2, TMP, counter_offset);
   ldr(TMP, Address(TMP2, 0));
@@ -1579,14 +1592,21 @@
 
 void Assembler::UpdateAllocationStatsWithSize(intptr_t cid, Register size_reg) {
   ASSERT(cid > 0);
+
+  const intptr_t shared_table_offset =
+      target::Isolate::class_table_offset() +
+      target::ClassTable::shared_class_table_offset();
+  const intptr_t table_offset =
+      target::SharedClassTable::class_heap_stats_table_offset();
+
   const uword class_offset = target::ClassTable::ClassOffsetFor(cid);
   const uword count_field_offset =
       target::ClassHeapStats::allocated_since_gc_new_space_offset();
   const uword size_field_offset =
       target::ClassHeapStats::allocated_size_since_gc_new_space_offset();
+
   LoadIsolate(TMP2);
-  intptr_t table_offset = target::Isolate::class_table_offset() +
-                          target::ClassTable::class_heap_stats_table_offset();
+  ldr(TMP2, Address(TMP2, shared_table_offset));
   ldr(TMP, Address(TMP2, table_offset));
   AddImmediate(TMP2, TMP, class_offset);
   ldr(TMP, Address(TMP2, count_field_offset));
diff --git a/runtime/vm/compiler/assembler/assembler_arm64.h b/runtime/vm/compiler/assembler/assembler_arm64.h
index d945c0e..315e72f 100644
--- a/runtime/vm/compiler/assembler/assembler_arm64.h
+++ b/runtime/vm/compiler/assembler/assembler_arm64.h
@@ -1526,7 +1526,6 @@
   void CompareObject(Register reg, const Object& object);
 
   void LoadClassId(Register result, Register object);
-  // Overwrites class_id register (it will be tagged afterwards).
   void LoadClassById(Register result, Register class_id);
   void CompareClassId(Register object,
                       intptr_t class_id,
diff --git a/runtime/vm/compiler/assembler/assembler_ia32.cc b/runtime/vm/compiler/assembler/assembler_ia32.cc
index 5834616..4943f780 100644
--- a/runtime/vm/compiler/assembler/assembler_ia32.cc
+++ b/runtime/vm/compiler/assembler/assembler_ia32.cc
@@ -2362,11 +2362,17 @@
                                      bool near_jump) {
   ASSERT(cid > 0);
   Address state_address(kNoRegister, 0);
-  intptr_t state_offset = target::ClassTable::StateOffsetFor(cid);
+
+  const intptr_t shared_table_offset =
+      target::Isolate::class_table_offset() +
+      target::ClassTable::shared_class_table_offset();
+  const intptr_t table_offset =
+      target::SharedClassTable::class_heap_stats_table_offset();
+  const intptr_t state_offset = target::ClassTable::StateOffsetFor(cid);
+
   ASSERT(temp_reg != kNoRegister);
   LoadIsolate(temp_reg);
-  intptr_t table_offset = target::Isolate::class_table_offset() +
-                          target::ClassTable::class_heap_stats_table_offset();
+  movl(temp_reg, Address(temp_reg, shared_table_offset));
   movl(temp_reg, Address(temp_reg, table_offset));
   state_address = Address(temp_reg, state_offset);
   testb(state_address,
@@ -2378,11 +2384,17 @@
 
 void Assembler::UpdateAllocationStats(intptr_t cid, Register temp_reg) {
   ASSERT(cid > 0);
-  intptr_t counter_offset = target::ClassTable::NewSpaceCounterOffsetFor(cid);
+  const intptr_t shared_table_offset =
+      target::Isolate::class_table_offset() +
+      target::ClassTable::shared_class_table_offset();
+  const intptr_t table_offset =
+      target::SharedClassTable::class_heap_stats_table_offset();
+  const intptr_t counter_offset =
+      target::ClassTable::NewSpaceCounterOffsetFor(cid);
+
   ASSERT(temp_reg != kNoRegister);
   LoadIsolate(temp_reg);
-  intptr_t table_offset = target::Isolate::class_table_offset() +
-                          target::ClassTable::class_heap_stats_table_offset();
+  movl(temp_reg, Address(temp_reg, shared_table_offset));
   movl(temp_reg, Address(temp_reg, table_offset));
   incl(Address(temp_reg, counter_offset));
 }
@@ -2617,12 +2629,12 @@
 
 void Assembler::LoadClassById(Register result, Register class_id) {
   ASSERT(result != class_id);
+
+  const intptr_t table_offset = target::Isolate::class_table_offset() +
+                                target::ClassTable::table_offset();
   LoadIsolate(result);
-  const intptr_t offset = target::Isolate::class_table_offset() +
-                          target::ClassTable::table_offset();
-  movl(result, Address(result, offset));
-  ASSERT(target::ClassTable::kSizeOfClassPairLog2 == 3);
-  movl(result, Address(result, class_id, TIMES_8, 0));
+  movl(result, Address(result, table_offset));
+  movl(result, Address(result, class_id, TIMES_4, 0));
 }
 
 void Assembler::CompareClassId(Register object,
diff --git a/runtime/vm/compiler/assembler/assembler_x64.cc b/runtime/vm/compiler/assembler/assembler_x64.cc
index 8bc626a..9c1cb4f 100644
--- a/runtime/vm/compiler/assembler/assembler_x64.cc
+++ b/runtime/vm/compiler/assembler/assembler_x64.cc
@@ -1851,11 +1851,16 @@
                                      Label* trace,
                                      bool near_jump) {
   ASSERT(cid > 0);
-  intptr_t state_offset = target::ClassTable::StateOffsetFor(cid);
+  const intptr_t shared_table_offset =
+      target::Isolate::class_table_offset() +
+      target::ClassTable::shared_class_table_offset();
+  const intptr_t table_offset =
+      target::SharedClassTable::class_heap_stats_table_offset();
+  const intptr_t state_offset = target::ClassTable::StateOffsetFor(cid);
+
   Register temp_reg = TMP;
   LoadIsolate(temp_reg);
-  intptr_t table_offset = target::Isolate::class_table_offset() +
-                          target::ClassTable::class_heap_stats_table_offset();
+  movq(temp_reg, Address(temp_reg, shared_table_offset));
   movq(temp_reg, Address(temp_reg, table_offset));
   testb(Address(temp_reg, state_offset),
         Immediate(target::ClassHeapStats::TraceAllocationMask()));
@@ -1866,11 +1871,17 @@
 
 void Assembler::UpdateAllocationStats(intptr_t cid) {
   ASSERT(cid > 0);
-  intptr_t counter_offset = target::ClassTable::NewSpaceCounterOffsetFor(cid);
+  const intptr_t shared_table_offset =
+      target::Isolate::class_table_offset() +
+      target::ClassTable::shared_class_table_offset();
+  const intptr_t table_offset =
+      target::SharedClassTable::class_heap_stats_table_offset();
+  const intptr_t counter_offset =
+      target::ClassTable::NewSpaceCounterOffsetFor(cid);
+
   Register temp_reg = TMP;
   LoadIsolate(temp_reg);
-  intptr_t table_offset = target::Isolate::class_table_offset() +
-                          target::ClassTable::class_heap_stats_table_offset();
+  movq(temp_reg, Address(temp_reg, shared_table_offset));
   movq(temp_reg, Address(temp_reg, table_offset));
   incq(Address(temp_reg, counter_offset));
 }
@@ -2125,14 +2136,11 @@
 
 void Assembler::LoadClassById(Register result, Register class_id) {
   ASSERT(result != class_id);
+  const intptr_t table_offset = target::Isolate::class_table_offset() +
+                                target::ClassTable::table_offset();
+
   LoadIsolate(result);
-  const intptr_t offset = target::Isolate::class_table_offset() +
-                          target::ClassTable::table_offset();
-  movq(result, Address(result, offset));
-  ASSERT(target::ClassTable::kSizeOfClassPairLog2 == 4);
-  // TIMES_16 is not a real scale factor on x64, so we double the class id
-  // and use TIMES_8.
-  addq(class_id, class_id);
+  movq(result, Address(result, table_offset));
   movq(result, Address(result, class_id, TIMES_8, 0));
 }
 
diff --git a/runtime/vm/compiler/assembler/assembler_x64.h b/runtime/vm/compiler/assembler/assembler_x64.h
index 9e69dc8..4065bdd 100644
--- a/runtime/vm/compiler/assembler/assembler_x64.h
+++ b/runtime/vm/compiler/assembler/assembler_x64.h
@@ -803,8 +803,6 @@
 
   // Loading and comparing classes of objects.
   void LoadClassId(Register result, Register object);
-
-  // Overwrites class_id register (it will be tagged afterwards).
   void LoadClassById(Register result, Register class_id);
 
   void CompareClassId(Register object,
diff --git a/runtime/vm/compiler/backend/il_arm64.cc b/runtime/vm/compiler/backend/il_arm64.cc
index b49dc6e..3359f05 100644
--- a/runtime/vm/compiler/backend/il_arm64.cc
+++ b/runtime/vm/compiler/backend/il_arm64.cc
@@ -5419,6 +5419,55 @@
                                  Register out) {
   ASSERT(op_kind == Token::kMOD || op_kind == Token::kTRUNCDIV);
 
+  // Special case 64-bit div/mod by compile-time constant. Note that various
+  // special constants (such as powers of two) should have been optimized
+  // earlier in the pipeline. Div or mod by zero falls into general code
+  // to implement the exception.
+  if (FLAG_optimization_level <= 2) {
+    // We only consider magic operations under O3.
+  } else if (auto c = instruction->right()->definition()->AsConstant()) {
+    if (c->value().IsInteger()) {
+      const int64_t divisor = Integer::Cast(c->value()).AsInt64Value();
+      if (divisor <= -2 || divisor >= 2) {
+        // For x DIV c or x MOD c: use magic operations.
+        compiler::Label pos;
+        int64_t magic = 0;
+        int64_t shift = 0;
+        Utils::CalculateMagicAndShiftForDivRem(divisor, &magic, &shift);
+        // Compute tmp = high(magic * numerator).
+        __ LoadImmediate(TMP2, magic);
+        __ smulh(TMP2, TMP2, left);
+        // Compute tmp +/-= numerator.
+        if (divisor > 0 && magic < 0) {
+          __ add(TMP2, TMP2, compiler::Operand(left));
+        } else if (divisor < 0 && magic > 0) {
+          __ sub(TMP2, TMP2, compiler::Operand(left));
+        }
+        // Shift if needed.
+        if (shift != 0) {
+          __ add(TMP2, ZR, compiler::Operand(TMP2, ASR, shift));
+        }
+        // Finalize DIV or MOD.
+        if (op_kind == Token::kTRUNCDIV) {
+          __ sub(out, TMP2, compiler::Operand(TMP2, ASR, 63));
+        } else {
+          __ sub(TMP2, TMP2, compiler::Operand(TMP2, ASR, 63));
+          __ LoadImmediate(TMP, divisor);
+          __ msub(out, TMP2, TMP, left);
+          // Compensate for Dart's Euclidean view of MOD.
+          __ CompareRegisters(out, ZR);
+          if (divisor > 0) {
+            __ add(TMP2, out, compiler::Operand(TMP));
+          } else {
+            __ sub(TMP2, out, compiler::Operand(TMP));
+          }
+          __ csel(out, TMP2, out, LT);
+        }
+        return;
+      }
+    }
+  }
+
   // Prepare a slow path.
   Range* right_range = instruction->right()->definition()->range();
   Int64DivideSlowPath* slow_path = new (Z) Int64DivideSlowPath(
diff --git a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
index 7068b74..1cfab97 100644
--- a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
+++ b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
@@ -44,8 +44,7 @@
     UNREACHABLE();
   }
 
-  B->graph_entry_ =
-      new (Z) GraphEntryInstr(*parsed_function(), Compiler::kNoOSRDeoptId);
+  B->graph_entry_ = new (Z) GraphEntryInstr(*parsed_function(), B->osr_id_);
 
   auto normal_entry = B->BuildFunctionEntry(B->graph_entry_);
   B->graph_entry_->set_normal_entry(normal_entry);
@@ -63,6 +62,9 @@
   body += Return(TokenPosition::kNoSource);
 
   PrologueInfo prologue_info(-1, -1);
+  if (B->IsCompiledForOsr()) {
+    B->graph_entry_->RelinkToOsrEntry(Z, B->last_used_block_id_ + 1);
+  }
   return new (Z) FlowGraph(*parsed_function(), B->graph_entry_,
                            B->last_used_block_id_, prologue_info);
 }
diff --git a/runtime/vm/compiler/method_recognizer.cc b/runtime/vm/compiler/method_recognizer.cc
index 9dda8a1..07f910f 100644
--- a/runtime/vm/compiler/method_recognizer.cc
+++ b/runtime/vm/compiler/method_recognizer.cc
@@ -317,10 +317,10 @@
 static struct {
   intptr_t symbol_id;
   intptr_t cid;
-  intptr_t finger_print;
+  uint32_t finger_print;
   const char* name;
 } factory_recognizer_list[] = {RECOGNIZED_LIST_FACTORY_LIST(RECOGNIZE_FACTORY){
-    Symbols::kIllegal, -1, -1, NULL}};
+    Symbols::kIllegal, -1, 0, NULL}};
 
 #undef RECOGNIZE_FACTORY
 
diff --git a/runtime/vm/compiler/recognized_methods_list.h b/runtime/vm/compiler/recognized_methods_list.h
index 27e1bb1..3af03f5 100644
--- a/runtime/vm/compiler/recognized_methods_list.h
+++ b/runtime/vm/compiler/recognized_methods_list.h
@@ -9,337 +9,335 @@
 
 // clang-format off
 // (class-name, function-name, recognized enum, fingerprint).
-// When adding a new function add a 0 as fingerprint, build and run with
-// `tools/test.py vm/dart/reused_instructions_test` to get the correct
-// fingerprint from the mismatch error (or use Library::GetFunction() and print
-// func.SourceFingerprint()).
-// TODO(36376): Restore checking fingerprints of recognized methods.
+// When adding a new function, add a 0 as the fingerprint and run the build in
+// debug mode to get the correct fingerprint from the mismatch error.
 #define OTHER_RECOGNIZED_LIST(V)                                               \
-  V(::, identical, ObjectIdentical, 0x49c6e96a)                                \
-  V(ClassID, getID, ClassIDgetID, 0x7b18b257)                                  \
-  V(Object, Object., ObjectConstructor, 0x681617fe)                            \
-  V(List, ., ListFactory, 0x629f8324)                                          \
-  V(_List, ., ObjectArrayAllocate, 0x2121902f)                                 \
-  V(_TypedList, _getInt8, ByteArrayBaseGetInt8, 0x7041895a)                    \
-  V(_TypedList, _getUint8, ByteArrayBaseGetUint8, 0x336fa3ea)                  \
-  V(_TypedList, _getInt16, ByteArrayBaseGetInt16, 0x231bbe2e)                  \
-  V(_TypedList, _getUint16, ByteArrayBaseGetUint16, 0x0371785f)                \
-  V(_TypedList, _getInt32, ByteArrayBaseGetInt32, 0x65ab3a20)                  \
-  V(_TypedList, _getUint32, ByteArrayBaseGetUint32, 0x0cb0fcf6)                \
-  V(_TypedList, _getInt64, ByteArrayBaseGetInt64, 0x7db75d78)                  \
-  V(_TypedList, _getUint64, ByteArrayBaseGetUint64, 0x1487cfc6)                \
-  V(_TypedList, _getFloat32, ByteArrayBaseGetFloat32, 0x6674ea6f)              \
-  V(_TypedList, _getFloat64, ByteArrayBaseGetFloat64, 0x236c6e7a)              \
-  V(_TypedList, _getFloat32x4, ByteArrayBaseGetFloat32x4, 0x5c367ffb)          \
-  V(_TypedList, _getInt32x4, ByteArrayBaseGetInt32x4, 0x772d1c0f)              \
-  V(_TypedList, _setInt8, ByteArrayBaseSetInt8, 0x12bae36a)                    \
-  V(_TypedList, _setUint8, ByteArrayBaseSetUint8, 0x15821cc9)                  \
-  V(_TypedList, _setInt16, ByteArrayBaseSetInt16, 0x1f8237fa)                  \
-  V(_TypedList, _setUint16, ByteArrayBaseSetUint16, 0x181e5d16)                \
-  V(_TypedList, _setInt32, ByteArrayBaseSetInt32, 0x7ddb9f87)                  \
-  V(_TypedList, _setUint32, ByteArrayBaseSetUint32, 0x74094f8d)                \
-  V(_TypedList, _setInt64, ByteArrayBaseSetInt64, 0x4741396e)                  \
-  V(_TypedList, _setUint64, ByteArrayBaseSetUint64, 0x3b398ae4)                \
-  V(_TypedList, _setFloat32, ByteArrayBaseSetFloat32, 0x03db087b)              \
-  V(_TypedList, _setFloat64, ByteArrayBaseSetFloat64, 0x38a80b0d)              \
-  V(_TypedList, _setFloat32x4, ByteArrayBaseSetFloat32x4, 0x40052c4e)          \
-  V(_TypedList, _setInt32x4, ByteArrayBaseSetInt32x4, 0x07b89f54)              \
-  V(ByteData, ., ByteDataFactory, 0x0)                                         \
-  V(_ByteDataView, get:offsetInBytes, ByteDataViewOffsetInBytes, 0x0)          \
-  V(_ByteDataView, get:_typedData, ByteDataViewTypedData, 0x0)                 \
-  V(_TypedListView, get:offsetInBytes, TypedDataViewOffsetInBytes, 0x0)        \
-  V(_TypedListView, get:_typedData, TypedDataViewTypedData, 0x0)               \
-  V(_ByteDataView, ._, TypedData_ByteDataView_factory, 0x0)                    \
-  V(_Int8ArrayView, ._, TypedData_Int8ArrayView_factory, 0x0)                  \
-  V(_Uint8ArrayView, ._, TypedData_Uint8ArrayView_factory, 0x0)                \
-  V(_Uint8ClampedArrayView, ._, TypedData_Uint8ClampedArrayView_factory, 0x0)  \
-  V(_Int16ArrayView, ._, TypedData_Int16ArrayView_factory, 0x0)                \
-  V(_Uint16ArrayView, ._, TypedData_Uint16ArrayView_factory, 0x0)              \
-  V(_Int32ArrayView, ._, TypedData_Int32ArrayView_factory, 0x0)                \
-  V(_Uint32ArrayView, ._, TypedData_Uint32ArrayView_factory, 0x0)              \
-  V(_Int64ArrayView, ._, TypedData_Int64ArrayView_factory, 0x0)                \
-  V(_Uint64ArrayView, ._, TypedData_Uint64ArrayView_factory, 0x0)              \
-  V(_Float32ArrayView, ._, TypedData_Float32ArrayView_factory, 0x0)            \
-  V(_Float64ArrayView, ._, TypedData_Float64ArrayView_factory, 0x0)            \
-  V(_Float32x4ArrayView, ._, TypedData_Float32x4ArrayView_factory, 0x0)        \
-  V(_Int32x4ArrayView, ._, TypedData_Int32x4ArrayView_factory, 0x0)            \
-  V(_Float64x2ArrayView, ._, TypedData_Float64x2ArrayView_factory, 0x0)        \
-  V(::, _toClampedUint8, ConvertIntToClampedUint8, 0x564b0435)                 \
-  V(_StringBase, _interpolate, StringBaseInterpolate, 0x01ecb15a)              \
-  V(_IntegerImplementation, toDouble, IntegerToDouble, 0x05da96ed)             \
-  V(_Double, _add, DoubleAdd, 0x2a38277b)                                      \
-  V(_Double, _sub, DoubleSub, 0x4f466391)                                      \
-  V(_Double, _mul, DoubleMul, 0x175e4f66)                                      \
-  V(_Double, _div, DoubleDiv, 0x0854181b)                                      \
-  V(::, min, MathMin, 0x32ebc57d)                                              \
-  V(::, max, MathMax, 0x377e8889)                                              \
-  V(::, _doublePow, MathDoublePow, 0x5add0ec1)                                 \
-  V(::, _intPow, MathIntPow, 0x11b45569)                                       \
-  V(Float32x4, Float32x4., Float32x4Constructor, 0x26ea459b)                   \
-  V(Float32x4, Float32x4.zero, Float32x4Zero, 0x16eca604)                      \
-  V(Float32x4, Float32x4.splat, Float32x4Splat, 0x694e83e3)                    \
-  V(Float32x4, Float32x4.fromInt32x4Bits, Int32x4ToFloat32x4, 0x2f62ebd3)      \
-  V(Float32x4, Float32x4.fromFloat64x2, Float64x2ToFloat32x4, 0x50ed6910)      \
-  V(_Float32x4, shuffle, Float32x4Shuffle, 0x7829101f)                         \
-  V(_Float32x4, shuffleMix, Float32x4ShuffleMix, 0x4182c06b)                   \
-  V(_Float32x4, get:signMask, Float32x4GetSignMask, 0x1d08b351)                \
-  V(_Float32x4, equal, Float32x4Equal, 0x11adb239)                             \
-  V(_Float32x4, greaterThan, Float32x4GreaterThan, 0x48adaf58)                 \
-  V(_Float32x4, greaterThanOrEqual, Float32x4GreaterThanOrEqual, 0x32db94ca)   \
-  V(_Float32x4, lessThan, Float32x4LessThan, 0x425b000c)                       \
-  V(_Float32x4, lessThanOrEqual, Float32x4LessThanOrEqual, 0x0278c2f8)         \
-  V(_Float32x4, notEqual, Float32x4NotEqual, 0x2987cd26)                       \
-  V(_Float32x4, min, Float32x4Min, 0x5ed74b6f)                                 \
-  V(_Float32x4, max, Float32x4Max, 0x68696442)                                 \
-  V(_Float32x4, scale, Float32x4Scale, 0x704e4122)                             \
-  V(_Float32x4, sqrt, Float32x4Sqrt, 0x2c967a6f)                               \
-  V(_Float32x4, reciprocalSqrt, Float32x4ReciprocalSqrt, 0x6264bfe8)           \
-  V(_Float32x4, reciprocal, Float32x4Reciprocal, 0x3cd7e819)                   \
-  V(_Float32x4, unary-, Float32x4Negate, 0x37accb52)                           \
-  V(_Float32x4, abs, Float32x4Abs, 0x471cdd87)                                 \
-  V(_Float32x4, clamp, Float32x4Clamp, 0x2cb30492)                             \
-  V(_Float32x4, withX, Float32x4WithX, 0x4e336aff)                             \
-  V(_Float32x4, withY, Float32x4WithY, 0x0a72b910)                             \
-  V(_Float32x4, withZ, Float32x4WithZ, 0x31e93658)                             \
-  V(_Float32x4, withW, Float32x4WithW, 0x60ddc105)                             \
-  V(Float64x2, Float64x2., Float64x2Constructor, 0x43054b9f)                   \
-  V(Float64x2, Float64x2.zero, Float64x2Zero, 0x4af12f9d)                      \
-  V(Float64x2, Float64x2.splat, Float64x2Splat, 0x134edef0)                    \
-  V(Float64x2, Float64x2.fromFloat32x4, Float32x4ToFloat64x2, 0x17d6b5e4)      \
-  V(_Float64x2, get:x, Float64x2GetX, 0x58c09c58)                              \
-  V(_Float64x2, get:y, Float64x2GetY, 0x3cf5e5b8)                              \
-  V(_Float64x2, unary-, Float64x2Negate, 0x415ca009)                           \
-  V(_Float64x2, abs, Float64x2Abs, 0x031f9e47)                                 \
-  V(_Float64x2, sqrt, Float64x2Sqrt, 0x77f711dd)                               \
-  V(_Float64x2, get:signMask, Float64x2GetSignMask, 0x27deda4b)                \
-  V(_Float64x2, scale, Float64x2Scale, 0x26830a61)                             \
-  V(_Float64x2, withX, Float64x2WithX, 0x1d2bcaf5)                             \
-  V(_Float64x2, withY, Float64x2WithY, 0x383ed6ac)                             \
-  V(_Float64x2, min, Float64x2Min,  0x28d7ddf6)                                \
-  V(_Float64x2, max, Float64x2Max,  0x0bd74e5b)                                \
-  V(Int32x4, Int32x4., Int32x4Constructor, 0x480555a9)                         \
-  V(Int32x4, Int32x4.bool, Int32x4BoolConstructor, 0x36aa6963)                 \
-  V(Int32x4, Int32x4.fromFloat32x4Bits, Float32x4ToInt32x4, 0x6715388a)        \
-  V(_Int32x4, get:flagX, Int32x4GetFlagX, 0x56396c82)                          \
-  V(_Int32x4, get:flagY, Int32x4GetFlagY, 0x44704738)                          \
-  V(_Int32x4, get:flagZ, Int32x4GetFlagZ, 0x20d6ff37)                          \
-  V(_Int32x4, get:flagW, Int32x4GetFlagW, 0x5045616a)                          \
-  V(_Int32x4, get:signMask, Int32x4GetSignMask, 0x2c1fb2a3)                    \
-  V(_Int32x4, shuffle, Int32x4Shuffle, 0x20bc0b16)                             \
-  V(_Int32x4, shuffleMix, Int32x4ShuffleMix, 0x5c7056e1)                       \
-  V(_Int32x4, select, Int32x4Select, 0x6b49654f)                               \
-  V(_Int32x4, withFlagX, Int32x4WithFlagX, 0x0ef58fcf)                         \
-  V(_Int32x4, withFlagY, Int32x4WithFlagY, 0x6485a9c4)                         \
-  V(_Int32x4, withFlagZ, Int32x4WithFlagZ, 0x267acdfa)                         \
-  V(_Int32x4, withFlagW, Int32x4WithFlagW, 0x345ac675)                         \
-  V(_HashVMBase, get:_index, LinkedHashMap_getIndex, 0x02477157)               \
-  V(_HashVMBase, set:_index, LinkedHashMap_setIndex, 0x4fc8d5e0)               \
-  V(_HashVMBase, get:_data, LinkedHashMap_getData, 0x2d7a70ac)                 \
-  V(_HashVMBase, set:_data, LinkedHashMap_setData, 0x0ec032e8)                 \
-  V(_HashVMBase, get:_usedData, LinkedHashMap_getUsedData, 0x088599ed)         \
-  V(_HashVMBase, set:_usedData, LinkedHashMap_setUsedData, 0x5f42ca86)         \
-  V(_HashVMBase, get:_hashMask, LinkedHashMap_getHashMask, 0x32f3b13b)         \
-  V(_HashVMBase, set:_hashMask, LinkedHashMap_setHashMask, 0x7219c45b)         \
-  V(_HashVMBase, get:_deletedKeys, LinkedHashMap_getDeletedKeys, 0x558481c2)   \
-  V(_HashVMBase, set:_deletedKeys, LinkedHashMap_setDeletedKeys, 0x5aa9888d)   \
-  V(::, _classRangeCheck, ClassRangeCheck, 0x2ae76b84)                         \
-  V(::, _asyncStackTraceHelper, AsyncStackTraceHelper, 0)                      \
-  V(::, _abi, FfiAbi, 0x0)                                                     \
-  V(::, _asFunctionInternal, FfiAsFunctionInternal, 0x0)                       \
-  V(::, _nativeCallbackFunction, FfiNativeCallbackFunction, 0x0)               \
+  V(::, identical, ObjectIdentical, 0xc6e9467a)                                \
+  V(ClassID, getID, ClassIDgetID, 0xf0376ced)                                  \
+  V(Object, Object., ObjectConstructor, 0x8f3ae7ea)                            \
+  V(List, ., ListFactory, 0xd834242d)                                          \
+  V(_List, ., ObjectArrayAllocate, 0xe9c6d2be)                                 \
+  V(_TypedList, _getInt8, ByteArrayBaseGetInt8, 0xa24c2704)                    \
+  V(_TypedList, _getUint8, ByteArrayBaseGetUint8, 0xa491df3e)                  \
+  V(_TypedList, _getInt16, ByteArrayBaseGetInt16, 0xb65ae1fc)                  \
+  V(_TypedList, _getUint16, ByteArrayBaseGetUint16, 0xb4b776e5)                \
+  V(_TypedList, _getInt32, ByteArrayBaseGetInt32, 0xb460abe4)                  \
+  V(_TypedList, _getUint32, ByteArrayBaseGetUint32, 0x8c066c71)                \
+  V(_TypedList, _getInt64, ByteArrayBaseGetInt64, 0xacf2f222)                  \
+  V(_TypedList, _getUint64, ByteArrayBaseGetUint64, 0xa74b200b)                \
+  V(_TypedList, _getFloat32, ByteArrayBaseGetFloat32, 0xa33a9f77)              \
+  V(_TypedList, _getFloat64, ByteArrayBaseGetFloat64, 0x87d86b60)              \
+  V(_TypedList, _getFloat32x4, ByteArrayBaseGetFloat32x4, 0x3e76086e)          \
+  V(_TypedList, _getInt32x4, ByteArrayBaseGetInt32x4, 0xfea5f17f)              \
+  V(_TypedList, _setInt8, ByteArrayBaseSetInt8, 0xd2c4e74b)                    \
+  V(_TypedList, _setUint8, ByteArrayBaseSetUint8, 0xec62b082)                  \
+  V(_TypedList, _setInt16, ByteArrayBaseSetInt16, 0xc3566903)                  \
+  V(_TypedList, _setUint16, ByteArrayBaseSetUint16, 0xdb50780f)                \
+  V(_TypedList, _setInt32, ByteArrayBaseSetInt32, 0xbeeeea8a)                  \
+  V(_TypedList, _setUint32, ByteArrayBaseSetUint32, 0xca02f10a)                \
+  V(_TypedList, _setInt64, ByteArrayBaseSetInt64, 0xcf587ccf)                  \
+  V(_TypedList, _setUint64, ByteArrayBaseSetUint64, 0xe01a1df0)                \
+  V(_TypedList, _setFloat32, ByteArrayBaseSetFloat32, 0xb6a6294f)              \
+  V(_TypedList, _setFloat64, ByteArrayBaseSetFloat64, 0xce7dad17)              \
+  V(_TypedList, _setFloat32x4, ByteArrayBaseSetFloat32x4, 0x4b773b59)          \
+  V(_TypedList, _setInt32x4, ByteArrayBaseSetInt32x4, 0xfa2a6f88)              \
+  V(ByteData, ., ByteDataFactory, 0x0d31f187)                                  \
+  V(_ByteDataView, get:offsetInBytes, ByteDataViewOffsetInBytes, 0x0d956c6d)   \
+  V(_ByteDataView, get:_typedData, ByteDataViewTypedData, 0x28cc4efc)          \
+  V(_TypedListView, get:offsetInBytes, TypedDataViewOffsetInBytes, 0x0d956c6d) \
+  V(_TypedListView, get:_typedData, TypedDataViewTypedData, 0x28cc4efc)        \
+  V(_ByteDataView, ._, TypedData_ByteDataView_factory, 0xb839ff59)             \
+  V(_Int8ArrayView, ._, TypedData_Int8ArrayView_factory, 0x3d000a8d)           \
+  V(_Uint8ArrayView, ._, TypedData_Uint8ArrayView_factory, 0xff69de0f)         \
+  V(_Uint8ClampedArrayView, ._, TypedData_Uint8ClampedArrayView_factory,       \
+    0xdff11b9a)                                                                \
+  V(_Int16ArrayView, ._, TypedData_Int16ArrayView_factory, 0x1635c91e)         \
+  V(_Uint16ArrayView, ._, TypedData_Uint16ArrayView_factory, 0x287cbc66)       \
+  V(_Int32ArrayView, ._, TypedData_Int32ArrayView_factory, 0xf5270227)         \
+  V(_Uint32ArrayView, ._, TypedData_Uint32ArrayView_factory, 0xbb74a021)       \
+  V(_Int64ArrayView, ._, TypedData_Int64ArrayView_factory, 0xf348a583)         \
+  V(_Uint64ArrayView, ._, TypedData_Uint64ArrayView_factory, 0x10589491)       \
+  V(_Float32ArrayView, ._, TypedData_Float32ArrayView_factory, 0xbb4124b3)     \
+  V(_Float64ArrayView, ._, TypedData_Float64ArrayView_factory, 0x5f0b81e9)     \
+  V(_Float32x4ArrayView, ._, TypedData_Float32x4ArrayView_factory, 0xd8c71a39) \
+  V(_Int32x4ArrayView, ._, TypedData_Int32x4ArrayView_factory, 0x9bfbd6d5)     \
+  V(_Float64x2ArrayView, ._, TypedData_Float64x2ArrayView_factory, 0x1a383408) \
+  V(::, _toClampedUint8, ConvertIntToClampedUint8, 0x59765a4a)                 \
+  V(_StringBase, _interpolate, StringBaseInterpolate, 0xe5a934d2)              \
+  V(_IntegerImplementation, toDouble, IntegerToDouble, 0x22a26db3)             \
+  V(_Double, _add, DoubleAdd, 0x2f5c036a)                                      \
+  V(_Double, _sub, DoubleSub, 0x6d3cec71)                                      \
+  V(_Double, _mul, DoubleMul, 0x648e67af)                                      \
+  V(_Double, _div, DoubleDiv, 0x6d72d7d4)                                      \
+  V(::, min, MathMin, 0x07168bf9)                                              \
+  V(::, max, MathMax, 0xc7dbc9a0)                                              \
+  V(::, _doublePow, MathDoublePow, 0x5ae04e61)                                 \
+  V(::, _intPow, MathIntPow, 0x569ffd3f)                                       \
+  V(Float32x4, Float32x4., Float32x4Constructor, 0xdf9f0693)                   \
+  V(Float32x4, Float32x4.zero, Float32x4Zero, 0x9b875c7f)                      \
+  V(Float32x4, Float32x4.splat, Float32x4Splat, 0xf584a639)                    \
+  V(Float32x4, Float32x4.fromInt32x4Bits, Int32x4ToFloat32x4, 0x7339b2bd)      \
+  V(Float32x4, Float32x4.fromFloat64x2, Float64x2ToFloat32x4, 0x5de0e788)      \
+  V(_Float32x4, shuffle, Float32x4Shuffle, 0x5bc2446e)                         \
+  V(_Float32x4, shuffleMix, Float32x4ShuffleMix, 0x61887391)                   \
+  V(_Float32x4, get:signMask, Float32x4GetSignMask, 0x2931936f)                \
+  V(_Float32x4, equal, Float32x4Equal, 0x63e87fb9)                             \
+  V(_Float32x4, greaterThan, Float32x4GreaterThan, 0x71db0fc2)                 \
+  V(_Float32x4, greaterThanOrEqual, Float32x4GreaterThanOrEqual, 0x6dfbf3fa)   \
+  V(_Float32x4, lessThan, Float32x4LessThan, 0x69a60360)                       \
+  V(_Float32x4, lessThanOrEqual, Float32x4LessThanOrEqual, 0x6604e583)         \
+  V(_Float32x4, notEqual, Float32x4NotEqual, 0x83dcc786)                       \
+  V(_Float32x4, min, Float32x4Min, 0xf70ed6d5)                                 \
+  V(_Float32x4, max, Float32x4Max, 0xd93e58a6)                                 \
+  V(_Float32x4, scale, Float32x4Scale, 0xea28b605)                             \
+  V(_Float32x4, sqrt, Float32x4Sqrt, 0xacff17f7)                               \
+  V(_Float32x4, reciprocalSqrt, Float32x4ReciprocalSqrt, 0xa5e00f7d)           \
+  V(_Float32x4, reciprocal, Float32x4Reciprocal, 0x9c5a3fb7)                   \
+  V(_Float32x4, unary-, Float32x4Negate, 0xae8af7f1)                           \
+  V(_Float32x4, abs, Float32x4Abs, 0xb34e9b8d)                                 \
+  V(_Float32x4, clamp, Float32x4Clamp, 0xbed4ce62)                             \
+  V(_Float32x4, withX, Float32x4WithX, 0xe204ec19)                             \
+  V(_Float32x4, withY, Float32x4WithY, 0xff17a63f)                             \
+  V(_Float32x4, withZ, Float32x4WithZ, 0x0e7144f2)                             \
+  V(_Float32x4, withW, Float32x4WithW, 0x0802b80f)                             \
+  V(Float64x2, Float64x2., Float64x2Constructor, 0xb0bb0109)                   \
+  V(Float64x2, Float64x2.zero, Float64x2Zero, 0x5e70f315)                      \
+  V(Float64x2, Float64x2.splat, Float64x2Splat, 0xb86e3ccf)                    \
+  V(Float64x2, Float64x2.fromFloat32x4, Float32x4ToFloat64x2, 0x956c2161)      \
+  V(_Float64x2, get:x, Float64x2GetX, 0x00b83193)                              \
+  V(_Float64x2, get:y, Float64x2GetY, 0xee498cb6)                              \
+  V(_Float64x2, unary-, Float64x2Negate, 0x71748e87)                           \
+  V(_Float64x2, abs, Float64x2Abs, 0x76383223)                                 \
+  V(_Float64x2, sqrt, Float64x2Sqrt, 0x6fe8ae8d)                               \
+  V(_Float64x2, get:signMask, Float64x2GetSignMask, 0x2931936f)                \
+  V(_Float64x2, scale, Float64x2Scale, 0xad124c9b)                             \
+  V(_Float64x2, withX, Float64x2WithX, 0xa4ee82af)                             \
+  V(_Float64x2, withY, Float64x2WithY, 0xc2013cd5)                             \
+  V(_Float64x2, min, Float64x2Min,  0x57938495)                                \
+  V(_Float64x2, max, Float64x2Max,  0x39c30666)                                \
+  V(Int32x4, Int32x4., Int32x4Constructor, 0xa77aeafb)                         \
+  V(Int32x4, Int32x4.bool, Int32x4BoolConstructor, 0x51ae2c0c)                 \
+  V(Int32x4, Int32x4.fromFloat32x4Bits, Float32x4ToInt32x4, 0x64c906dc)        \
+  V(_Int32x4, get:flagX, Int32x4GetFlagX, 0x9f8da5bb)                          \
+  V(_Int32x4, get:flagY, Int32x4GetFlagY, 0xbafddc9b)                          \
+  V(_Int32x4, get:flagZ, Int32x4GetFlagZ, 0xc8a777ee)                          \
+  V(_Int32x4, get:flagW, Int32x4GetFlagW, 0xd1c78a2f)                          \
+  V(_Int32x4, get:signMask, Int32x4GetSignMask, 0x2931936f)                    \
+  V(_Int32x4, shuffle, Int32x4Shuffle, 0x00cff856)                             \
+  V(_Int32x4, shuffleMix, Int32x4ShuffleMix, 0x57a21961)                       \
+  V(_Int32x4, select, Int32x4Select, 0xafd1fc25)                               \
+  V(_Int32x4, withFlagX, Int32x4WithFlagX, 0x7a1fe4b5)                         \
+  V(_Int32x4, withFlagY, Int32x4WithFlagY, 0x8c658940)                         \
+  V(_Int32x4, withFlagZ, Int32x4WithFlagZ, 0x97d3a01c)                         \
+  V(_Int32x4, withFlagW, Int32x4WithFlagW, 0x80e3723b)                         \
+  V(_HashVMBase, get:_index, LinkedHashMap_getIndex, 0x09db1d9d)               \
+  V(_HashVMBase, set:_index, LinkedHashMap_setIndex, 0xb643fb19)               \
+  V(_HashVMBase, get:_data, LinkedHashMap_getData, 0x9a54182a)                 \
+  V(_HashVMBase, set:_data, LinkedHashMap_setData, 0x8bc58326)                 \
+  V(_HashVMBase, get:_usedData, LinkedHashMap_getUsedData, 0xf3cf0e2e)         \
+  V(_HashVMBase, set:_usedData, LinkedHashMap_setUsedData, 0x75261d2a)         \
+  V(_HashVMBase, get:_hashMask, LinkedHashMap_getHashMask, 0xfbd541dd)         \
+  V(_HashVMBase, set:_hashMask, LinkedHashMap_setHashMask, 0x7d2c50d9)         \
+  V(_HashVMBase, get:_deletedKeys, LinkedHashMap_getDeletedKeys, 0xfdd43ee1)   \
+  V(_HashVMBase, set:_deletedKeys, LinkedHashMap_setDeletedKeys, 0x7f2b4ddd)   \
+  V(::, _classRangeCheck, ClassRangeCheck, 0xca52e30a)                         \
+  V(::, _asyncStackTraceHelper, AsyncStackTraceHelper, 0xaeaed5cb)             \
+  V(::, _abi, FfiAbi, 0xf2e89620)                                              \
+  V(::, _asFunctionInternal, FfiAsFunctionInternal, 0x82525e9e)                \
+  V(::, _nativeCallbackFunction, FfiNativeCallbackFunction, 0x591fb33c)        \
 
 // List of intrinsics:
 // (class-name, function-name, intrinsification method, fingerprint).
 #define CORE_LIB_INTRINSIC_LIST(V)                                             \
-  V(_Smi, ~, Smi_bitNegate, 0x67299f4f)                                        \
-  V(_Smi, get:bitLength, Smi_bitLength, 0x25b3cb0a)                            \
-  V(_Smi, _bitAndFromSmi, Smi_bitAndFromSmi, 0x562d5047)                       \
-  V(_BigIntImpl, _lsh, Bigint_lsh, 0x5b6cfc8b)                                 \
-  V(_BigIntImpl, _rsh, Bigint_rsh, 0x6ff14a49)                                 \
-  V(_BigIntImpl, _absAdd, Bigint_absAdd, 0x5bf14238)                           \
-  V(_BigIntImpl, _absSub, Bigint_absSub, 0x1de5bd32)                           \
-  V(_BigIntImpl, _mulAdd, Bigint_mulAdd, 0x6f277966)                           \
-  V(_BigIntImpl, _sqrAdd, Bigint_sqrAdd, 0x68e4c8ea)                           \
+  V(_Smi, ~, Smi_bitNegate, 0x2f002cba)                                        \
+  V(_Smi, get:bitLength, Smi_bitLength, 0x277b8ace)                            \
+  V(_Smi, _bitAndFromSmi, Smi_bitAndFromSmi, 0x90b94dd3)                       \
+  V(_BigIntImpl, _lsh, Bigint_lsh, 0x776e33c7)                                 \
+  V(_BigIntImpl, _rsh, Bigint_rsh, 0x2bf277fc)                                 \
+  V(_BigIntImpl, _absAdd, Bigint_absAdd, 0x147eb8ec)                           \
+  V(_BigIntImpl, _absSub, Bigint_absSub, 0xed4c4e74)                           \
+  V(_BigIntImpl, _mulAdd, Bigint_mulAdd, 0xc8dcc37e)                           \
+  V(_BigIntImpl, _sqrAdd, Bigint_sqrAdd, 0x45be1228)                           \
   V(_BigIntImpl, _estimateQuotientDigit, Bigint_estimateQuotientDigit,         \
-    0x35456d91)                                                                \
-  V(_BigIntMontgomeryReduction, _mulMod, Montgomery_mulMod, 0x0f7b0375)        \
-  V(_Double, >, Double_greaterThan, 0x4f1375a3)                                \
-  V(_Double, >=, Double_greaterEqualThan, 0x4260c184)                          \
-  V(_Double, <, Double_lessThan, 0x365d1eba)                                   \
-  V(_Double, <=, Double_lessEqualThan, 0x74b5eb64)                             \
-  V(_Double, ==, Double_equal, 0x613492fc)                                     \
-  V(_Double, +, Double_add, 0x53994370)                                        \
-  V(_Double, -, Double_sub, 0x3b69d466)                                        \
-  V(_Double, *, Double_mul, 0x2bb9bd5d)                                        \
-  V(_Double, /, Double_div, 0x483eee28)                                        \
-  V(_Double, get:hashCode, Double_hashCode, 0x702b77b7)                        \
-  V(_Double, get:_identityHashCode, Double_identityHash, 0x7bda5549)           \
-  V(_Double, get:isNaN, Double_getIsNaN, 0x0af9d4a9)                           \
-  V(_Double, get:isInfinite, Double_getIsInfinite, 0x0f7acb47)                 \
-  V(_Double, get:isNegative, Double_getIsNegative, 0x3a59e7f4)                 \
-  V(_Double, _mulFromInteger, Double_mulFromInteger, 0x2017fcf6)               \
-  V(_Double, .fromInteger, DoubleFromInteger, 0x6d234f4b)                      \
-  V(_GrowableList, ._withData, GrowableArray_Allocate, 0x28b2138e)             \
-  V(_RegExp, _ExecuteMatch, RegExp_ExecuteMatch, 0x380184b1)                   \
-  V(_RegExp, _ExecuteMatchSticky, RegExp_ExecuteMatchSticky, 0x79b8f955)       \
-  V(Object, ==, ObjectEquals, 0x7b32a55a)                                      \
-  V(Object, get:runtimeType, ObjectRuntimeType, 0x00e8ab29)                    \
-  V(Object, _haveSameRuntimeType, ObjectHaveSameRuntimeType, 0x4dc50799)       \
-  V(_StringBase, get:hashCode, String_getHashCode, 0x78c3d446)                 \
-  V(_StringBase, get:_identityHashCode, String_identityHash, 0x0472b1d8)       \
-  V(_StringBase, get:isEmpty, StringBaseIsEmpty, 0x4a8b29c8)                   \
-  V(_StringBase, _substringMatches, StringBaseSubstringMatches, 0x46de4f10)    \
-  V(_StringBase, [], StringBaseCharAt, 0x7cbb8603)                             \
-  V(_OneByteString, get:hashCode, OneByteString_getHashCode, 0x78c3d446)       \
+    0xd7c44af1)                                                                \
+  V(_BigIntMontgomeryReduction, _mulMod, Montgomery_mulMod, 0xa1a5caf3)        \
+  V(_Double, >, Double_greaterThan, 0x682a02bc)                                \
+  V(_Double, >=, Double_greaterEqualThan, 0x2961f8ee)                          \
+  V(_Double, <, Double_lessThan, 0xcbff42e5)                                   \
+  V(_Double, <=, Double_lessEqualThan, 0xd2253d90)                             \
+  V(_Double, ==, Double_equal, 0xa7dfa02b)                                     \
+  V(_Double, +, Double_add, 0xf7d8da94)                                        \
+  V(_Double, -, Double_sub, 0xc8dda725)                                        \
+  V(_Double, *, Double_mul, 0x2dac85a2)                                        \
+  V(_Double, /, Double_div, 0x6cf1f09e)                                        \
+  V(_Double, get:hashCode, Double_hashCode, 0x22a75218)                        \
+  V(_Double, get:_identityHashCode, Double_identityHash, 0xf46be6d6)           \
+  V(_Double, get:isNaN, Double_getIsNaN, 0xb177a8f6)                           \
+  V(_Double, get:isInfinite, Double_getIsInfinite, 0xa1e96db5)                 \
+  V(_Double, get:isNegative, Double_getIsNegative, 0xb15ff274)                 \
+  V(_Double, _mulFromInteger, Double_mulFromInteger, 0xe2853768)               \
+  V(_Double, .fromInteger, DoubleFromInteger, 0x89504536)                      \
+  V(_GrowableList, ._withData, GrowableArray_Allocate, 0x55981e03)             \
+  V(_RegExp, _ExecuteMatch, RegExp_ExecuteMatch, 0xb961fc8d)                   \
+  V(_RegExp, _ExecuteMatchSticky, RegExp_ExecuteMatchSticky, 0xb22daf53)       \
+  V(Object, ==, ObjectEquals, 0x91ead0d6)                                      \
+  V(Object, get:runtimeType, ObjectRuntimeType, 0x8cdba093)                    \
+  V(Object, _haveSameRuntimeType, ObjectHaveSameRuntimeType, 0xcee5d65a)       \
+  V(_StringBase, get:hashCode, String_getHashCode, 0x22a75237)                 \
+  V(_StringBase, get:_identityHashCode, String_identityHash, 0xf46be6f5)       \
+  V(_StringBase, get:isEmpty, StringBaseIsEmpty, 0xd7218394)                   \
+  V(_StringBase, _substringMatches, StringBaseSubstringMatches, 0x46fc3731)    \
+  V(_StringBase, [], StringBaseCharAt, 0xe67164fe)                             \
+  V(_OneByteString, get:hashCode, OneByteString_getHashCode, 0x22a75237)       \
   V(_OneByteString, _substringUncheckedNative,                                 \
-    OneByteString_substringUnchecked,  0x3538ad86)                             \
-  V(_OneByteString, _setAt, OneByteStringSetAt, 0x11ffddd1)                    \
-  V(_OneByteString, _allocate, OneByteString_allocate,          0x74933376)    \
-  V(_OneByteString, ==, OneByteString_equality, 0x4eda197e)                    \
-  V(_TwoByteString, ==, TwoByteString_equality, 0x4eda197e)                    \
-  V(_Type, get:hashCode, Type_getHashCode, 0x18d1523f)                         \
-  V(::, _getHash, Object_getHash, 0x2827856d)                                  \
-  V(::, _setHash, Object_setHash, 0x690faebd)                                  \
+    OneByteString_substringUnchecked,  0x94c41563)                             \
+  V(_OneByteString, _setAt, OneByteStringSetAt, 0xc6c7e75d)                    \
+  V(_OneByteString, _allocate, OneByteString_allocate,          0xbe472ce0)    \
+  V(_OneByteString, ==, OneByteString_equality, 0xe1ea0c11)                    \
+  V(_TwoByteString, ==, TwoByteString_equality, 0xe1ea0c11)                    \
+  V(_Type, get:hashCode, Type_getHashCode, 0x22a75237)                         \
+  V(::, _getHash, Object_getHash, 0xb05aa13f)                                  \
+  V(::, _setHash, Object_setHash, 0xcb404dd2)                                  \
 
 
 #define CORE_INTEGER_LIB_INTRINSIC_LIST(V)                                     \
   V(_IntegerImplementation, _addFromInteger, Integer_addFromInteger,           \
-    0x6a10c54a)                                                                \
-  V(_IntegerImplementation, +, Integer_add, 0x43d53af7)                        \
+    0xc7bd74ae)                                                                \
+  V(_IntegerImplementation, +, Integer_add, 0x49774600)                        \
   V(_IntegerImplementation, _subFromInteger, Integer_subFromInteger,           \
-    0x3fa4b1ed)                                                                \
-  V(_IntegerImplementation, -, Integer_sub, 0x2dc22e03)                        \
+    0x8e0de2a2)                                                                \
+  V(_IntegerImplementation, -, Integer_sub, 0x1a853bf1)                        \
   V(_IntegerImplementation, _mulFromInteger, Integer_mulFromInteger,           \
-    0x3216e299)                                                                \
-  V(_IntegerImplementation, *, Integer_mul, 0x4e7a1c24)                        \
+    0x95751a41)                                                                \
+  V(_IntegerImplementation, *, Integer_mul, 0xefe7fbce)                        \
   V(_IntegerImplementation, _moduloFromInteger, Integer_moduloFromInteger,     \
-     0x6348b974)                                                               \
-  V(_IntegerImplementation, ~/, Integer_truncDivide, 0x4efb2d39)               \
-  V(_IntegerImplementation, unary-, Integer_negate, 0x428bf6fa)                \
+    0xbc75fece)                                                                \
+  V(_IntegerImplementation, ~/, Integer_truncDivide, 0xfb066107)               \
+  V(_IntegerImplementation, unary-, Integer_negate, 0xdb5f0d70)                \
   V(_IntegerImplementation, _bitAndFromInteger, Integer_bitAndFromInteger,     \
-    0x395b1678)                                                                \
-  V(_IntegerImplementation, &, Integer_bitAnd, 0x5ab35f30)                     \
+    0xb7e724d2)                                                                \
+  V(_IntegerImplementation, &, Integer_bitAnd, 0xd9888ca4)                     \
   V(_IntegerImplementation, _bitOrFromInteger, Integer_bitOrFromInteger,       \
-    0x6a36b395)                                                                \
-  V(_IntegerImplementation, |, Integer_bitOr, 0x267fa107)                      \
+    0xa97501aa)                                                                \
+  V(_IntegerImplementation, |, Integer_bitOr, 0xc82cc85c)                      \
   V(_IntegerImplementation, _bitXorFromInteger, Integer_bitXorFromInteger,     \
-    0x72da93f0)                                                                \
-  V(_IntegerImplementation, ^, Integer_bitXor, 0x0c7b0230)                     \
+    0x9ab4d16e)                                                                \
+  V(_IntegerImplementation, ^, Integer_bitXor, 0xc1ed9463)                     \
   V(_IntegerImplementation, _greaterThanFromInteger,                           \
-    Integer_greaterThanFromInt, 0x4a50ed58)                                    \
-  V(_IntegerImplementation, >, Integer_greaterThan, 0x6599a6e1)                \
-  V(_IntegerImplementation, ==, Integer_equal, 0x58abc487)                     \
+    Integer_greaterThanFromInt, 0x3366ff66)                                    \
+  V(_IntegerImplementation, >, Integer_greaterThan, 0xe74b678c)                \
+  V(_IntegerImplementation, ==, Integer_equal, 0xb6faea0e)                     \
   V(_IntegerImplementation, _equalToInteger, Integer_equalToInteger,           \
-    0x063be842)                                                                \
-  V(_IntegerImplementation, <, Integer_lessThan, 0x365d1eba)                   \
-  V(_IntegerImplementation, <=, Integer_lessEqualThan, 0x74b5eb64)             \
-  V(_IntegerImplementation, >=, Integer_greaterEqualThan, 0x4260c184)          \
-  V(_IntegerImplementation, <<, Integer_shl, 0x371c45fa)                       \
-  V(_IntegerImplementation, >>, Integer_sar, 0x2b630578)                       \
-  V(_Double, toInt, DoubleToInteger, 0x26ef344b)                               \
+    0x39d3cd05)                                                                \
+  V(_IntegerImplementation, <, Integer_lessThan, 0xcbff42e5)                   \
+  V(_IntegerImplementation, <=, Integer_lessEqualThan, 0xd2253d90)             \
+  V(_IntegerImplementation, >=, Integer_greaterEqualThan, 0x2961f8ee)          \
+  V(_IntegerImplementation, <<, Integer_shl, 0x972a7fd6)                       \
+  V(_IntegerImplementation, >>, Integer_sar, 0xfe022e7b)                       \
+  V(_Double, toInt, DoubleToInteger, 0x14433ded)                               \
 
 #define MATH_LIB_INTRINSIC_LIST(V)                                             \
-  V(::, sqrt, MathSqrt, 0x70482cf3)                                            \
-  V(_Random, _nextState, Random_nextState, 0x2842c4d5)                         \
+  V(::, sqrt, MathSqrt, 0x2c20a879)                                            \
+  V(_Random, _nextState, Random_nextState, 0x30682e3d)                         \
 
 #define GRAPH_MATH_LIB_INTRINSIC_LIST(V)                                       \
-  V(::, sin, MathSin, 0x6b7bd98c)                                              \
-  V(::, cos, MathCos, 0x459bf5fe)                                              \
-  V(::, tan, MathTan, 0x3bcd772a)                                              \
-  V(::, asin, MathAsin, 0x2ecc2fcd)                                            \
-  V(::, acos, MathAcos, 0x08cf2212)                                            \
-  V(::, atan, MathAtan, 0x1e2731d5)                                            \
-  V(::, atan2, MathAtan2, 0x39f1fa41)                                          \
+  V(::, sin, MathSin, 0x18e743c0)                                              \
+  V(::, cos, MathCos, 0x6623c0ce)                                              \
+  V(::, tan, MathTan, 0x3584ee62)                                              \
+  V(::, asin, MathAsin, 0xb023f0df)                                            \
+  V(::, acos, MathAcos, 0x165661fa)                                            \
+  V(::, atan, MathAtan, 0xc91eca17)                                            \
+  V(::, atan2, MathAtan2, 0x79b3a5e6)                                          \
 
 #define TYPED_DATA_LIB_INTRINSIC_LIST(V)                                       \
-  V(Int8List, ., TypedData_Int8Array_factory, 0x7e39a3a1)                      \
-  V(Uint8List, ., TypedData_Uint8Array_factory, 0x3a79adf7)                    \
-  V(Uint8ClampedList, ., TypedData_Uint8ClampedArray_factory, 0x67f38395)      \
-  V(Int16List, ., TypedData_Int16Array_factory, 0x6477bda8)                    \
-  V(Uint16List, ., TypedData_Uint16Array_factory, 0x5707c5a2)                  \
-  V(Int32List, ., TypedData_Int32Array_factory, 0x2b96ec0e)                    \
-  V(Uint32List, ., TypedData_Uint32Array_factory, 0x0c1c0d62)                  \
-  V(Int64List, ., TypedData_Int64Array_factory, 0x279ab485)                    \
-  V(Uint64List, ., TypedData_Uint64Array_factory, 0x7bcb89c2)                  \
-  V(Float32List, ., TypedData_Float32Array_factory, 0x43506c09)                \
-  V(Float64List, ., TypedData_Float64Array_factory, 0x1fde3eaf)                \
-  V(Float32x4List, ., TypedData_Float32x4Array_factory, 0x4a4030d6)            \
-  V(Int32x4List, ., TypedData_Int32x4Array_factory, 0x6dd02406)                \
-  V(Float64x2List, ., TypedData_Float64x2Array_factory, 0x688e4e97)            \
+  V(Int8List, ., TypedData_Int8Array_factory, 0x6ce2f102)                      \
+  V(Uint8List, ., TypedData_Uint8Array_factory, 0x1163d489)                    \
+  V(Uint8ClampedList, ., TypedData_Uint8ClampedArray_factory, 0x0b0e9f0f)      \
+  V(Int16List, ., TypedData_Int16Array_factory, 0x6addd02d)                    \
+  V(Uint16List, ., TypedData_Uint16Array_factory, 0x139a6464)                  \
+  V(Int32List, ., TypedData_Int32Array_factory, 0x40dad19a)                    \
+  V(Uint32List, ., TypedData_Uint32Array_factory, 0x988357c5)                  \
+  V(Int64List, ., TypedData_Int64Array_factory, 0xef0a3469)                    \
+  V(Uint64List, ., TypedData_Uint64Array_factory, 0xf49c0472)                  \
+  V(Float32List, ., TypedData_Float32Array_factory, 0x779b26f8)                \
+  V(Float64List, ., TypedData_Float64Array_factory, 0xf623554b)                \
+  V(Float32x4List, ., TypedData_Float32x4Array_factory, 0x9edf5402)            \
+  V(Int32x4List, ., TypedData_Int32x4Array_factory, 0x915e8e68)                \
+  V(Float64x2List, ., TypedData_Float64x2Array_factory, 0x0d206864)            \
 
 #define GRAPH_TYPED_DATA_INTRINSICS_LIST(V)                                    \
-  V(_Int8List, [], Int8ArrayGetIndexed, 0x49767a2c)                            \
-  V(_Int8List, []=, Int8ArraySetIndexed, 0x24f42cd0)                           \
-  V(_Uint8List, [], Uint8ArrayGetIndexed, 0x088d86d4)                          \
-  V(_Uint8List, []=, Uint8ArraySetIndexed, 0x12639541)                         \
-  V(_ExternalUint8Array, [], ExternalUint8ArrayGetIndexed, 0x088d86d4)         \
-  V(_ExternalUint8Array, []=, ExternalUint8ArraySetIndexed, 0x12639541)        \
-  V(_Uint8ClampedList, [], Uint8ClampedArrayGetIndexed, 0x088d86d4)            \
-  V(_Uint8ClampedList, []=, Uint8ClampedArraySetIndexed, 0x6790dba1)           \
+  V(_Int8List, [], Int8ArrayGetIndexed, 0xdab47d5d)                            \
+  V(_Int8List, []=, Int8ArraySetIndexed, 0x09ba0f32)                           \
+  V(_Uint8List, [], Uint8ArrayGetIndexed, 0xa9468b1d)                          \
+  V(_Uint8List, []=, Uint8ArraySetIndexed, 0xa6fd9dce)                         \
+  V(_ExternalUint8Array, [], ExternalUint8ArrayGetIndexed, 0xa9468b1d)         \
+  V(_ExternalUint8Array, []=, ExternalUint8ArraySetIndexed, 0xa6fd9dce)        \
+  V(_Uint8ClampedList, [], Uint8ClampedArrayGetIndexed, 0xa9468b1d)            \
+  V(_Uint8ClampedList, []=, Uint8ClampedArraySetIndexed, 0x7d60b42e)           \
   V(_ExternalUint8ClampedArray, [], ExternalUint8ClampedArrayGetIndexed,       \
-    0x088d86d4)                                                                \
+    0xa9468b1d)                                                                \
   V(_ExternalUint8ClampedArray, []=, ExternalUint8ClampedArraySetIndexed,      \
-    0x6790dba1)                                                                \
-  V(_Int16List, [], Int16ArrayGetIndexed, 0x5ec64948)                          \
-  V(_Int16List, []=, Int16ArraySetIndexed, 0x0e4e8221)                         \
-  V(_Uint16List, [], Uint16ArrayGetIndexed, 0x5f49d093)                        \
-  V(_Uint16List, []=, Uint16ArraySetIndexed, 0x2efbc90f)                       \
-  V(_Int32List, [], Int32ArrayGetIndexed, 0x4bc0d3dd)                          \
-  V(_Int32List, []=, Int32ArraySetIndexed, 0x1adf9823)                         \
-  V(_Uint32List, [], Uint32ArrayGetIndexed, 0x188658ce)                        \
-  V(_Uint32List, []=, Uint32ArraySetIndexed, 0x01f51a79)                       \
-  V(_Int64List, [], Int64ArrayGetIndexed, 0x51eafb97)                          \
-  V(_Int64List, []=, Int64ArraySetIndexed, 0x376181fb)                         \
-  V(_Uint64List, [], Uint64ArrayGetIndexed, 0x4b2a1ba2)                        \
-  V(_Uint64List, []=, Uint64ArraySetIndexed, 0x5f881bd4)                       \
-  V(_Float64List, [], Float64ArrayGetIndexed, 0x0a714486)                      \
-  V(_Float64List, []=, Float64ArraySetIndexed, 0x04937367)                     \
-  V(_Float32List, [], Float32ArrayGetIndexed, 0x5ade301f)                      \
-  V(_Float32List, []=, Float32ArraySetIndexed, 0x0d5c2e2b)                     \
-  V(_Float32x4List, [], Float32x4ArrayGetIndexed, 0x128cddeb)                  \
-  V(_Float32x4List, []=, Float32x4ArraySetIndexed, 0x7ad55c72)                 \
-  V(_Int32x4List, [], Int32x4ArrayGetIndexed, 0x4b78af9c)                      \
-  V(_Int32x4List, []=, Int32x4ArraySetIndexed, 0x31453dab)                     \
-  V(_Float64x2List, [], Float64x2ArrayGetIndexed, 0x644a0be1)                  \
-  V(_Float64x2List, []=, Float64x2ArraySetIndexed, 0x6b836b0b)                 \
-  V(_TypedList, get:length, TypedListLength, 0x0)                \
-  V(_TypedListView, get:length, TypedListViewLength, 0x0)        \
-  V(_ByteDataView, get:length, ByteDataViewLength, 0x0)          \
-  V(_Float32x4, get:x, Float32x4ShuffleX, 0x63d1a9fd)                          \
-  V(_Float32x4, get:y, Float32x4ShuffleY, 0x203523d9)                          \
-  V(_Float32x4, get:z, Float32x4ShuffleZ, 0x13190678)                          \
-  V(_Float32x4, get:w, Float32x4ShuffleW, 0x698a38de)                          \
-  V(_Float32x4, *, Float32x4Mul, 0x5dec68b2)                                   \
-  V(_Float32x4, -, Float32x4Sub, 0x3ea14461)                                   \
-  V(_Float32x4, +, Float32x4Add, 0x7ffcf301)                                   \
+    0x7d60b42e)                                                                \
+  V(_Int16List, [], Int16ArrayGetIndexed, 0x2b783e9d)                          \
+  V(_Int16List, []=, Int16ArraySetIndexed, 0x894edd67)                         \
+  V(_Uint16List, [], Uint16ArrayGetIndexed, 0x3d599bdd)                        \
+  V(_Uint16List, []=, Uint16ArraySetIndexed, 0x146065d0)                       \
+  V(_Int32List, [], Int32ArrayGetIndexed, 0x645ac57e)                          \
+  V(_Int32List, []=, Int32ArraySetIndexed, 0x58343408)                         \
+  V(_Uint32List, [], Uint32ArrayGetIndexed, 0xe6f6183e)                        \
+  V(_Uint32List, []=, Uint32ArraySetIndexed, 0x7ee99568)                       \
+  V(_Int64List, [], Int64ArrayGetIndexed, 0x57d917de)                          \
+  V(_Int64List, []=, Int64ArraySetIndexed, 0x94485c32)                         \
+  V(_Uint64List, [], Uint64ArrayGetIndexed, 0x7fb017de)                        \
+  V(_Uint64List, []=, Uint64ArraySetIndexed, 0x1c695796)                       \
+  V(_Float64List, [], Float64ArrayGetIndexed, 0x9e20a2c3)                      \
+  V(_Float64List, []=, Float64ArraySetIndexed, 0xcd01ec0c)                     \
+  V(_Float32List, [], Float32ArrayGetIndexed, 0x7c01bb83)                      \
+  V(_Float32List, []=, Float32ArraySetIndexed, 0xcb87f800)                     \
+  V(_Float32x4List, [], Float32x4ArrayGetIndexed, 0x5a2a83fc)                  \
+  V(_Float32x4List, []=, Float32x4ArraySetIndexed, 0x5ae5c9f3)                 \
+  V(_Int32x4List, [], Int32x4ArrayGetIndexed, 0x05ef16d4)                      \
+  V(_Int32x4List, []=, Int32x4ArraySetIndexed, 0x2e8437b1)                     \
+  V(_Float64x2List, [], Float64x2ArrayGetIndexed, 0xe7fbf246)                  \
+  V(_Float64x2List, []=, Float64x2ArraySetIndexed, 0xce826d19)                 \
+  V(_TypedList, get:length, TypedListLength, 0x05176aac)                       \
+  V(_TypedListView, get:length, TypedListViewLength, 0x05176aac)               \
+  V(_ByteDataView, get:length, ByteDataViewLength, 0x05176aac)                 \
+  V(_Float32x4, get:x, Float32x4ShuffleX, 0x00b83193)                          \
+  V(_Float32x4, get:y, Float32x4ShuffleY, 0xee498cb6)                          \
+  V(_Float32x4, get:z, Float32x4ShuffleZ, 0x2414f84c)                          \
+  V(_Float32x4, get:w, Float32x4ShuffleW, 0x06553cce)                          \
+  V(_Float32x4, *, Float32x4Mul, 0xf817cb64)                                   \
+  V(_Float32x4, -, Float32x4Sub, 0xeff9bb27)                                   \
+  V(_Float32x4, +, Float32x4Add, 0xcac0f0b6)                                   \
 
 #define GRAPH_CORE_INTRINSICS_LIST(V)                                          \
-  V(_List, get:length, ObjectArrayLength, 0x25952390)                          \
-  V(_List, [], ObjectArrayGetIndexed, 0x653da02e)                              \
-  V(_List, []=, ObjectArraySetIndexed, 0x16b3d2b0)                             \
-  V(_List, _setIndexed, ObjectArraySetIndexedUnchecked, 0x50d64c75)            \
-  V(_ImmutableList, get:length, ImmutableArrayLength, 0x25952390)              \
-  V(_ImmutableList, [], ImmutableArrayGetIndexed, 0x653da02e)                  \
-  V(_GrowableList, get:length, GrowableArrayLength, 0x18dd86b4)                \
-  V(_GrowableList, get:_capacity, GrowableArrayCapacity, 0x2e04be60)           \
-  V(_GrowableList, _setData, GrowableArraySetData, 0x3dbea348)                 \
-  V(_GrowableList, _setLength, GrowableArraySetLength, 0x753e55da)             \
-  V(_GrowableList, [], GrowableArrayGetIndexed, 0x446fe1f0)                    \
-  V(_GrowableList, []=, GrowableArraySetIndexed, 0x40a462ec)                   \
-  V(_GrowableList, _setIndexed, GrowableArraySetIndexedUnchecked, 0x297083df)  \
-  V(_StringBase, get:length, StringBaseLength, 0x2a2d03d1)                     \
-  V(_OneByteString, codeUnitAt, OneByteStringCodeUnitAt, 0x55a0a1f3)           \
-  V(_TwoByteString, codeUnitAt, TwoByteStringCodeUnitAt, 0x55a0a1f3)           \
+  V(_List, get:length, ObjectArrayLength, 0x05176aac)                          \
+  V(_List, [], ObjectArrayGetIndexed, 0x7e13418e)                              \
+  V(_List, []=, ObjectArraySetIndexed, 0x4d5e74cf)                             \
+  V(_List, _setIndexed, ObjectArraySetIndexedUnchecked, 0x91b2c203)            \
+  V(_ImmutableList, get:length, ImmutableArrayLength, 0x05176aac)              \
+  V(_ImmutableList, [], ImmutableArrayGetIndexed, 0x7e13418e)                  \
+  V(_GrowableList, get:length, GrowableArrayLength, 0x05176aac)                \
+  V(_GrowableList, get:_capacity, GrowableArrayCapacity, 0x2a661633)           \
+  V(_GrowableList, _setData, GrowableArraySetData, 0x9e2350fe)                 \
+  V(_GrowableList, _setLength, GrowableArraySetLength, 0x8d94d91d)             \
+  V(_GrowableList, [], GrowableArrayGetIndexed, 0x7e13418e)                    \
+  V(_GrowableList, []=, GrowableArraySetIndexed, 0x4d5e74cf)                   \
+  V(_GrowableList, _setIndexed, GrowableArraySetIndexedUnchecked, 0x91b2c203)  \
+  V(_StringBase, get:length, StringBaseLength, 0x05176aac)                     \
+  V(_OneByteString, codeUnitAt, OneByteStringCodeUnitAt, 0xb0959953)           \
+  V(_TwoByteString, codeUnitAt, TwoByteStringCodeUnitAt, 0xb0959953)           \
   V(_ExternalOneByteString, codeUnitAt, ExternalOneByteStringCodeUnitAt,       \
-    0x55a0a1f3)                                                                \
+    0xb0959953)                                                                \
   V(_ExternalTwoByteString, codeUnitAt, ExternalTwoByteStringCodeUnitAt,       \
-    0x55a0a1f3)                                                                \
-  V(_Double, unary-, DoubleFlipSignBit, 0x6db4674f)                            \
-  V(_Double, truncateToDouble, DoubleTruncate, 0x2f27e5d3)                     \
-  V(_Double, roundToDouble, DoubleRound, 0x2f89c512)                           \
-  V(_Double, floorToDouble, DoubleFloor, 0x6aa87a5f)                           \
-  V(_Double, ceilToDouble, DoubleCeil, 0x1b045e9e)                             \
-  V(_Double, _modulo, DoubleMod, 0x5b8ceed7)
+    0xb0959953)                                                                \
+  V(_Double, unary-, DoubleFlipSignBit, 0x039c6e4a)                            \
+  V(_Double, truncateToDouble, DoubleTruncate, 0x2960d21d)                     \
+  V(_Double, roundToDouble, DoubleRound, 0x1cd615c4)                           \
+  V(_Double, floorToDouble, DoubleFloor, 0x1b41170c)                           \
+  V(_Double, ceilToDouble, DoubleCeil, 0x25a81a9d)                             \
+  V(_Double, _modulo, DoubleMod, 0x42a93471)
 
 
 #define GRAPH_INTRINSICS_LIST(V)                                               \
@@ -348,14 +346,14 @@
   GRAPH_MATH_LIB_INTRINSIC_LIST(V)                                             \
 
 #define DEVELOPER_LIB_INTRINSIC_LIST(V)                                        \
-  V(_UserTag, makeCurrent, UserTag_makeCurrent, 0x0b3066fd)                    \
-  V(::, _getDefaultTag, UserTag_defaultTag, 0x69f3f1ad)                        \
-  V(::, _getCurrentTag, Profiler_getCurrentTag, 0x05fa99d2)                    \
-  V(::, _isDartStreamEnabled, Timeline_isDartStreamEnabled, 0x72f13f7a)        \
+  V(_UserTag, makeCurrent, UserTag_makeCurrent, 0x472d1eb5)                    \
+  V(::, _getDefaultTag, UserTag_defaultTag, 0x5c124271)                        \
+  V(::, _getCurrentTag, Profiler_getCurrentTag, 0x5d6d8a14)                    \
+  V(::, _isDartStreamEnabled, Timeline_isDartStreamEnabled, 0xcf6f3099)        \
 
 #define ASYNC_LIB_INTRINSIC_LIST(V)                                            \
-  V(::, _clearAsyncThreadStackTrace, ClearAsyncThreadStackTrace, 0x2edd4b25)   \
-  V(::, _setAsyncThreadStackTrace, SetAsyncThreadStackTrace, 0x04f429a7)       \
+  V(::, _clearAsyncThreadStackTrace, ClearAsyncThreadStackTrace, 0x341efd8e)   \
+  V(::, _setAsyncThreadStackTrace, SetAsyncThreadStackTrace, 0x5f29f453)       \
 
 #define ALL_INTRINSICS_NO_INTEGER_LIB_LIST(V)                                  \
   ASYNC_LIB_INTRINSIC_LIST(V)                                                  \
@@ -375,58 +373,58 @@
 
 // A list of core functions that internally dispatch based on received id.
 #define POLYMORPHIC_TARGET_LIST(V)                                             \
-  V(_StringBase, [], StringBaseCharAt, 0x7cbb8603)                             \
-  V(_TypedList, _getInt8, ByteArrayBaseGetInt8, 0x7041895a)                    \
-  V(_TypedList, _getUint8, ByteArrayBaseGetUint8, 0x336fa3ea)                  \
-  V(_TypedList, _getInt16, ByteArrayBaseGetInt16, 0x231bbe2e)                  \
-  V(_TypedList, _getUint16, ByteArrayBaseGetUint16, 0x0371785f)                \
-  V(_TypedList, _getInt32, ByteArrayBaseGetInt32, 0x65ab3a20)                  \
-  V(_TypedList, _getUint32, ByteArrayBaseGetUint32, 0x0cb0fcf6)                \
-  V(_TypedList, _getInt64, ByteArrayBaseGetInt64, 0x7db75d78)                  \
-  V(_TypedList, _getUint64, ByteArrayBaseGetUint64, 0x1487cfc6)                \
-  V(_TypedList, _getFloat32, ByteArrayBaseGetFloat32, 0x6674ea6f)              \
-  V(_TypedList, _getFloat64, ByteArrayBaseGetFloat64, 0x236c6e7a)              \
-  V(_TypedList, _getFloat32x4, ByteArrayBaseGetFloat32x4, 0x5c367ffb)          \
-  V(_TypedList, _getInt32x4, ByteArrayBaseGetInt32x4, 0x772d1c0f)              \
-  V(_TypedList, _setInt8, ByteArrayBaseSetInt8, 0x12bae36a)                    \
-  V(_TypedList, _setUint8, ByteArrayBaseSetInt8, 0x15821cc9)                   \
-  V(_TypedList, _setInt16, ByteArrayBaseSetInt16, 0x1f8237fa)                  \
-  V(_TypedList, _setUint16, ByteArrayBaseSetInt16, 0x181e5d16)                 \
-  V(_TypedList, _setInt32, ByteArrayBaseSetInt32, 0x7ddb9f87)                  \
-  V(_TypedList, _setUint32, ByteArrayBaseSetUint32, 0x74094f8d)                \
-  V(_TypedList, _setInt64, ByteArrayBaseSetInt64, 0x4741396e)                  \
-  V(_TypedList, _setUint64, ByteArrayBaseSetUint64, 0x3b398ae4)                \
-  V(_TypedList, _setFloat32, ByteArrayBaseSetFloat32, 0x03db087b)              \
-  V(_TypedList, _setFloat64, ByteArrayBaseSetFloat64, 0x38a80b0d)              \
-  V(_TypedList, _setFloat32x4, ByteArrayBaseSetFloat32x4, 0x40052c4e)          \
-  V(_TypedList, _setInt32x4, ByteArrayBaseSetInt32x4, 0x07b89f54)              \
-  V(Object, get:runtimeType, ObjectRuntimeType, 0x00e8ab29)
+  V(_StringBase, [], StringBaseCharAt, 0xe67164fe)                             \
+  V(_TypedList, _getInt8, ByteArrayBaseGetInt8, 0xa24c2704)                    \
+  V(_TypedList, _getUint8, ByteArrayBaseGetUint8, 0xa491df3e)                  \
+  V(_TypedList, _getInt16, ByteArrayBaseGetInt16, 0xb65ae1fc)                  \
+  V(_TypedList, _getUint16, ByteArrayBaseGetUint16, 0xb4b776e5)                \
+  V(_TypedList, _getInt32, ByteArrayBaseGetInt32, 0xb460abe4)                  \
+  V(_TypedList, _getUint32, ByteArrayBaseGetUint32, 0x8c066c71)                \
+  V(_TypedList, _getInt64, ByteArrayBaseGetInt64, 0xacf2f222)                  \
+  V(_TypedList, _getUint64, ByteArrayBaseGetUint64, 0xa74b200b)                \
+  V(_TypedList, _getFloat32, ByteArrayBaseGetFloat32, 0xa33a9f77)              \
+  V(_TypedList, _getFloat64, ByteArrayBaseGetFloat64, 0x87d86b60)              \
+  V(_TypedList, _getFloat32x4, ByteArrayBaseGetFloat32x4, 0x3e76086e)          \
+  V(_TypedList, _getInt32x4, ByteArrayBaseGetInt32x4, 0xfea5f17f)              \
+  V(_TypedList, _setInt8, ByteArrayBaseSetInt8, 0xd2c4e74b)                    \
+  V(_TypedList, _setUint8, ByteArrayBaseSetInt8, 0xec62b082)                   \
+  V(_TypedList, _setInt16, ByteArrayBaseSetInt16, 0xc3566903)                  \
+  V(_TypedList, _setUint16, ByteArrayBaseSetInt16, 0xdb50780f)                 \
+  V(_TypedList, _setInt32, ByteArrayBaseSetInt32, 0xbeeeea8a)                  \
+  V(_TypedList, _setUint32, ByteArrayBaseSetUint32, 0xca02f10a)                \
+  V(_TypedList, _setInt64, ByteArrayBaseSetInt64, 0xcf587ccf)                  \
+  V(_TypedList, _setUint64, ByteArrayBaseSetUint64, 0xe01a1df0)                \
+  V(_TypedList, _setFloat32, ByteArrayBaseSetFloat32, 0xb6a6294f)              \
+  V(_TypedList, _setFloat64, ByteArrayBaseSetFloat64, 0xce7dad17)              \
+  V(_TypedList, _setFloat32x4, ByteArrayBaseSetFloat32x4, 0x4b773b59)          \
+  V(_TypedList, _setInt32x4, ByteArrayBaseSetInt32x4, 0xfa2a6f88)              \
+  V(Object, get:runtimeType, ObjectRuntimeType, 0x8cdba093)
 
 // List of recognized list factories:
 // (factory-name-symbol, class-name-string, constructor-name-string,
 //  result-cid, fingerprint).
 #define RECOGNIZED_LIST_FACTORY_LIST(V)                                        \
-  V(_ListFactory, _List, ., kArrayCid, 0x2121902f)                             \
+  V(_ListFactory, _List, ., kArrayCid, 0xe9c6d2be)                             \
   V(_GrowableListWithData, _GrowableList, ._withData, kGrowableObjectArrayCid, \
-    0x28b2138e)                                                                \
+    0x55981e03)                                                                \
   V(_GrowableListFactory, _GrowableList, ., kGrowableObjectArrayCid,           \
     0x3eed680b)                                                                \
-  V(_Int8ArrayFactory, Int8List, ., kTypedDataInt8ArrayCid, 0x7e39a3a1)        \
-  V(_Uint8ArrayFactory, Uint8List, ., kTypedDataUint8ArrayCid, 0x3a79adf7)     \
+  V(_Int8ArrayFactory, Int8List, ., kTypedDataInt8ArrayCid, 0x6ce2f102)        \
+  V(_Uint8ArrayFactory, Uint8List, ., kTypedDataUint8ArrayCid, 0x1163d489)     \
   V(_Uint8ClampedArrayFactory, Uint8ClampedList, .,                            \
-    kTypedDataUint8ClampedArrayCid, 0x67f38395)                                \
-  V(_Int16ArrayFactory, Int16List, ., kTypedDataInt16ArrayCid, 0x6477bda8)     \
-  V(_Uint16ArrayFactory, Uint16List, ., kTypedDataUint16ArrayCid, 0x5707c5a2)  \
-  V(_Int32ArrayFactory, Int32List, ., kTypedDataInt32ArrayCid, 0x2b96ec0e)     \
-  V(_Uint32ArrayFactory, Uint32List, ., kTypedDataUint32ArrayCid, 0x0c1c0d62)  \
-  V(_Int64ArrayFactory, Int64List, ., kTypedDataInt64ArrayCid, 0x279ab485)     \
-  V(_Uint64ArrayFactory, Uint64List, ., kTypedDataUint64ArrayCid, 0x7bcb89c2)  \
+    kTypedDataUint8ClampedArrayCid, 0x0b0e9f0f)                                \
+  V(_Int16ArrayFactory, Int16List, ., kTypedDataInt16ArrayCid, 0x6addd02d)     \
+  V(_Uint16ArrayFactory, Uint16List, ., kTypedDataUint16ArrayCid, 0x139a6464)  \
+  V(_Int32ArrayFactory, Int32List, ., kTypedDataInt32ArrayCid, 0x40dad19a)     \
+  V(_Uint32ArrayFactory, Uint32List, ., kTypedDataUint32ArrayCid, 0x988357c5)  \
+  V(_Int64ArrayFactory, Int64List, ., kTypedDataInt64ArrayCid, 0xef0a3469)     \
+  V(_Uint64ArrayFactory, Uint64List, ., kTypedDataUint64ArrayCid, 0xf49c0472)  \
   V(_Float64ArrayFactory, Float64List, ., kTypedDataFloat64ArrayCid,           \
-    0x1fde3eaf)                                                                \
+    0xf623554b)                                                                \
   V(_Float32ArrayFactory, Float32List, ., kTypedDataFloat32ArrayCid,           \
-    0x43506c09)                                                                \
+    0x779b26f8)                                                                \
   V(_Float32x4ArrayFactory, Float32x4List, ., kTypedDataFloat32x4ArrayCid,     \
-    0x4a4030d6)
+    0x9edf5402)
 
 // clang-format on
 
diff --git a/runtime/vm/compiler/runtime_api.h b/runtime/vm/compiler/runtime_api.h
index ef2bc61..0579418 100644
--- a/runtime/vm/compiler/runtime_api.h
+++ b/runtime/vm/compiler/runtime_api.h
@@ -755,15 +755,22 @@
 #endif  // !defined(PRODUCT)
 };
 
+class SharedClassTable : public AllStatic {
+ public:
+  static word class_heap_stats_table_offset();
+};
+
 class ClassTable : public AllStatic {
  public:
   static word table_offset();
+  static word shared_class_table_offset();
 #if !defined(PRODUCT)
   static word ClassOffsetFor(intptr_t cid);
   static word StateOffsetFor(intptr_t cid);
-  static word class_heap_stats_table_offset();
   static word NewSpaceCounterOffsetFor(intptr_t cid);
   static word NewSpaceSizeOffsetFor(intptr_t cid);
+  static word SharedTableOffsetFor();
+  static word SizeOffsetFor(intptr_t cid, bool is_new);
 #endif  // !defined(PRODUCT)
   static const word kSizeOfClassPairLog2;
 };
diff --git a/runtime/vm/compiler/runtime_offsets_extracted.h b/runtime/vm/compiler/runtime_offsets_extracted.h
index 021c6dd..add5eab 100644
--- a/runtime/vm/compiler/runtime_offsets_extracted.h
+++ b/runtime/vm/compiler/runtime_offsets_extracted.h
@@ -22,8 +22,6 @@
 static constexpr dart::compiler::target::word Array_kMaxElements = 268435455;
 static constexpr dart::compiler::target::word Array_kMaxNewSpaceElements =
     65533;
-static constexpr dart::compiler::target::word ClassTable_kSizeOfClassPairLog2 =
-    3;
 static constexpr dart::compiler::target::word
     Instructions_kMonomorphicEntryOffsetJIT = 0;
 static constexpr dart::compiler::target::word
@@ -85,7 +83,11 @@
 static constexpr dart::compiler::target::word
     ClassHeapStats_allocated_size_since_gc_new_space_offset = 52;
 static constexpr dart::compiler::target::word ClassHeapStats_state_offset = 160;
+static constexpr dart::compiler::target::word
+    ClassTable_shared_class_table_offset = 20;
 static constexpr dart::compiler::target::word ClassTable_table_offset = 8;
+static constexpr dart::compiler::target::word
+    SharedClassTable_class_heap_stats_table_offset = 0;
 static constexpr dart::compiler::target::word Closure_context_offset = 20;
 static constexpr dart::compiler::target::word
     Closure_delayed_type_arguments_offset = 12;
@@ -138,12 +140,12 @@
 static constexpr dart::compiler::target::word ICData_state_bits_offset = 28;
 static constexpr dart::compiler::target::word
     ICData_receivers_static_type_offset = 16;
-static constexpr dart::compiler::target::word Isolate_class_table_offset = 36;
+static constexpr dart::compiler::target::word Isolate_class_table_offset = 40;
 static constexpr dart::compiler::target::word Isolate_current_tag_offset = 20;
 static constexpr dart::compiler::target::word Isolate_default_tag_offset = 24;
 static constexpr dart::compiler::target::word Isolate_ic_miss_code_offset = 28;
-static constexpr dart::compiler::target::word Isolate_object_store_offset = 32;
-static constexpr dart::compiler::target::word Isolate_single_step_offset = 56;
+static constexpr dart::compiler::target::word Isolate_object_store_offset = 36;
+static constexpr dart::compiler::target::word Isolate_single_step_offset = 64;
 static constexpr dart::compiler::target::word Isolate_user_tag_offset = 16;
 static constexpr dart::compiler::target::word LinkedHashMap_data_offset = 16;
 static constexpr dart::compiler::target::word
@@ -339,8 +341,6 @@
 static constexpr dart::compiler::target::word ClassTable_elements_start_offset =
     0;
 static constexpr dart::compiler::target::word ClassTable_element_size = 168;
-static constexpr dart::compiler::target::word
-    ClassTable_class_heap_stats_table_offset = 16;
 static constexpr dart::compiler::target::word Code_entry_point_offset[] = {
     4, 12, 8, 16};
 static constexpr dart::compiler::target::word
@@ -378,8 +378,6 @@
     576460752303423487;
 static constexpr dart::compiler::target::word Array_kMaxNewSpaceElements =
     32765;
-static constexpr dart::compiler::target::word ClassTable_kSizeOfClassPairLog2 =
-    4;
 static constexpr dart::compiler::target::word
     Instructions_kMonomorphicEntryOffsetJIT = 8;
 static constexpr dart::compiler::target::word
@@ -442,7 +440,11 @@
 static constexpr dart::compiler::target::word
     ClassHeapStats_allocated_size_since_gc_new_space_offset = 104;
 static constexpr dart::compiler::target::word ClassHeapStats_state_offset = 272;
+static constexpr dart::compiler::target::word
+    ClassTable_shared_class_table_offset = 40;
 static constexpr dart::compiler::target::word ClassTable_table_offset = 16;
+static constexpr dart::compiler::target::word
+    SharedClassTable_class_heap_stats_table_offset = 0;
 static constexpr dart::compiler::target::word Closure_context_offset = 40;
 static constexpr dart::compiler::target::word
     Closure_delayed_type_arguments_offset = 24;
@@ -495,12 +497,12 @@
 static constexpr dart::compiler::target::word ICData_state_bits_offset = 52;
 static constexpr dart::compiler::target::word
     ICData_receivers_static_type_offset = 32;
-static constexpr dart::compiler::target::word Isolate_class_table_offset = 72;
+static constexpr dart::compiler::target::word Isolate_class_table_offset = 80;
 static constexpr dart::compiler::target::word Isolate_current_tag_offset = 40;
 static constexpr dart::compiler::target::word Isolate_default_tag_offset = 48;
 static constexpr dart::compiler::target::word Isolate_ic_miss_code_offset = 56;
-static constexpr dart::compiler::target::word Isolate_object_store_offset = 64;
-static constexpr dart::compiler::target::word Isolate_single_step_offset = 112;
+static constexpr dart::compiler::target::word Isolate_object_store_offset = 72;
+static constexpr dart::compiler::target::word Isolate_single_step_offset = 128;
 static constexpr dart::compiler::target::word Isolate_user_tag_offset = 32;
 static constexpr dart::compiler::target::word LinkedHashMap_data_offset = 32;
 static constexpr dart::compiler::target::word
@@ -698,8 +700,6 @@
 static constexpr dart::compiler::target::word ClassTable_elements_start_offset =
     0;
 static constexpr dart::compiler::target::word ClassTable_element_size = 288;
-static constexpr dart::compiler::target::word
-    ClassTable_class_heap_stats_table_offset = 32;
 static constexpr dart::compiler::target::word Code_entry_point_offset[] = {
     8, 24, 16, 32};
 static constexpr dart::compiler::target::word
@@ -736,8 +736,6 @@
 static constexpr dart::compiler::target::word Array_kMaxElements = 268435455;
 static constexpr dart::compiler::target::word Array_kMaxNewSpaceElements =
     65533;
-static constexpr dart::compiler::target::word ClassTable_kSizeOfClassPairLog2 =
-    3;
 static constexpr dart::compiler::target::word
     Instructions_kMonomorphicEntryOffsetJIT = 6;
 static constexpr dart::compiler::target::word
@@ -799,7 +797,11 @@
 static constexpr dart::compiler::target::word
     ClassHeapStats_allocated_size_since_gc_new_space_offset = 52;
 static constexpr dart::compiler::target::word ClassHeapStats_state_offset = 160;
+static constexpr dart::compiler::target::word
+    ClassTable_shared_class_table_offset = 20;
 static constexpr dart::compiler::target::word ClassTable_table_offset = 8;
+static constexpr dart::compiler::target::word
+    SharedClassTable_class_heap_stats_table_offset = 0;
 static constexpr dart::compiler::target::word Closure_context_offset = 20;
 static constexpr dart::compiler::target::word
     Closure_delayed_type_arguments_offset = 12;
@@ -852,12 +854,12 @@
 static constexpr dart::compiler::target::word ICData_state_bits_offset = 28;
 static constexpr dart::compiler::target::word
     ICData_receivers_static_type_offset = 16;
-static constexpr dart::compiler::target::word Isolate_class_table_offset = 36;
+static constexpr dart::compiler::target::word Isolate_class_table_offset = 40;
 static constexpr dart::compiler::target::word Isolate_current_tag_offset = 20;
 static constexpr dart::compiler::target::word Isolate_default_tag_offset = 24;
 static constexpr dart::compiler::target::word Isolate_ic_miss_code_offset = 28;
-static constexpr dart::compiler::target::word Isolate_object_store_offset = 32;
-static constexpr dart::compiler::target::word Isolate_single_step_offset = 56;
+static constexpr dart::compiler::target::word Isolate_object_store_offset = 36;
+static constexpr dart::compiler::target::word Isolate_single_step_offset = 64;
 static constexpr dart::compiler::target::word Isolate_user_tag_offset = 16;
 static constexpr dart::compiler::target::word LinkedHashMap_data_offset = 16;
 static constexpr dart::compiler::target::word
@@ -1053,8 +1055,6 @@
 static constexpr dart::compiler::target::word ClassTable_elements_start_offset =
     0;
 static constexpr dart::compiler::target::word ClassTable_element_size = 168;
-static constexpr dart::compiler::target::word
-    ClassTable_class_heap_stats_table_offset = 16;
 static constexpr dart::compiler::target::word Code_entry_point_offset[] = {
     4, 12, 8, 16};
 static constexpr dart::compiler::target::word
@@ -1088,8 +1088,6 @@
     576460752303423487;
 static constexpr dart::compiler::target::word Array_kMaxNewSpaceElements =
     32765;
-static constexpr dart::compiler::target::word ClassTable_kSizeOfClassPairLog2 =
-    4;
 static constexpr dart::compiler::target::word
     Instructions_kMonomorphicEntryOffsetJIT = 8;
 static constexpr dart::compiler::target::word
@@ -1152,7 +1150,11 @@
 static constexpr dart::compiler::target::word
     ClassHeapStats_allocated_size_since_gc_new_space_offset = 104;
 static constexpr dart::compiler::target::word ClassHeapStats_state_offset = 272;
+static constexpr dart::compiler::target::word
+    ClassTable_shared_class_table_offset = 40;
 static constexpr dart::compiler::target::word ClassTable_table_offset = 16;
+static constexpr dart::compiler::target::word
+    SharedClassTable_class_heap_stats_table_offset = 0;
 static constexpr dart::compiler::target::word Closure_context_offset = 40;
 static constexpr dart::compiler::target::word
     Closure_delayed_type_arguments_offset = 24;
@@ -1205,12 +1207,12 @@
 static constexpr dart::compiler::target::word ICData_state_bits_offset = 52;
 static constexpr dart::compiler::target::word
     ICData_receivers_static_type_offset = 32;
-static constexpr dart::compiler::target::word Isolate_class_table_offset = 72;
+static constexpr dart::compiler::target::word Isolate_class_table_offset = 80;
 static constexpr dart::compiler::target::word Isolate_current_tag_offset = 40;
 static constexpr dart::compiler::target::word Isolate_default_tag_offset = 48;
 static constexpr dart::compiler::target::word Isolate_ic_miss_code_offset = 56;
-static constexpr dart::compiler::target::word Isolate_object_store_offset = 64;
-static constexpr dart::compiler::target::word Isolate_single_step_offset = 112;
+static constexpr dart::compiler::target::word Isolate_object_store_offset = 72;
+static constexpr dart::compiler::target::word Isolate_single_step_offset = 128;
 static constexpr dart::compiler::target::word Isolate_user_tag_offset = 32;
 static constexpr dart::compiler::target::word LinkedHashMap_data_offset = 32;
 static constexpr dart::compiler::target::word
@@ -1408,8 +1410,6 @@
 static constexpr dart::compiler::target::word ClassTable_elements_start_offset =
     0;
 static constexpr dart::compiler::target::word ClassTable_element_size = 288;
-static constexpr dart::compiler::target::word
-    ClassTable_class_heap_stats_table_offset = 32;
 static constexpr dart::compiler::target::word Code_entry_point_offset[] = {
     8, 24, 16, 32};
 static constexpr dart::compiler::target::word
@@ -1448,8 +1448,6 @@
     576460752303423487;
 static constexpr dart::compiler::target::word Array_kMaxNewSpaceElements =
     32765;
-static constexpr dart::compiler::target::word ClassTable_kSizeOfClassPairLog2 =
-    4;
 static constexpr dart::compiler::target::word
     Instructions_kMonomorphicEntryOffsetJIT = 0;
 static constexpr dart::compiler::target::word
@@ -1512,7 +1510,11 @@
 static constexpr dart::compiler::target::word
     ClassHeapStats_allocated_size_since_gc_new_space_offset = 104;
 static constexpr dart::compiler::target::word ClassHeapStats_state_offset = 272;
+static constexpr dart::compiler::target::word
+    ClassTable_shared_class_table_offset = 40;
 static constexpr dart::compiler::target::word ClassTable_table_offset = 16;
+static constexpr dart::compiler::target::word
+    SharedClassTable_class_heap_stats_table_offset = 0;
 static constexpr dart::compiler::target::word Closure_context_offset = 40;
 static constexpr dart::compiler::target::word
     Closure_delayed_type_arguments_offset = 24;
@@ -1565,12 +1567,12 @@
 static constexpr dart::compiler::target::word ICData_state_bits_offset = 52;
 static constexpr dart::compiler::target::word
     ICData_receivers_static_type_offset = 32;
-static constexpr dart::compiler::target::word Isolate_class_table_offset = 72;
+static constexpr dart::compiler::target::word Isolate_class_table_offset = 80;
 static constexpr dart::compiler::target::word Isolate_current_tag_offset = 40;
 static constexpr dart::compiler::target::word Isolate_default_tag_offset = 48;
 static constexpr dart::compiler::target::word Isolate_ic_miss_code_offset = 56;
-static constexpr dart::compiler::target::word Isolate_object_store_offset = 64;
-static constexpr dart::compiler::target::word Isolate_single_step_offset = 112;
+static constexpr dart::compiler::target::word Isolate_object_store_offset = 72;
+static constexpr dart::compiler::target::word Isolate_single_step_offset = 128;
 static constexpr dart::compiler::target::word Isolate_user_tag_offset = 32;
 static constexpr dart::compiler::target::word LinkedHashMap_data_offset = 32;
 static constexpr dart::compiler::target::word
@@ -1700,8 +1702,6 @@
 static constexpr dart::compiler::target::word ClassTable_elements_start_offset =
     0;
 static constexpr dart::compiler::target::word ClassTable_element_size = 288;
-static constexpr dart::compiler::target::word
-    ClassTable_class_heap_stats_table_offset = 32;
 static constexpr dart::compiler::target::word Code_entry_point_offset[] = {
     8, 24, 16, 32};
 static constexpr dart::compiler::target::word
@@ -1734,8 +1734,6 @@
 static constexpr dart::compiler::target::word Array_kMaxElements = 268435455;
 static constexpr dart::compiler::target::word Array_kMaxNewSpaceElements =
     65533;
-static constexpr dart::compiler::target::word ClassTable_kSizeOfClassPairLog2 =
-    3;
 static constexpr dart::compiler::target::word
     Instructions_kMonomorphicEntryOffsetJIT = 0;
 static constexpr dart::compiler::target::word
@@ -1797,7 +1795,11 @@
 static constexpr dart::compiler::target::word
     ClassHeapStats_allocated_size_since_gc_new_space_offset = 52;
 static constexpr dart::compiler::target::word ClassHeapStats_state_offset = 160;
+static constexpr dart::compiler::target::word
+    ClassTable_shared_class_table_offset = 20;
 static constexpr dart::compiler::target::word ClassTable_table_offset = 8;
+static constexpr dart::compiler::target::word
+    SharedClassTable_class_heap_stats_table_offset = 0;
 static constexpr dart::compiler::target::word Closure_context_offset = 20;
 static constexpr dart::compiler::target::word
     Closure_delayed_type_arguments_offset = 12;
@@ -1850,12 +1852,12 @@
 static constexpr dart::compiler::target::word ICData_state_bits_offset = 28;
 static constexpr dart::compiler::target::word
     ICData_receivers_static_type_offset = 16;
-static constexpr dart::compiler::target::word Isolate_class_table_offset = 36;
+static constexpr dart::compiler::target::word Isolate_class_table_offset = 40;
 static constexpr dart::compiler::target::word Isolate_current_tag_offset = 20;
 static constexpr dart::compiler::target::word Isolate_default_tag_offset = 24;
 static constexpr dart::compiler::target::word Isolate_ic_miss_code_offset = 28;
-static constexpr dart::compiler::target::word Isolate_object_store_offset = 32;
-static constexpr dart::compiler::target::word Isolate_single_step_offset = 56;
+static constexpr dart::compiler::target::word Isolate_object_store_offset = 36;
+static constexpr dart::compiler::target::word Isolate_single_step_offset = 64;
 static constexpr dart::compiler::target::word Isolate_user_tag_offset = 16;
 static constexpr dart::compiler::target::word LinkedHashMap_data_offset = 16;
 static constexpr dart::compiler::target::word
@@ -1984,8 +1986,6 @@
 static constexpr dart::compiler::target::word ClassTable_elements_start_offset =
     0;
 static constexpr dart::compiler::target::word ClassTable_element_size = 168;
-static constexpr dart::compiler::target::word
-    ClassTable_class_heap_stats_table_offset = 16;
 static constexpr dart::compiler::target::word Code_entry_point_offset[] = {
     4, 12, 8, 16};
 static constexpr dart::compiler::target::word
diff --git a/runtime/vm/compiler/runtime_offsets_list.h b/runtime/vm/compiler/runtime_offsets_list.h
index f67e729..eb574eb 100644
--- a/runtime/vm/compiler/runtime_offsets_list.h
+++ b/runtime/vm/compiler/runtime_offsets_list.h
@@ -34,7 +34,6 @@
   ARRAY(ObjectPool, element_offset)                                            \
   CONSTANT(Array, kMaxElements)                                                \
   CONSTANT(Array, kMaxNewSpaceElements)                                        \
-  CONSTANT(ClassTable, kSizeOfClassPairLog2)                                   \
   CONSTANT(Instructions, kMonomorphicEntryOffsetJIT)                           \
   CONSTANT(Instructions, kPolymorphicEntryOffsetJIT)                           \
   CONSTANT(Instructions, kMonomorphicEntryOffsetAOT)                           \
@@ -71,7 +70,9 @@
   NOT_IN_PRODUCT(                                                              \
       FIELD(ClassHeapStats, allocated_size_since_gc_new_space_offset))         \
   NOT_IN_PRODUCT(FIELD(ClassHeapStats, state_offset))                          \
+  FIELD(ClassTable, shared_class_table_offset)                                 \
   FIELD(ClassTable, table_offset)                                              \
+  NOT_IN_PRODUCT(FIELD(SharedClassTable, class_heap_stats_table_offset))       \
   FIELD(Closure, context_offset)                                               \
   FIELD(Closure, delayed_type_arguments_offset)                                \
   FIELD(Closure, function_offset)                                              \
@@ -244,7 +245,6 @@
   NOT_IN_PRODUCT(ARRAY_STRUCTFIELD(                                            \
       ClassTable, NewSpaceSizeOffsetFor, ClassOffsetFor,                       \
       ClassHeapStats::allocated_size_since_gc_new_space_offset()))             \
-  NOT_IN_PRODUCT(FIELD(ClassTable, class_heap_stats_table_offset))             \
   RANGE(Code, entry_point_offset, CodeEntryKind, CodeEntryKind::kNormal,       \
         CodeEntryKind::kMonomorphicUnchecked,                                  \
         [](CodeEntryKind value) { return true; })                              \
diff --git a/runtime/vm/compiler/stub_code_compiler_arm64.cc b/runtime/vm/compiler/stub_code_compiler_arm64.cc
index c565ba5..16746a5 100644
--- a/runtime/vm/compiler/stub_code_compiler_arm64.cc
+++ b/runtime/vm/compiler/stub_code_compiler_arm64.cc
@@ -2796,12 +2796,8 @@
   // Non-Closure handling.
   {
     __ Bind(&not_closure);
-    if (n == 1) {
-      __ SmiTag(kInstanceCidOrFunction);
-    } else {
-      ASSERT(n >= 2);
+    if (n >= 2) {
       Label has_no_type_arguments;
-      // [LoadClassById] also tags [kInstanceCidOrFunction] as a side-effect.
       __ LoadClassById(R5, kInstanceCidOrFunction);
       __ mov(kInstanceInstantiatorTypeArgumentsReg, kNullReg);
       __ LoadFieldFromOffset(
@@ -2818,6 +2814,7 @@
         __ mov(kInstanceDelayedFunctionTypeArgumentsReg, kNullReg);
       }
     }
+    __ SmiTag(kInstanceCidOrFunction);
   }
 
   Label found, not_found, next_iteration;
diff --git a/runtime/vm/compiler/stub_code_compiler_x64.cc b/runtime/vm/compiler/stub_code_compiler_x64.cc
index 7ac6ced..b376b02 100644
--- a/runtime/vm/compiler/stub_code_compiler_x64.cc
+++ b/runtime/vm/compiler/stub_code_compiler_x64.cc
@@ -2782,12 +2782,8 @@
   // Non-Closure handling.
   {
     __ Bind(&not_closure);
-    if (n == 1) {
-      __ SmiTag(kInstanceCidOrFunction);
-    } else {
-      ASSERT(n >= 2);
+    if (n >= 2) {
       Label has_no_type_arguments;
-      // [LoadClassById] also tags [kInstanceCidOrFunction] as a side-effect.
       __ LoadClassById(RDI, kInstanceCidOrFunction);
       __ movq(kInstanceInstantiatorTypeArgumentsReg, kNullReg);
       __ movl(
@@ -2806,6 +2802,7 @@
         __ movq(kInstanceDelayedFunctionTypeArgumentsReg, kNullReg);
       }
     }
+    __ SmiTag(kInstanceCidOrFunction);
   }
 
   Label found, not_found, next_iteration;
diff --git a/runtime/vm/dart.cc b/runtime/vm/dart.cc
index 59f903a..0463a15 100644
--- a/runtime/vm/dart.cc
+++ b/runtime/vm/dart.cc
@@ -859,14 +859,6 @@
 #else
 #error What architecture?
 #endif
-  } else {
-#if defined(ARCH_IS_32_BIT)
-    buffer.AddString(" 32-bit");
-#elif defined(ARCH_IS_64_BIT)
-    buffer.AddString(" 64-bit");
-#else
-#error What word size?
-#endif
   }
 
   if (FLAG_precompiled_mode && FLAG_dwarf_stack_traces) {
diff --git a/runtime/vm/dart_api_impl.cc b/runtime/vm/dart_api_impl.cc
index 4b259aa..4c62313 100644
--- a/runtime/vm/dart_api_impl.cc
+++ b/runtime/vm/dart_api_impl.cc
@@ -1666,21 +1666,10 @@
 
   Symbols::Compact();
 
-  uint8_t* vm_snapshot_instruction_buffer = nullptr;
-  BlobImageWriter vm_image_writer(T, &vm_snapshot_instruction_buffer,
-                                  ApiReallocate, 2 * MB /* initial_size */,
-                                  /*shared_objects=*/nullptr,
-                                  /*shared_instructions=*/nullptr,
-                                  /*reused_instructions=*/nullptr);
-  uint8_t* isolate_snapshot_instruction_buffer = nullptr;
-  BlobImageWriter isolate_image_writer(T, &isolate_snapshot_instruction_buffer,
-                                       ApiReallocate, 2 * MB /* initial_size */,
-                                       /*shared_objects=*/nullptr,
-                                       /*shared_instructions=*/nullptr,
-                                       /*reused_instructions=*/nullptr);
   FullSnapshotWriter writer(Snapshot::kFull, vm_snapshot_data_buffer,
                             isolate_snapshot_data_buffer, ApiReallocate,
-                            &vm_image_writer, &isolate_image_writer);
+                            NULL /* vm_image_writer */,
+                            NULL /* isolate_image_writer */);
   writer.WriteFullSnapshot();
   if (vm_snapshot_data_buffer != NULL) {
     *vm_snapshot_data_size = writer.VmIsolateSnapshotSize();
diff --git a/runtime/vm/debugger.cc b/runtime/vm/debugger.cc
index 0dd231a..6e3bcc2 100644
--- a/runtime/vm/debugger.cc
+++ b/runtime/vm/debugger.cc
@@ -637,13 +637,14 @@
   }
 }
 
-// Compute token_pos_ and token_pos_initialized_.
-// If not IsInterpreted(), then also compute try_index_ and deopt_id_.
+// If not token_pos_initialized_, compute token_pos_, try_index_ and,
+// if not IsInterpreted(), also compute deopt_id_.
 TokenPosition ActivationFrame::TokenPos() {
   if (!token_pos_initialized_) {
     token_pos_initialized_ = true;
     if (IsInterpreted()) {
       token_pos_ = bytecode().GetTokenIndexOfPC(pc_);
+      try_index_ = bytecode().GetTryIndexAtPc(pc_);
       return token_pos_;
     }
     token_pos_ = TokenPosition::kNoSource;
@@ -663,16 +664,6 @@
 }
 
 intptr_t ActivationFrame::TryIndex() {
-#if !defined(DART_PRECOMPILED_RUNTIME)
-  if (IsInterpreted()) {
-    if (pc_desc_.IsNull()) {
-      ASSERT(try_index_ == -1);
-      pc_desc_ = bytecode().pc_descriptors();
-      try_index_ = bytecode().GetTryIndexAtPc(pc_);
-    }
-    return try_index_;
-  }
-#endif  // !defined(DART_PRECOMPILED_RUNTIME)
   if (!token_pos_initialized_) {
     TokenPos();  // Side effect: computes token_pos_initialized_, try_index_.
   }
@@ -2467,9 +2458,9 @@
           // Grab the awaiter.
           async_activation ^= activation->GetAsyncAwaiter();
           async_stack_trace ^= activation->GetCausalStack();
-          // see comment regarding skipping frames of async functions called
-          // synchronously above.
-          skip_sync_async_frames_count = 2;
+          // Interpreted bytecode does not invoke _ClosureCall().
+          // Skip _AsyncAwaitCompleterStart() only.
+          skip_sync_async_frames_count = 1;
         } else {
           stack_trace->AddActivation(
               CollectDartFrame(isolate, frame->pc(), frame, bytecode));
diff --git a/runtime/vm/heap/heap.cc b/runtime/vm/heap/heap.cc
index 2e9d7f4..33487fb 100644
--- a/runtime/vm/heap/heap.cc
+++ b/runtime/vm/heap/heap.cc
@@ -885,10 +885,10 @@
   for (int sel = 0; sel < Heap::kNumWeakSelectors; sel++) {
     const auto selector = static_cast<Heap::WeakSelector>(sel);
     auto before_table = GetWeakTable(before_space, selector);
-    intptr_t entry = before_table->RemoveValue(before_object);
+    intptr_t entry = before_table->RemoveValueExclusive(before_object);
     if (entry != 0) {
       auto after_table = GetWeakTable(after_space, selector);
-      after_table->SetValue(after_object, entry);
+      after_table->SetValueExclusive(after_object, entry);
     }
   }
 
diff --git a/runtime/vm/heap/heap_test.cc b/runtime/vm/heap/heap_test.cc
index c79848e..a456287 100644
--- a/runtime/vm/heap/heap_test.cc
+++ b/runtime/vm/heap/heap_test.cc
@@ -82,7 +82,7 @@
  public:
   static ClassHeapStats* GetHeapStatsForCid(ClassTable* class_table,
                                             intptr_t cid) {
-    return class_table->PreliminaryStatsAt(cid);
+    return class_table->shared_class_table()->PreliminaryStatsAt(cid);
   }
 
   static void DumpClassHeapStats(ClassHeapStats* stats) {
diff --git a/runtime/vm/heap/marker.cc b/runtime/vm/heap/marker.cc
index be5a212..5558aa8 100644
--- a/runtime/vm/heap/marker.cc
+++ b/runtime/vm/heap/marker.cc
@@ -90,7 +90,7 @@
       : ObjectPointerVisitor(isolate),
         thread_(Thread::Current()),
 #ifndef PRODUCT
-        num_classes_(isolate->class_table()->Capacity()),
+        num_classes_(isolate->shared_class_table()->Capacity()),
         class_stats_count_(new intptr_t[num_classes_]),
         class_stats_size_(new intptr_t[num_classes_]),
 #endif  // !PRODUCT
@@ -372,7 +372,8 @@
 class MarkingWeakVisitor : public HandleVisitor {
  public:
   explicit MarkingWeakVisitor(Thread* thread)
-      : HandleVisitor(thread), class_table_(thread->isolate()->class_table()) {}
+      : HandleVisitor(thread),
+        class_table_(thread->isolate()->shared_class_table()) {}
 
   void VisitHandle(uword addr) {
     FinalizablePersistentHandle* handle =
@@ -394,7 +395,7 @@
   }
 
  private:
-  ClassTable* class_table_;
+  SharedClassTable* class_table_;
 
   DISALLOW_COPY_AND_ASSIGN(MarkingWeakVisitor);
 };
@@ -500,11 +501,11 @@
         heap_->GetWeakTable(Heap::kOld, static_cast<Heap::WeakSelector>(sel));
     intptr_t size = table->size();
     for (intptr_t i = 0; i < size; i++) {
-      if (table->IsValidEntryAt(i)) {
-        RawObject* raw_obj = table->ObjectAt(i);
+      if (table->IsValidEntryAtExclusive(i)) {
+        RawObject* raw_obj = table->ObjectAtExclusive(i);
         ASSERT(raw_obj->IsHeapObject());
         if (!raw_obj->IsMarked()) {
-          table->InvalidateAt(i);
+          table->InvalidateAtExclusive(i);
         }
       }
     }
@@ -724,7 +725,7 @@
 #ifndef PRODUCT
     // Class heap stats are not themselves thread-safe yet, so we update the
     // stats while holding stats_mutex_.
-    ClassTable* table = heap_->isolate()->class_table();
+    auto table = heap_->isolate()->shared_class_table();
     for (intptr_t i = 0; i < table->NumCids(); ++i) {
       const intptr_t count = visitor->live_count(i);
       if (count > 0) {
diff --git a/runtime/vm/heap/pages.cc b/runtime/vm/heap/pages.cc
index 4a85864..88222d0 100644
--- a/runtime/vm/heap/pages.cc
+++ b/runtime/vm/heap/pages.cc
@@ -541,7 +541,8 @@
   intptr_t size_in_words = size >> kWordSizeLog2;
   AtomicOperations::IncrementBy(&(usage_.external_in_words), size_in_words);
   NOT_IN_PRODUCT(
-      heap_->isolate()->class_table()->UpdateAllocatedExternalOld(cid, size));
+      heap_->isolate()->shared_class_table()->UpdateAllocatedExternalOld(cid,
+                                                                         size));
 }
 
 void PageSpace::PromoteExternal(intptr_t cid, intptr_t size) {
@@ -1097,7 +1098,7 @@
     return;
   }
 
-  NOT_IN_PRODUCT(isolate->class_table()->ResetCountersOld());
+  NOT_IN_PRODUCT(isolate->shared_class_table()->ResetCountersOld());
   marker_->MarkObjects(this);
   usage_.used_in_words = marker_->marked_words() + allocated_black_in_words_;
   allocated_black_in_words_ = 0;
diff --git a/runtime/vm/heap/scavenger.cc b/runtime/vm/heap/scavenger.cc
index accb638..b92a870 100644
--- a/runtime/vm/heap/scavenger.cc
+++ b/runtime/vm/heap/scavenger.cc
@@ -281,7 +281,7 @@
   ScavengerWeakVisitor(Thread* thread, Scavenger* scavenger)
       : HandleVisitor(thread),
         scavenger_(scavenger),
-        class_table_(thread->isolate()->class_table()) {
+        class_table_(thread->isolate()->shared_class_table()) {
     ASSERT(scavenger->heap_->isolate() == thread->isolate());
   }
 
@@ -307,7 +307,7 @@
 
  private:
   Scavenger* scavenger_;
-  ClassTable* class_table_;
+  SharedClassTable* class_table_;
 
   DISALLOW_COPY_AND_ASSIGN(ScavengerWeakVisitor);
 };
@@ -486,7 +486,7 @@
 }
 
 SemiSpace* Scavenger::Prologue(Isolate* isolate) {
-  NOT_IN_PRODUCT(isolate->class_table()->ResetCountersNew());
+  NOT_IN_PRODUCT(isolate->shared_class_table()->ResetCountersNew());
 
   isolate->ReleaseStoreBuffers();
   AbandonTLABs(isolate);
@@ -593,7 +593,7 @@
     heap_->UpdateGlobalMaxUsed();
   }
 
-  NOT_IN_PRODUCT(isolate->class_table()->UpdatePromoted());
+  NOT_IN_PRODUCT(isolate->shared_class_table()->UpdatePromoted());
 }
 
 bool Scavenger::ShouldPerformIdleScavenge(int64_t deadline) {
@@ -708,7 +708,7 @@
 
 void Scavenger::ProcessToSpace(ScavengerVisitor* visitor) {
   Thread* thread = Thread::Current();
-  NOT_IN_PRODUCT(ClassTable* class_table = thread->isolate()->class_table());
+  NOT_IN_PRODUCT(auto class_table = visitor->isolate()->shared_class_table());
 
   // Iterate until all work has been drained.
   while ((resolved_top_ < top_) || PromotedStackHasMore()) {
@@ -851,8 +851,8 @@
                               WeakTable* replacement_old) {
     intptr_t size = table->size();
     for (intptr_t i = 0; i < size; i++) {
-      if (table->IsValidEntryAt(i)) {
-        RawObject* raw_obj = table->ObjectAt(i);
+      if (table->IsValidEntryAtExclusive(i)) {
+        RawObject* raw_obj = table->ObjectAtExclusive(i);
         ASSERT(raw_obj->IsHeapObject());
         uword raw_addr = RawObject::ToAddr(raw_obj);
         uword header = *reinterpret_cast<uword*>(raw_addr);
@@ -862,7 +862,7 @@
           raw_obj = RawObject::FromAddr(new_addr);
           auto replacement =
               raw_obj->IsNewObject() ? replacement_new : replacement_old;
-          replacement->SetValue(raw_obj, table->ValueAt(i));
+          replacement->SetValueExclusive(raw_obj, table->ValueAtExclusive(i));
         }
       }
     }
@@ -1161,7 +1161,8 @@
   ASSERT(size >= 0);
   external_size_ += size;
   NOT_IN_PRODUCT(
-      heap_->isolate()->class_table()->UpdateAllocatedExternalNew(cid, size));
+      heap_->isolate()->shared_class_table()->UpdateAllocatedExternalNew(cid,
+                                                                         size));
 }
 
 void Scavenger::FreeExternal(intptr_t size) {
diff --git a/runtime/vm/heap/weak_table.cc b/runtime/vm/heap/weak_table.cc
index 4fd7917..95acc86 100644
--- a/runtime/vm/heap/weak_table.cc
+++ b/runtime/vm/heap/weak_table.cc
@@ -29,11 +29,11 @@
   return result;
 }
 
-void WeakTable::SetValue(RawObject* key, intptr_t val) {
+void WeakTable::SetValueExclusive(RawObject* key, intptr_t val) {
   intptr_t mask = size() - 1;
   intptr_t idx = Hash(key) & mask;
   intptr_t empty_idx = -1;
-  RawObject* obj = ObjectAt(idx);
+  RawObject* obj = ObjectAtExclusive(idx);
 
   while (obj != NULL) {
     if (obj == key) {
@@ -44,7 +44,7 @@
       empty_idx = idx;  // Insert at this location if not found.
     }
     idx = (idx + 1) & mask;
-    obj = ObjectAt(idx);
+    obj = ObjectAtExclusive(idx);
   }
 
   if (val == 0) {
@@ -60,7 +60,7 @@
     idx = empty_idx;
   }
 
-  ASSERT(!IsValidEntryAt(idx));
+  ASSERT(!IsValidEntryAtExclusive(idx));
   // Set the key and value.
   SetObjectAt(idx, key);
   SetValueAt(idx, val);
@@ -87,7 +87,7 @@
   if (used_ == 0) return;
 
   for (intptr_t i = 0; i < size_; i++) {
-    if (IsValidEntryAt(i)) {
+    if (IsValidEntryAtExclusive(i)) {
       visitor->VisitPointer(ObjectPointerAt(i));
     }
   }
@@ -107,9 +107,9 @@
   intptr_t mask = new_size - 1;
   set_used(0);
   for (intptr_t i = 0; i < old_size; i++) {
-    if (IsValidEntryAt(i)) {
+    if (IsValidEntryAtExclusive(i)) {
       // Find the new hash location for this entry.
-      RawObject* key = ObjectAt(i);
+      RawObject* key = ObjectAtExclusive(i);
       intptr_t idx = Hash(key) & mask;
       RawObject* obj = reinterpret_cast<RawObject*>(new_data[ObjectIndex(idx)]);
       while (obj != NULL) {
@@ -119,7 +119,7 @@
       }
 
       new_data[ObjectIndex(idx)] = reinterpret_cast<intptr_t>(key);
-      new_data[ValueIndex(idx)] = ValueAt(i);
+      new_data[ValueIndex(idx)] = ValueAtExclusive(i);
       set_used(used() + 1);
     }
   }
diff --git a/runtime/vm/heap/weak_table.h b/runtime/vm/heap/weak_table.h
index c7970cf..c1487b1 100644
--- a/runtime/vm/heap/weak_table.h
+++ b/runtime/vm/heap/weak_table.h
@@ -8,6 +8,7 @@
 #include "vm/globals.h"
 
 #include "platform/assert.h"
+#include "vm/lockers.h"
 #include "vm/raw_object.h"
 
 namespace dart {
@@ -46,64 +47,82 @@
   intptr_t used() const { return used_; }
   intptr_t count() const { return count_; }
 
-  bool IsValidEntryAt(intptr_t i) const {
-    ASSERT(((ValueAt(i) == 0) && ((ObjectAt(i) == NULL) ||
-                                  (data_[ObjectIndex(i)] == kDeletedEntry))) ||
-           ((ValueAt(i) != 0) && (ObjectAt(i) != NULL) &&
-            (data_[ObjectIndex(i)] != kDeletedEntry)));
+  // The following methods can be called concurrently and are guarded by a lock.
+
+  intptr_t GetValue(RawObject* key) {
+    MutexLocker ml(&mutex_);
+    return GetValueExclusive(key);
+  }
+
+  void SetValue(RawObject* key, intptr_t val) {
+    MutexLocker ml(&mutex_);
+    return SetValueExclusive(key, val);
+  }
+
+  // The following "exclusive" methods must only be called from call sites
+  // which are known to have exclusive access to the weak table.
+  //
+  // This is mostly limited to GC related code (e.g. scavenger, marker, ...)
+
+  bool IsValidEntryAtExclusive(intptr_t i) const {
+    ASSERT((ValueAtExclusive(i) == 0 &&
+            (ObjectAtExclusive(i) == NULL ||
+             data_[ObjectIndex(i)] == kDeletedEntry)) ||
+           (ValueAtExclusive(i) != 0 && ObjectAtExclusive(i) != NULL &&
+            data_[ObjectIndex(i)] != kDeletedEntry));
     return (data_[ValueIndex(i)] != 0);
   }
 
-  void InvalidateAt(intptr_t i) {
-    ASSERT(IsValidEntryAt(i));
+  void InvalidateAtExclusive(intptr_t i) {
+    ASSERT(IsValidEntryAtExclusive(i));
     SetValueAt(i, 0);
   }
 
-  RawObject* ObjectAt(intptr_t i) const {
+  RawObject* ObjectAtExclusive(intptr_t i) const {
     ASSERT(i >= 0);
     ASSERT(i < size());
     return reinterpret_cast<RawObject*>(data_[ObjectIndex(i)]);
   }
 
-  intptr_t ValueAt(intptr_t i) const {
+  intptr_t ValueAtExclusive(intptr_t i) const {
     ASSERT(i >= 0);
     ASSERT(i < size());
     return data_[ValueIndex(i)];
   }
 
-  void SetValue(RawObject* key, intptr_t val);
+  void SetValueExclusive(RawObject* key, intptr_t val);
 
-  intptr_t GetValue(RawObject* key) const {
+  intptr_t GetValueExclusive(RawObject* key) const {
     intptr_t mask = size() - 1;
     intptr_t idx = Hash(key) & mask;
-    RawObject* obj = ObjectAt(idx);
+    RawObject* obj = ObjectAtExclusive(idx);
     while (obj != NULL) {
       if (obj == key) {
-        return ValueAt(idx);
+        return ValueAtExclusive(idx);
       }
       idx = (idx + 1) & mask;
-      obj = ObjectAt(idx);
+      obj = ObjectAtExclusive(idx);
     }
-    ASSERT(ValueAt(idx) == 0);
+    ASSERT(ValueAtExclusive(idx) == 0);
     return 0;
   }
 
   // Removes and returns the value associated with |key|. Returns 0 if there is
   // no value associated with |key|.
-  intptr_t RemoveValue(RawObject* key) {
+  intptr_t RemoveValueExclusive(RawObject* key) {
     intptr_t mask = size() - 1;
     intptr_t idx = Hash(key) & mask;
-    RawObject* obj = ObjectAt(idx);
+    RawObject* obj = ObjectAtExclusive(idx);
     while (obj != NULL) {
       if (obj == key) {
-        intptr_t result = ValueAt(idx);
-        InvalidateAt(idx);
+        intptr_t result = ValueAtExclusive(idx);
+        InvalidateAtExclusive(idx);
         return result;
       }
       idx = (idx + 1) & mask;
-      obj = ObjectAt(idx);
+      obj = ObjectAtExclusive(idx);
     }
-    ASSERT(ValueAt(idx) == 0);
+    ASSERT(ValueAtExclusive(idx) == 0);
     return 0;
   }
 
@@ -174,6 +193,8 @@
     return reinterpret_cast<uintptr_t>(key) * 92821;
   }
 
+  Mutex mutex_;
+
   // data_ contains size_ tuples of key/value.
   intptr_t* data_;
   // size_ keeps the number of entries in data_. used_ maintains the number of
diff --git a/runtime/vm/image_snapshot.cc b/runtime/vm/image_snapshot.cc
index 03672dc..c097744 100644
--- a/runtime/vm/image_snapshot.cc
+++ b/runtime/vm/image_snapshot.cc
@@ -1090,6 +1090,7 @@
       shared_data_image_(shared_data_image),
       shared_instructions_image_(shared_instructions_image) {
   ASSERT(data_image != NULL);
+  ASSERT(instructions_image != NULL);
 }
 
 RawApiError* ImageReader::VerifyAlignment() const {
@@ -1106,7 +1107,6 @@
 }
 
 RawInstructions* ImageReader::GetInstructionsAt(int32_t offset) const {
-  ASSERT(instructions_image_ != nullptr);
   ASSERT(Utils::IsAligned(offset, OS::PreferredCodeAlignment()));
 
   RawObject* result;
diff --git a/runtime/vm/interpreter.cc b/runtime/vm/interpreter.cc
index 77bd91d..e4a735a 100644
--- a/runtime/vm/interpreter.cc
+++ b/runtime/vm/interpreter.cc
@@ -264,7 +264,7 @@
                                           RawObject** result) {
   const uword start = thread->top();
 #ifndef PRODUCT
-  ClassTable* table = thread->isolate()->class_table();
+  auto table = thread->isolate()->shared_class_table();
   if (UNLIKELY(table->TraceAllocationFor(class_id))) {
     return false;
   }
diff --git a/runtime/vm/isolate.cc b/runtime/vm/isolate.cc
index c341416..261fde1 100644
--- a/runtime/vm/isolate.cc
+++ b/runtime/vm/isolate.cc
@@ -1050,7 +1050,8 @@
       current_tag_(UserTag::null()),
       default_tag_(UserTag::null()),
       ic_miss_code_(Code::null()),
-      class_table_(),
+      shared_class_table_(new SharedClassTable()),
+      class_table_(shared_class_table_.get()),
       store_buffer_(new StoreBuffer()),
 #if !defined(TARGET_ARCH_DBC) && !defined(DART_PRECOMPILED_RUNTIME)
       native_callback_trampolines_(),
diff --git a/runtime/vm/isolate.h b/runtime/vm/isolate.h
index 48895f3..faef0b3 100644
--- a/runtime/vm/isolate.h
+++ b/runtime/vm/isolate.h
@@ -340,6 +340,9 @@
   SafepointHandler* safepoint_handler() const {
     return group()->safepoint_handler();
   }
+
+  SharedClassTable* shared_class_table() { return shared_class_table_.get(); }
+
   ClassTable* class_table() { return &class_table_; }
   static intptr_t class_table_offset() {
     return OFFSET_OF(Isolate, class_table_);
@@ -1023,6 +1026,7 @@
   RawUserTag* current_tag_;
   RawUserTag* default_tag_;
   RawCode* ic_miss_code_;
+  std::unique_ptr<SharedClassTable> shared_class_table_;
   ObjectStore* object_store_ = nullptr;
   ClassTable class_table_;
   bool single_step_ = false;
diff --git a/runtime/vm/isolate_reload.cc b/runtime/vm/isolate_reload.cc
index 640c358..17fa30e 100644
--- a/runtime/vm/isolate_reload.cc
+++ b/runtime/vm/isolate_reload.cc
@@ -676,9 +676,6 @@
   if (skip_reload) {
     ASSERT(modified_libs_->IsEmpty());
     reload_skipped_ = true;
-    // Inform GetUnusedChangesInLastReload that a reload has happened.
-    I->object_store()->set_changed_in_last_reload(
-        GrowableObjectArray::Handle(GrowableObjectArray::New()));
     ReportOnJSON(js_);
 
     // If we use the CFE and performed a compilation, we need to notify that
@@ -1218,81 +1215,6 @@
 }
 #endif
 
-static void RecordChanges(const GrowableObjectArray& changed_in_last_reload,
-                          const Class& old_cls,
-                          const Class& new_cls) {
-  // All members of enum classes are synthetic, so nothing to report here.
-  if (new_cls.is_enum_class()) {
-    return;
-  }
-
-  // Don't report `typedef bool Predicate(Object o)` as unused. There is nothing
-  // to execute.
-  if (new_cls.IsTypedefClass()) {
-    return;
-  }
-
-  if (new_cls.raw() == old_cls.raw()) {
-    // A new class maps to itself. All its functions, field initizers, and so
-    // on are new.
-    changed_in_last_reload.Add(new_cls);
-    return;
-  }
-
-  if (old_cls.IsTopLevel()) {
-    return;
-  }
-
-  if (!old_cls.is_finalized()) {
-    if (new_cls.SourceFingerprint() == old_cls.SourceFingerprint()) {
-      return;
-    }
-    // We don't know the members. Register interest in the whole class. Creates
-    // false positives.
-    changed_in_last_reload.Add(new_cls);
-    return;
-  }
-  ASSERT(new_cls.is_finalized());
-
-  Zone* zone = Thread::Current()->zone();
-  const Array& functions = Array::Handle(zone, new_cls.functions());
-  const Array& fields = Array::Handle(zone, new_cls.fields());
-  Function& new_function = Function::Handle(zone);
-  Function& old_function = Function::Handle(zone);
-  Field& new_field = Field::Handle(zone);
-  Field& old_field = Field::Handle(zone);
-  String& selector = String::Handle(zone);
-  for (intptr_t i = 0; i < functions.Length(); i++) {
-    new_function ^= functions.At(i);
-    selector = new_function.name();
-    old_function = old_cls.LookupFunction(selector);
-    // If we made live changes with proper structed edits, this would just be
-    // old != new.
-    if (old_function.IsNull() || (new_function.SourceFingerprint() !=
-                                  old_function.SourceFingerprint())) {
-      ASSERT(!new_function.HasCode());
-      ASSERT(new_function.usage_counter() == 0);
-      changed_in_last_reload.Add(new_function);
-    }
-  }
-  for (intptr_t i = 0; i < fields.Length(); i++) {
-    new_field ^= fields.At(i);
-    if (!new_field.is_static()) continue;
-    selector = new_field.name();
-    old_field = old_cls.LookupField(selector);
-    if (old_field.IsNull() || !old_field.is_static()) {
-      // New field.
-      changed_in_last_reload.Add(new_field);
-    } else if (new_field.SourceFingerprint() != old_field.SourceFingerprint()) {
-      // Changed field.
-      changed_in_last_reload.Add(new_field);
-      if (!old_field.IsUninitialized()) {
-        new_field.set_initializer_changed_after_initialization(true);
-      }
-    }
-  }
-}
-
 void IsolateReloadContext::Commit() {
   TIMELINE_SCOPE(Commit);
   TIR_Print("---- COMMITTING RELOAD\n");
@@ -1331,9 +1253,6 @@
     lib_map.Release();
   }
 
-  const GrowableObjectArray& changed_in_last_reload =
-      GrowableObjectArray::Handle(GrowableObjectArray::New());
-
   {
     TIMELINE_SCOPE(CopyStaticFieldsAndPatchFieldsAndFunctions);
     // Copy static field values from the old classes to the new classes.
@@ -1359,7 +1278,6 @@
           old_cls.PatchFieldsAndFunctions();
           old_cls.MigrateImplicitStaticClosures(this, new_cls);
         }
-        RecordChanges(changed_in_last_reload, old_cls, new_cls);
       }
     }
 
@@ -1378,15 +1296,6 @@
     }
   }
 
-  if (FLAG_identity_reload) {
-    Object& changed = Object::Handle();
-    for (intptr_t i = 0; i < changed_in_last_reload.Length(); i++) {
-      changed = changed_in_last_reload.At(i);
-      ASSERT(changed.IsClass());  // Only fuzzy from lazy finalization.
-    }
-  }
-  I->object_store()->set_changed_in_last_reload(changed_in_last_reload);
-
   {
     TIMELINE_SCOPE(UpdateLibrariesArray);
     // Update the libraries array.
diff --git a/runtime/vm/isolate_reload.h b/runtime/vm/isolate_reload.h
index 300195e..b6e0553 100644
--- a/runtime/vm/isolate_reload.h
+++ b/runtime/vm/isolate_reload.h
@@ -145,6 +145,8 @@
   // All zone allocated objects must be allocated from this zone.
   Zone* zone() const { return zone_; }
 
+  bool UseSavedClassTableForGC() const { return saved_class_table_ != nullptr; }
+
   bool reload_skipped() const { return reload_skipped_; }
   bool reload_aborted() const { return reload_aborted_; }
   RawError* error() const;
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index 5dbc67b..c541cd2 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -2202,7 +2202,7 @@
     }
   }
 #ifndef PRODUCT
-  ClassTable* class_table = thread->isolate()->class_table();
+  auto class_table = thread->isolate()->shared_class_table();
   if (space == Heap::kNew) {
     class_table->UpdateAllocatedNew(cls_id, size);
   } else {
@@ -3298,7 +3298,7 @@
 
 bool Class::TraceAllocation(Isolate* isolate) const {
 #ifndef PRODUCT
-  ClassTable* class_table = isolate->class_table();
+  auto class_table = isolate->shared_class_table();
   return class_table->TraceAllocationFor(id());
 #else
   return false;
@@ -3310,7 +3310,7 @@
   Isolate* isolate = Isolate::Current();
   const bool changed = trace_allocation != this->TraceAllocation(isolate);
   if (changed) {
-    ClassTable* class_table = isolate->class_table();
+    auto class_table = isolate->shared_class_table();
     class_table->SetTraceAllocationFor(id(), trace_allocation);
     DisableAllocationStub();
   }
@@ -8104,21 +8104,31 @@
 }
 
 bool Function::CheckSourceFingerprint(const char* prefix, int32_t fp) const {
-  // TODO(36376): Restore checking fingerprints of recognized methods.
-  // '(kernel_offset() <= 0)' looks like an impossible condition, fix this and
-  //  re-enable fingerprints checking.
-  if (!Isolate::Current()->obfuscate() && !is_declared_in_bytecode() &&
-      (kernel_offset() <= 0) && (SourceFingerprint() != fp)) {
+  if (Isolate::Current()->obfuscate() || FLAG_precompiled_mode ||
+      (Dart::vm_snapshot_kind() != Snapshot::kNone)) {
+    return true;  // The kernel structure has been altered, skip checking.
+  }
+
+  if (is_declared_in_bytecode()) {
+    // AST and bytecode compute different fingerprints, and we only track one
+    // fingerprint set.
+    return true;
+  }
+
+  if (SourceFingerprint() != fp) {
     const bool recalculatingFingerprints = false;
     if (recalculatingFingerprints) {
       // This output can be copied into a file, then used with sed
       // to replace the old values.
-      // sed -i.bak -f /tmp/newkeys runtime/vm/compiler/method_recognizer.h
+      // sed -i.bak -f /tmp/newkeys \
+      //    runtime/vm/compiler/recognized_methods_list.h
       THR_Print("s/0x%08x/0x%08x/\n", fp, SourceFingerprint());
     } else {
       THR_Print(
-          "FP mismatch while recognizing method %s:"
-          " expecting 0x%08x found 0x%08x\n",
+          "FP mismatch while recognizing method %s: expecting 0x%08x found "
+          "0x%08x.\nIf the behavior of this function has changed, then changes "
+          "are also needed in the VM's compiler. Otherwise the fingerprint can "
+          "simply be updated in recognized_methods_list.h\n",
           ToFullyQualifiedCString(), fp, SourceFingerprint());
       return false;
     }
diff --git a/runtime/vm/object_store.h b/runtime/vm/object_store.h
index 77461f0..8fab9f4 100644
--- a/runtime/vm/object_store.h
+++ b/runtime/vm/object_store.h
@@ -139,7 +139,6 @@
   R_(Function, megamorphic_miss_function)                                      \
   RW(Array, code_order_table)                                                  \
   RW(Array, obfuscation_map)                                                   \
-  RW(GrowableObjectArray, changed_in_last_reload)                              \
   RW(Class, ffi_pointer_class)                                                 \
   RW(Class, ffi_native_type_class)                                             \
   RW(Class, ffi_struct_class)                                                  \
diff --git a/runtime/vm/profiler_test.cc b/runtime/vm/profiler_test.cc
index 21566b5..65e7a5f 100644
--- a/runtime/vm/profiler_test.cc
+++ b/runtime/vm/profiler_test.cc
@@ -494,7 +494,7 @@
 }
 
 #if defined(DART_USE_TCMALLOC) && defined(HOST_OS_LINUX) && defined(DEBUG) &&  \
-    defined(HOST_ARCH_x64)
+    defined(HOST_ARCH_X64)
 
 DART_NOINLINE static void NativeAllocationSampleHelper(char** result) {
   ASSERT(result != NULL);
@@ -502,12 +502,12 @@
 }
 
 ISOLATE_UNIT_TEST_CASE(Profiler_NativeAllocation) {
-  EnableProfiler();
-
   bool enable_malloc_hooks_saved = FLAG_profiler_native_memory;
   FLAG_profiler_native_memory = true;
 
-  MallocHooks::InitOnce();
+  EnableProfiler();
+
+  MallocHooks::Init();
   MallocHooks::ResetStats();
   bool stack_trace_collection_enabled =
       MallocHooks::stack_trace_collection_enabled();
@@ -536,31 +536,27 @@
     // Filter for the class in the time range.
     NativeAllocationSampleFilter filter(before_allocations_micros,
                                         allocation_extent_micros);
-    profile.Build(thread, &filter, Profiler::sample_buffer());
+    profile.Build(thread, &filter, Profiler::allocation_sample_buffer());
     // We should have 1 allocation sample.
     EXPECT_EQ(1, profile.sample_count());
-    ProfileStackWalker walker(&profile)
+    ProfileStackWalker walker(&profile);
 
-        // Move down from the root.
-        EXPECT(walker.Down());
+    // Move down from the root.
     EXPECT_SUBSTRING("[Native]", walker.CurrentName());
-    EXPECT_EQ(walker.native_allocation_size_bytes(), 1024);
+    EXPECT_EQ(1024ul, profile.SampleAt(0)->native_allocation_size_bytes());
     EXPECT(walker.Down());
     EXPECT_STREQ("dart::Dart_TestProfiler_NativeAllocation()",
                  walker.CurrentName());
-    EXPECT_EQ(walker.native_allocation_size_bytes(), 1024);
     EXPECT(walker.Down());
     EXPECT_STREQ("dart::TestCase::Run()", walker.CurrentName());
-    EXPECT_EQ(walker.native_allocation_size_bytes(), 1024);
     EXPECT(walker.Down());
     EXPECT_STREQ("dart::TestCaseBase::RunTest()", walker.CurrentName());
-    EXPECT_EQ(walker.native_allocation_size_bytes(), 1024);
     EXPECT(walker.Down());
     EXPECT_STREQ("dart::TestCaseBase::RunAll()", walker.CurrentName());
-    EXPECT_EQ(walker.native_allocation_size_bytes(), 1024);
+    EXPECT(walker.Down());
+    EXPECT_SUBSTRING("[Native]", walker.CurrentName());
     EXPECT(walker.Down());
     EXPECT_STREQ("main", walker.CurrentName());
-    EXPECT_EQ(walker.native_allocation_size_bytes(), 1024);
     EXPECT(!walker.Down());
   }
 
@@ -601,11 +597,10 @@
 
   MallocHooks::set_stack_trace_collection_enabled(
       stack_trace_collection_enabled);
-  MallocHooks::TearDown();
   FLAG_profiler_native_memory = enable_malloc_hooks_saved;
 }
-#endif  // defined(DART_USE_TCMALLOC) && !defined(PRODUCT) &&
-        // !defined(TARGET_ARCH_DBC) && !defined(HOST_OS_FUCHSIA)
+#endif  // defined(DART_USE_TCMALLOC) && defined(HOST_OS_LINUX) &&             \
+        // defined(DEBUG) && defined(HOST_ARCH_X64)
 
 ISOLATE_UNIT_TEST_CASE(Profiler_ToggleRecordAllocation) {
   EnableProfiler();
diff --git a/runtime/vm/raw_object.cc b/runtime/vm/raw_object.cc
index 1f2ccdb..212d274 100644
--- a/runtime/vm/raw_object.cc
+++ b/runtime/vm/raw_object.cc
@@ -9,6 +9,7 @@
 #include "vm/heap/become.h"
 #include "vm/heap/freelist.h"
 #include "vm/isolate.h"
+#include "vm/isolate_reload.h"
 #include "vm/object.h"
 #include "vm/runtime_entry.h"
 #include "vm/visitor.h"
@@ -57,11 +58,11 @@
     }
   }
   intptr_t class_id = ClassIdTag::decode(tags);
-  if (!isolate->class_table()->IsValidIndex(class_id)) {
+  if (!isolate->shared_class_table()->IsValidIndex(class_id)) {
     FATAL1("Invalid class id encountered %" Pd "\n", class_id);
   }
-  if ((class_id == kNullCid) &&
-      (isolate->class_table()->At(class_id) == NULL)) {
+  if (class_id == kNullCid &&
+      isolate->shared_class_table()->HasValidClassAt(class_id)) {
     // Null class not yet initialized; skip.
     return;
   }
@@ -212,9 +213,19 @@
       // TODO(koda): Add Size(ClassTable*) interface to allow caching in loops.
       Isolate* isolate = Isolate::Current();
 #if defined(DEBUG)
-      ClassTable* class_table = isolate->class_table();
+      auto class_table = isolate->shared_class_table();
+#if !defined(DART_PRECOMPILED_RUNTIME)
+      auto reload_context = isolate->reload_context();
+      const bool use_saved_class_table =
+          reload_context != nullptr ? reload_context->UseSavedClassTableForGC()
+                                    : false;
+#else
+      const bool use_saved_class_table = false;
+#endif
+
+      ASSERT(use_saved_class_table || class_table->SizeAt(class_id) > 0);
       if (!class_table->IsValidIndex(class_id) ||
-          !class_table->HasValidClassAt(class_id)) {
+          (!class_table->HasValidClassAt(class_id) && !use_saved_class_table)) {
         FATAL2("Invalid class id: %" Pd " from tags %x\n", class_id,
                ptr()->tags_);
       }
diff --git a/runtime/vm/raw_object.h b/runtime/vm/raw_object.h
index fc8dfc7..0c88bdc 100644
--- a/runtime/vm/raw_object.h
+++ b/runtime/vm/raw_object.h
@@ -2140,6 +2140,10 @@
 
  private:
   friend class Library;
+  friend class OneByteStringSerializationCluster;
+  friend class TwoByteStringSerializationCluster;
+  friend class OneByteStringDeserializationCluster;
+  friend class TwoByteStringDeserializationCluster;
   friend class RODataSerializationCluster;
   friend class ImageWriter;
 };
diff --git a/runtime/vm/service.cc b/runtime/vm/service.cc
index 4ab9c57..98539e3 100644
--- a/runtime/vm/service.cc
+++ b/runtime/vm/service.cc
@@ -1415,70 +1415,6 @@
   return true;
 }
 
-static const MethodParameter* get_unused_changes_in_last_reload_params[] = {
-    ISOLATE_PARAMETER, NULL,
-};
-
-static bool GetUnusedChangesInLastReload(Thread* thread, JSONStream* js) {
-  if (CheckCompilerDisabled(thread, js)) {
-    return true;
-  }
-
-  const GrowableObjectArray& changed_in_last_reload =
-      GrowableObjectArray::Handle(
-          thread->isolate()->object_store()->changed_in_last_reload());
-  if (changed_in_last_reload.IsNull()) {
-    js->PrintError(kIsolateMustHaveReloaded, "No change to compare with.");
-    return true;
-  }
-  JSONObject jsobj(js);
-  jsobj.AddProperty("type", "UnusedChangesInLastReload");
-  JSONArray jsarr(&jsobj, "unused");
-  Object& changed = Object::Handle();
-  Function& function = Function::Handle();
-  Field& field = Field::Handle();
-  Class& cls = Class::Handle();
-  Array& functions = Array::Handle();
-  Array& fields = Array::Handle();
-  for (intptr_t i = 0; i < changed_in_last_reload.Length(); i++) {
-    changed = changed_in_last_reload.At(i);
-    if (changed.IsFunction()) {
-      function ^= changed.raw();
-      if (!function.WasExecuted()) {
-        jsarr.AddValue(function);
-      }
-    } else if (changed.IsField()) {
-      field ^= changed.raw();
-      if (field.IsUninitialized() ||
-          field.initializer_changed_after_initialization()) {
-        jsarr.AddValue(field);
-      }
-    } else if (changed.IsClass()) {
-      cls ^= changed.raw();
-      if (!cls.is_finalized()) {
-        // Not used at all.
-        jsarr.AddValue(cls);
-      } else {
-        functions = cls.functions();
-        for (intptr_t j = 0; j < functions.Length(); j++) {
-          function ^= functions.At(j);
-          if (!function.WasExecuted()) {
-            jsarr.AddValue(function);
-          }
-        }
-        fields = cls.fields();
-        for (intptr_t j = 0; j < fields.Length(); j++) {
-          field ^= fields.At(j);
-          if (field.IsUninitialized()) {
-            jsarr.AddValue(field);
-          }
-        }
-      }
-    }
-  }
-  return true;
-}
-
 static const MethodParameter* get_stack_params[] = {
     RUNNABLE_ISOLATE_PARAMETER,
     NULL,
@@ -3943,7 +3879,7 @@
   Isolate* isolate = thread->isolate();
   if (should_reset_accumulator) {
     isolate->UpdateLastAllocationProfileAccumulatorResetTimestamp();
-    isolate->class_table()->ResetAllocationAccumulators();
+    isolate->shared_class_table()->ResetAllocationAccumulators();
   }
   if (should_collect) {
     isolate->UpdateLastAllocationProfileGCTimestamp();
@@ -4763,8 +4699,6 @@
     get_source_report_params },
   { "getStack", GetStack,
     get_stack_params },
-  { "_getUnusedChangesInLastReload", GetUnusedChangesInLastReload,
-    get_unused_changes_in_last_reload_params },
   { "_getTagProfile", GetTagProfile,
     get_tag_profile_params },
   { "_getTypeArgumentsList", GetTypeArgumentsList,
diff --git a/runtime/vm/snapshot.h b/runtime/vm/snapshot.h
index 5c3b68e..1f7beaa 100644
--- a/runtime/vm/snapshot.h
+++ b/runtime/vm/snapshot.h
@@ -196,6 +196,9 @@
   const uint8_t* Addr() const { return reinterpret_cast<const uint8_t*>(this); }
 
   const uint8_t* DataImage() const {
+    if (!IncludesCode(kind())) {
+      return NULL;
+    }
     uword offset = Utils::RoundUp(length(), OS::kMaxPreferredCodeAlignment);
     return Addr() + offset;
   }
diff --git a/runtime/vm/snapshot_test.cc b/runtime/vm/snapshot_test.cc
index 3da6666..e05f475 100644
--- a/runtime/vm/snapshot_test.cc
+++ b/runtime/vm/snapshot_test.cc
@@ -724,8 +724,7 @@
       "}\n";
   Dart_Handle result;
 
-  uint8_t* isolate_snapshot_data_buffer = nullptr;
-  intptr_t isolate_snapshot_data_size = 0;
+  uint8_t* isolate_snapshot_data_buffer;
 
   // Start an Isolate, load a script and create a full snapshot.
   Timer timer1(true, "Snapshot_test");
@@ -750,38 +749,17 @@
     OS::PrintErr("Without Snapshot: %" Pd64 "us\n", timer1.TotalElapsedTime());
 
     // Write snapshot with object content.
-    uint8_t* isolate_snapshot_text_buffer = nullptr;
-    BlobImageWriter image_writer(thread, &isolate_snapshot_text_buffer,
-                                 &malloc_allocator, 2 * MB /* initial_size */,
-                                 /*shared_objects=*/nullptr,
-                                 /*shared_instructions=*/nullptr,
-                                 /*reused_instructions=*/nullptr);
-    FullSnapshotWriter writer(Snapshot::kFull, nullptr,
+    FullSnapshotWriter writer(Snapshot::kFull, NULL,
                               &isolate_snapshot_data_buffer, &malloc_allocator,
-                              nullptr, &image_writer);
+                              NULL, /*image_writer*/ nullptr);
     writer.WriteFullSnapshot();
-    isolate_snapshot_data_size = writer.IsolateSnapshotSize();
-    free(isolate_snapshot_text_buffer);
   }
 
-  // Malloc gives only 8 byte alignment, but we need
-  // OS::kMaxPreferredCodeAlignment. Rellocate to VirtualMemory to get page
-  // alignment.
-  std::unique_ptr<VirtualMemory> aligned_isolate_snapshot_data_buffer(
-      VirtualMemory::Allocate(
-          Utils::RoundUp(isolate_snapshot_data_size, VirtualMemory::PageSize()),
-          false, "snapshot_test"));
-  memmove(aligned_isolate_snapshot_data_buffer->address(),
-          isolate_snapshot_data_buffer, isolate_snapshot_data_size);
-  free(isolate_snapshot_data_buffer);
-  isolate_snapshot_data_buffer = nullptr;
-
   // Now Create another isolate using the snapshot and execute a method
   // from the script.
   Timer timer2(true, "Snapshot_test");
   timer2.Start();
-  TestCase::CreateTestIsolateFromSnapshot(reinterpret_cast<uint8_t*>(
-      aligned_isolate_snapshot_data_buffer->address()));
+  TestCase::CreateTestIsolateFromSnapshot(isolate_snapshot_data_buffer);
   {
     Dart_EnterScope();  // Start a Dart API scope for invoking API functions.
     timer2.Stop();
@@ -794,6 +772,7 @@
     Dart_ExitScope();
   }
   Dart_ShutdownIsolate();
+  free(isolate_snapshot_data_buffer);
 }
 
 // Helper function to call a top level Dart function and serialize the result.
diff --git a/sdk_nnbd/BUILD.gn b/sdk_nnbd/BUILD.gn
new file mode 100644
index 0000000..228fc3c
--- /dev/null
+++ b/sdk_nnbd/BUILD.gn
@@ -0,0 +1,1069 @@
+# 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.
+
+# This GN file contains build rules for assembling the Dart SDK. There are
+# two possible variants: the "Full" SDK, and the "Platform" SDK. If you want
+# to make a new subset of the Full SDK, make it the same way we make
+# the Platform SDK.
+#
+# Warning:
+# If you need to copy something into dart-sdk/lib/foo in addition to the stuff
+# copied there by :copy_libraries, then you must depend on ":copy_libraries",
+# or ":copy_libraries" may delete/overwrite your addition, and the build will
+# fail.
+
+import("../build/dart/copy_tree.gni")
+import("../runtime/runtime_args.gni")
+
+declare_args() {
+  # Build a SDK with less stuff. It excludes dart2js, ddc, and web libraries.
+  dart_platform_sdk = true
+
+  # Path to stripped dart binaries relative to build output directory.
+  dart_stripped_binary = "dart"
+  dartaotruntime_stripped_binary = "dartaotruntime"
+  gen_snapshot_stripped_binary = "gen_snapshot"
+}
+
+# The directory layout of the SDK is as follows:
+#
+# ..dart-sdk/
+# ....bin/
+# ......dart or dart.exe (executable)
+# ......dart.lib (import library for VM native extensions on Windows)
+# ......dartaotruntime or dartaotruntime.exe (executable)
+# ......dartdoc
+# ......dartfmt
+# ......dart2aot
+# ......dart2js
+# ......dartanalyzer
+# ......dartdevc
+# ......utils/gen_snapshot or utils/gen_snapshot.exe (executable)
+# ......pub
+# ......snapshots/
+# ........analysis_server.dart.snapshot
+# ........dart2js.dart.snapshot
+# ........dartanalyzer.dart.snapshot
+# ........dartdoc.dart.snapshot
+# ........dartfmt.dart.snapshot
+# ........dartdevc.dart.snapshot
+# ........gen_kernel.dart.snapshot
+# ........kernel_worker.dart.snapshot
+# ........pub.dart.snapshot
+#.........resources/
+#...........dartdoc/
+#..............packages
+#.............resources/
+#.............templates/
+# ....include/
+# ......dart_api.h
+# ......dart_native_api.h
+# ......dart_tools_api.h
+# ....lib/
+# ......libraries.json
+# ......_internal/
+#.........strong.sum
+#.........dart2js_platform.dill
+#.........dart2js_server_platform.dill
+#.........dart2js_platform_strong.dill
+#.........dart2js_server_platform_strong.dill
+#.........vm_platform_strong.dill
+#.........dev_compiler/
+# ......async/
+# ......collection/
+# ......convert/
+# ......core/
+# ......html/
+# ......_http/
+# ......internal/
+# ......io/
+# ......isolate/
+# ......js/
+# ......js_util/
+# ......math/
+# ......mirrors/
+# ......typed_data/
+# ......wasm/
+# ......api_readme.md
+# ....model/
+# ......lexeme/
+# ........idx2word.json
+# ........model.tflite
+# ........word2idx.json
+
+# Scripts that go under bin/
+_platform_sdk_scripts = [
+  "dartanalyzer",
+  "dartfmt",
+  "pub",
+]
+
+_full_sdk_scripts = [
+  "dart2js",
+  "dartanalyzer",
+  "dartdevc",
+  "dartfmt",
+  "pub",
+]
+
+# Scripts not ending in _sdk that go under bin/
+_scripts = [ "dartdoc" ]
+
+# Snapshots that go under bin/snapshots
+_platform_sdk_snapshots = [
+  [
+    "dartanalyzer",
+    "../utils/dartanalyzer:generate_dartanalyzer_snapshot",
+  ],
+  [
+    "dart2native",
+    "../utils/dart2native:generate_dart2native_snapshot",
+  ],
+  [
+    "dartdoc",
+    "../utils/dartdoc",
+  ],
+  [
+    "dartfmt",
+    "../utils/dartfmt",
+  ],
+  [
+    "pub",
+    "../utils/pub",
+  ],
+]
+if (create_kernel_service_snapshot) {
+  _platform_sdk_snapshots += [
+    [
+      "kernel-service",
+      "../utils/kernel-service:kernel-service_snapshot",
+    ],
+  ]
+}
+if (dart_target_arch != "arm") {
+  _platform_sdk_snapshots += [
+    [
+      "analysis_server",
+      "../utils/analysis_server",
+    ],
+  ]
+}
+
+_full_sdk_snapshots = [
+  [
+    "dart2js",
+    "../utils/compiler:dart2js",
+  ],
+  [
+    "dartanalyzer",
+    "../utils/dartanalyzer:generate_dartanalyzer_snapshot",
+  ],
+  [
+    "dart2native",
+    "../utils/dart2native:generate_dart2native_snapshot",
+  ],
+  [
+    "dartdevc",
+    "../utils/dartdevc",
+  ],
+  [
+    "dartdoc",
+    "../utils/dartdoc",
+  ],
+  [
+    "dartfmt",
+    "../utils/dartfmt",
+  ],
+  [
+    "kernel_worker",
+    "../utils/bazel:kernel_worker",
+  ],
+  [
+    "pub",
+    "../utils/pub",
+  ],
+]
+if (create_kernel_service_snapshot) {
+  _full_sdk_snapshots += [
+    [
+      "kernel-service",
+      "../utils/kernel-service:kernel-service_snapshot",
+    ],
+  ]
+}
+if (dart_target_arch != "arm") {
+  _full_sdk_snapshots += [
+    [
+      "analysis_server",
+      "../utils/analysis_server",
+    ],
+  ]
+}
+
+# Libraries that go under lib/
+_full_sdk_libraries = [
+  "_chrome",
+  "_internal",
+  "async",
+  "cli",
+  "collection",
+  "convert",
+  "core",
+  "developer",
+  "ffi",
+  "html",
+  "_http",
+  "indexed_db",
+  "internal",
+  "io",
+  "isolate",
+  "js",
+  "js_util",
+  "math",
+  "mirrors",
+  "profiler",
+  "svg",
+  "typed_data",
+  "wasm",
+  "web_audio",
+  "web_gl",
+  "web_sql",
+]
+
+# Apps running on the platform SDK shouldn't be using Dart4Web libraries, but
+# the analyzer and dartdoc expect all the library sources to be present.
+#
+# _platform_sdk_libraries = [
+#   "_internal",
+#   "async",
+#   "cli",
+#   "collection",
+#   "convert",
+#   "core",
+#   "developer",
+#   "html",
+#   "_http",
+#   "internal",
+#   "io",
+#   "isolate",
+#   "math",
+#   "mirrors",
+#   "profiler",
+#   "typed_data",
+# ]
+_platform_sdk_libraries = _full_sdk_libraries
+
+# From here down to the copy_trees() invocation, we collect all the information
+# about trees that need to be copied in the list of scopes, copy_tree_specs.
+copy_tree_specs = []
+
+# This rule copies dartdoc templates to
+# bin/resources/dartdoc/templates
+copy_tree_specs += [ {
+      target = "copy_dartdoc_templates"
+      visibility = [ ":copy_dartdoc_files" ]
+      source = "../third_party/pkg/dartdoc/lib/templates"
+      dest = "$root_out_dir/dart-sdk/bin/resources/dartdoc/templates"
+      ignore_patterns = "{}"
+    } ]
+
+# This rule copies dartdoc resources to
+# bin/resources/dartdoc/resources
+copy_tree_specs += [ {
+      target = "copy_dartdoc_resources"
+      visibility = [ ":copy_dartdoc_files" ]
+      source = "../third_party/pkg/dartdoc/lib/resources"
+      dest = "$root_out_dir/dart-sdk/bin/resources/dartdoc/resources"
+      ignore_patterns = "{}"
+    } ]
+
+# This loop generates rules to copy libraries to lib/
+foreach(library, _full_sdk_libraries) {
+  copy_tree_specs += [ {
+        target = "copy_${library}_library"
+        visibility = [
+          ":copy_platform_sdk_libraries",
+          ":copy_full_sdk_libraries",
+        ]
+        source = "lib/$library"
+        dest = "$root_out_dir/dart-sdk/lib/$library"
+        ignore_patterns = "*.svn,doc,*.py,*.gypi,*.sh,.gitignore"
+      } ]
+}
+
+if (is_win) {
+  copy_tree_specs += [ {
+        target = "copy_7zip"
+        visibility = [ ":create_common_sdk" ]
+        deps = [
+          ":copy_libraries",
+        ]
+        source = "../third_party/7zip"
+        dest = "$root_out_dir/dart-sdk/lib/_internal/pub/asset/7zip"
+        ignore_patterns = ".svn"
+      } ]
+}
+
+if (target_cpu == "x64") {
+  copy_tree_specs += [
+      {
+        target = "copy_language_model"
+        visibility = [ ":create_common_sdk" ]
+        deps = [
+          ":copy_libraries",
+        ]
+        source = "../pkg/analysis_server/language_model"
+        dest = "$root_out_dir/dart-sdk/model"
+        ignore_patterns = "{}"
+      },
+      {
+        target = "copy_libtensorflowlite_c"
+        visibility = [ ":create_common_sdk" ]
+        deps = [
+          ":copy_libraries",
+        ]
+        source = "../third_party/pkg/tflite_native/lib/src/blobs"
+        dest = "$root_out_dir/dart-sdk/bin/snapshots"
+        ignore_patterns = "{}"
+      }
+   ]
+}
+
+# This generates targets for everything in copy_tree_specs. The targets have the
+# same name as the "target" fields in the scopes of copy_tree_specs.
+copy_trees("copy_trees") {
+  sources = copy_tree_specs
+}
+
+# Copies the Dart VM binary into bin/
+if (target_os != current_os && target_os == "fuchsia") {
+  # In the Fuchsia build, this has to use a symlink for two reasons.
+  # First, it makes the lookup of shared libraries relative to $ORIGIN
+  # (Linux) or @loader_path (macOS) find the libraries where they are,
+  # since those lookups use the directory of the symlink target rather
+  # than of the link itself (as they would for a copy or hard link).
+  # Second, when the dart binary is built as a "variant" (e.g. with a
+  # sanitizer), then $root_out_dir/dart is itself a symlink to the real
+  # binary in the selected variant toolchain's $root_out_dir and since
+  # the "copy" tool is actually a hard link rather than a copy, it will
+  # make a link to the symlink rather than the symlink's target, and the
+  # relative symlink interpreted from a different containing directory
+  # will not find the actual binary.
+  action("copy_dart") {
+    visibility = [ ":create_common_sdk" ]
+    dart_label = "../runtime/bin:dart"
+    deps = [
+      dart_label,
+    ]
+    dart_out = get_label_info(dart_label, "root_out_dir")
+    sources = [
+      "$dart_out/$dart_stripped_binary",
+    ]
+    outputs = [
+      "$root_out_dir/dart-sdk/bin/$dart_stripped_binary",
+    ]
+    script = "/bin/ln"
+    args = [
+      "-snf",
+      rebase_path(sources[0], get_path_info(outputs[0], "dir")),
+      rebase_path(outputs[0]),
+    ]
+  }
+} else {
+  copy("copy_dart") {
+    visibility = [ ":create_common_sdk" ]
+    deps = [
+      "../runtime/bin:dart",
+    ]
+    dart_out = get_label_info("../runtime/bin:dart", "root_out_dir")
+    if (is_win) {
+      sources = [
+        "$dart_out/dart.exe",
+      ]
+    } else {
+      sources = [
+        "$dart_out/$dart_stripped_binary",
+      ]
+    }
+    if (is_win) {
+      sources += [ "$dart_out/dart.lib" ]
+    }
+    outputs = [
+      "$root_out_dir/dart-sdk/bin/{{source_file_part}}",
+    ]
+  }
+}
+
+copy("copy_dartaotruntime") {
+  deps = [
+    "../runtime/bin:dartaotruntime",
+  ]
+  dartaotruntime_out = get_label_info("../runtime/bin:dartaotruntime", "root_out_dir")
+  if (is_win) {
+    sources = [
+      "$dartaotruntime_out/dartaotruntime.exe",
+    ]
+  } else {
+    sources = [
+      "$dartaotruntime_out/$dartaotruntime_stripped_binary",
+    ]
+  }
+  if (is_win) {
+    sources += [ "$dartaotruntime_out/dartaotruntime.lib" ]
+  }
+  outputs = [
+    "$root_out_dir/dart-sdk/bin/{{source_file_part}}",
+  ]
+}
+
+copy("copy_gen_snapshot") {
+  deps = [
+    "../runtime/bin:gen_snapshot",
+  ]
+  gen_snapshot_out = get_label_info("../runtime/bin:gen_snapshot", "root_out_dir")
+  if (is_win) {
+    sources = [
+      "$gen_snapshot_out/gen_snapshot.exe",
+    ]
+  } else {
+    sources = [
+      "$gen_snapshot_out/$gen_snapshot_stripped_binary",
+    ]
+  }
+  outputs = [
+    "$root_out_dir/dart-sdk/bin/utils/{{source_file_part}}",
+  ]
+}
+
+copy("copy_dart2aot") {
+  ext = ""
+  if (is_win) {
+    ext = ".bat"
+  }
+  sources = [
+    "bin/dart2aot$ext",
+  ]
+  outputs = [
+    "$root_out_dir/dart-sdk/bin/{{source_file_part}}",
+  ]
+}
+
+copy("copy_dart2native") {
+  deps = [
+    ":copy_gen_kernel_snapshot",
+    ":copy_gen_snapshot",
+  ]
+  ext = ""
+  if (is_win) {
+    ext = ".bat"
+  }
+  sources = [
+    "bin/dart2native$ext",
+  ]
+  outputs = [
+    "$root_out_dir/dart-sdk/bin/{{source_file_part}}",
+  ]
+}
+
+copy("copy_gen_kernel_snapshot") {
+  deps = [
+    "../utils/gen_kernel",
+  ]
+  sources = [
+    "$root_gen_dir/gen_kernel.dart.snapshot",
+  ]
+  outputs = [
+    "$root_out_dir/dart-sdk/bin/snapshots/{{source_file_part}}",
+  ]
+}
+
+# A template for copying the things in _platform_sdk_scripts and
+# _full_sdk_scripts into bin/
+template("copy_sdk_script") {
+  assert(defined(invoker.name), "copy_sdk_script must define 'name'")
+  name = invoker.name
+  ext = ""
+  if (is_win) {
+    ext = ".bat"
+  }
+  copy(target_name) {
+    visibility = [
+      ":copy_platform_sdk_scripts",
+      ":copy_full_sdk_scripts",
+    ]
+    sources = [
+      "bin/${name}_sdk$ext",
+    ]
+    outputs = [
+      "$root_out_dir/dart-sdk/bin/$name$ext",
+    ]
+  }
+}
+
+foreach(sdk_script, _full_sdk_scripts) {
+  copy_sdk_script("copy_${sdk_script}_script") {
+    name = sdk_script
+  }
+}
+
+foreach(script, _scripts) {
+  copy("copy_${script}_script") {
+    visibility = [
+      ":copy_platform_sdk_scripts",
+      ":copy_full_sdk_scripts",
+    ]
+    ext = ""
+    if (is_win) {
+      ext = ".bat"
+    }
+    sources = [
+      "bin/$script$ext",
+    ]
+    outputs = [
+      "$root_out_dir/dart-sdk/bin/{{source_file_part}}",
+    ]
+  }
+}
+
+# This is the main target for copying scripts in _platform_sdk_scripts to bin/
+group("copy_platform_sdk_scripts") {
+  visibility = [ ":create_platform_sdk" ]
+  public_deps = []
+  foreach(sdk_script, _platform_sdk_scripts) {
+    public_deps += [ ":copy_${sdk_script}_script" ]
+  }
+  foreach(script, _scripts) {
+    public_deps += [ ":copy_${script}_script" ]
+  }
+}
+
+# This is the main target for copying scripts in _full_sdk_scripts to bin/
+group("copy_full_sdk_scripts") {
+  visibility = [ ":create_full_sdk" ]
+  public_deps = []
+  foreach(sdk_script, _full_sdk_scripts) {
+    public_deps += [ ":copy_${sdk_script}_script" ]
+  }
+  foreach(script, _scripts) {
+    public_deps += [ ":copy_${script}_script" ]
+  }
+}
+
+# This loop generates "copy" targets that put snapshots into bin/snapshots
+foreach(snapshot, _full_sdk_snapshots) {
+  copy("copy_${snapshot[0]}_snapshot") {
+    visibility = [
+      ":copy_platform_sdk_snapshots",
+      ":copy_full_sdk_snapshots",
+    ]
+    deps = [
+      snapshot[1],
+    ]
+    sources = [
+      "$root_gen_dir/${snapshot[0]}.dart.snapshot",
+    ]
+    outputs = [
+      "$root_out_dir/dart-sdk/bin/snapshots/{{source_file_part}}",
+    ]
+  }
+}
+
+# This is the main rule for copying snapshots from _platform_sdk_snapshots to
+# bin/snapshots
+group("copy_platform_sdk_snapshots") {
+  visibility = [ ":create_platform_sdk" ]
+  public_deps = []
+  foreach(snapshot, _platform_sdk_snapshots) {
+    public_deps += [ ":copy_${snapshot[0]}_snapshot" ]
+  }
+}
+
+# This is the main rule for copying snapshots from _full_sdk_snapshots to
+# bin/snapshots
+group("copy_full_sdk_snapshots") {
+  visibility = [ ":create_full_sdk" ]
+  public_deps = []
+  foreach(snapshot, _full_sdk_snapshots) {
+    public_deps += [ ":copy_${snapshot[0]}_snapshot" ]
+  }
+}
+
+# This rule writes the .packages file for dartdoc resources.
+write_file("$root_out_dir/dart-sdk/bin/resources/dartdoc/.packages",
+           "dartdoc:.")
+
+# This is the main rule for copying the files that dartdoc needs.
+group("copy_dartdoc_files") {
+  visibility = [ ":create_common_sdk" ]
+  public_deps = [
+    ":copy_dartdoc_resources",
+    ":copy_dartdoc_templates",
+  ]
+}
+
+# This rule copies analyzer summaries to lib/_internal
+copy("copy_analysis_summaries") {
+  visibility = [ ":create_common_sdk" ]
+  deps = [
+    ":copy_libraries",
+    "../utils/dartanalyzer:generate_summary_strong",
+  ]
+  sources = [
+    "$root_gen_dir/strong.sum",
+  ]
+  outputs = [
+    "$root_out_dir/dart-sdk/lib/_internal/{{source_file_part}}",
+  ]
+}
+
+# This rule copies dill files to lib/_internal.
+copy("copy_vm_dill_files") {
+  visibility = [ ":create_common_sdk" ]
+  deps = [
+    ":copy_libraries",
+    "../runtime/vm:kernel_platform_files",
+  ]
+  sources = [
+    "$root_out_dir/vm_platform_strong.dill",
+  ]
+  outputs = [
+    "$root_out_dir/dart-sdk/lib/_internal/{{source_file_part}}",
+  ]
+}
+
+copy("copy_abi_dill_files") {
+  visibility = [ ":create_sdk_with_abi_versions" ]
+  sources = [
+    "../tools/abiversions",
+  ]
+  outputs = [
+    "$root_out_dir/dart-sdk/lib/_internal/abiversions",
+  ]
+}
+
+copy("copy_dart2js_dill_files") {
+  visibility = [ ":create_full_sdk" ]
+  deps = [
+    ":copy_libraries",
+    "../utils/compiler:compile_dart2js_platform",
+    "../utils/compiler:compile_dart2js_server_platform",
+  ]
+  sources = [
+    "$root_out_dir/dart2js_platform.dill",
+    "$root_out_dir/dart2js_server_platform.dill",
+  ]
+  outputs = [
+    "$root_out_dir/dart-sdk/lib/_internal/{{source_file_part}}",
+  ]
+}
+
+# This rule copies ddc summaries to lib/_internal
+copy("copy_dev_compiler_summary") {
+  visibility = [ ":copy_dev_compiler_sdk" ]
+  deps = [
+    ":copy_libraries",
+    "../utils/dartdevc:dartdevc_sdk",
+    "../utils/dartdevc:dartdevc_kernel_sdk_outline",
+  ]
+  gen_dir = get_label_info("../utils/dartdevc:dartdevc_sdk", "target_gen_dir")
+  sources = [
+    # TODO(vsm): Remove post CFE.
+    "$gen_dir/ddc_sdk.sum",
+    "$gen_dir/kernel/ddc_sdk.dill",
+  ]
+  outputs = [
+    "$root_out_dir/dart-sdk/lib/_internal/{{source_file_part}}",
+  ]
+}
+
+# TODO(vsm): Remove the old non-CFE versions of the SDK once we've completed
+# DDC to Kernel (DDK) migration.
+
+# This rule copies DDC's JS SDK and require.js to lib/dev_compiler/amd.
+copy("copy_dev_compiler_js_amd") {
+  visibility = [ ":copy_dev_compiler_js" ]
+  deps = [
+    "../utils/dartdevc:dartdevc_sdk",
+  ]
+  gen_dir = get_label_info("../utils/dartdevc:dartdevc_sdk", "target_gen_dir")
+  sources = [
+    "$gen_dir/js/amd/dart_sdk.js",
+    "$gen_dir/js/amd/dart_sdk.js.map",
+    "../third_party/requirejs/require.js",
+  ]
+  outputs = [
+    "$root_out_dir/dart-sdk/lib/dev_compiler/amd/{{source_file_part}}",
+  ]
+}
+
+# This rule copies DDC's JS SDK and run.js to lib/dev_compiler/common.
+copy("copy_dev_compiler_js_common") {
+  visibility = [ ":copy_dev_compiler_js" ]
+  deps = [
+    "../utils/dartdevc:dartdevc_sdk",
+  ]
+  gen_dir = get_label_info("../utils/dartdevc:dartdevc_sdk", "target_gen_dir")
+  sources = [
+    "$gen_dir/js/common/dart_sdk.js",
+    "$gen_dir/js/common/dart_sdk.js.map",
+    "../pkg/dev_compiler/lib/js/common/run.js",
+  ]
+  outputs = [
+    "$root_out_dir/dart-sdk/lib/dev_compiler/common/{{source_file_part}}",
+  ]
+}
+
+# This rule copies DDC's JS SDK to lib/dev_compiler/es6.
+copy("copy_dev_compiler_js_es6") {
+  visibility = [ ":copy_dev_compiler_js" ]
+  deps = [
+    "../utils/dartdevc:dartdevc_sdk",
+  ]
+  gen_dir = get_label_info("../utils/dartdevc:dartdevc_sdk", "target_gen_dir")
+  sources = [
+    "$gen_dir/js/es6/dart_sdk.js",
+    "$gen_dir/js/es6/dart_sdk.js.map",
+  ]
+  outputs = [
+    "$root_out_dir/dart-sdk/lib/dev_compiler/es6/{{source_file_part}}",
+  ]
+}
+
+# This rule copies DDK's JS SDK and require.js to lib/dev_compiler/kernel/amd.
+copy("copy_dev_compiler_js_amd_kernel") {
+  visibility = [ ":copy_dev_compiler_js" ]
+  deps = [
+    "../utils/dartdevc:dartdevc_kernel_sdk",
+  ]
+  gen_dir = get_label_info("../utils/dartdevc:dartdevc_kernel_sdk",
+                           "target_gen_dir")
+  sources = [
+    "$gen_dir/kernel/amd/dart_sdk.js",
+    "$gen_dir/kernel/amd/dart_sdk.js.map",
+    "../third_party/requirejs/require.js",
+  ]
+  outputs = [
+    "$root_out_dir/dart-sdk/lib/dev_compiler/kernel/amd/{{source_file_part}}",
+  ]
+}
+
+# This rule copies DDK's JS SDK to lib/dev_compiler/kernel/common.
+copy("copy_dev_compiler_js_common_kernel") {
+  visibility = [ ":copy_dev_compiler_js" ]
+  deps = [
+    "../utils/dartdevc:dartdevc_kernel_sdk",
+  ]
+  gen_dir = get_label_info("../utils/dartdevc:dartdevc_kernel_sdk",
+                           "target_gen_dir")
+  sources = [
+    "$gen_dir/kernel/common/dart_sdk.js",
+    "$gen_dir/kernel/common/dart_sdk.js.map",
+    "../pkg/dev_compiler/lib/js/common/run.js",
+  ]
+  outputs = [
+    "$root_out_dir/dart-sdk/lib/dev_compiler/kernel/common/{{source_file_part}}",
+  ]
+}
+
+# This rule copies DDK's JS SDK to lib/dev_compiler/kernel/es6.
+copy("copy_dev_compiler_js_es6_kernel") {
+  visibility = [ ":copy_dev_compiler_js" ]
+  deps = [
+    "../utils/dartdevc:dartdevc_kernel_sdk",
+  ]
+  gen_dir = get_label_info("../utils/dartdevc:dartdevc_kernel_sdk",
+                           "target_gen_dir")
+  sources = [
+    "$gen_dir/kernel/es6/dart_sdk.js",
+    "$gen_dir/kernel/es6/dart_sdk.js.map",
+  ]
+  outputs = [
+    "$root_out_dir/dart-sdk/lib/dev_compiler/kernel/es6/{{source_file_part}}",
+  ]
+}
+
+# Copies all of the JS artifacts needed by DDC.
+group("copy_dev_compiler_js") {
+  visibility = [
+    ":copy_dev_compiler_sdk",
+    ":copy_dev_compiler_tools",
+  ]
+  public_deps = [
+    ":copy_dev_compiler_js_amd",
+    ":copy_dev_compiler_js_amd_kernel",
+    ":copy_dev_compiler_js_common",
+    ":copy_dev_compiler_js_common_kernel",
+    ":copy_dev_compiler_js_es6",
+    ":copy_dev_compiler_js_es6_kernel",
+  ]
+}
+
+# This rule copies tools to go along with ddc.
+copy("copy_dev_compiler_tools") {
+  visibility = [ ":copy_dev_compiler_sdk" ]
+  deps = [
+    ":copy_dev_compiler_js",
+    "../utils/dartdevc:dartdevc_web",
+    "../utils/dartdevc:stack_trace_mapper",
+  ]
+  dart_out = get_label_info("../utils/dartdevc:dartdevc_web", "root_out_dir")
+  sources = [
+    "$dart_out/dev_compiler/build/web/dart_stack_trace_mapper.js",
+    "$dart_out/dev_compiler/build/web/ddc_web_compiler.js",
+  ]
+  outputs = [
+    "$root_out_dir/dart-sdk/lib/dev_compiler/web/{{source_file_part}}",
+  ]
+}
+
+# This is the main rule for copying ddc's dependencies to lib/
+group("copy_dev_compiler_sdk") {
+  visibility = [ ":create_full_sdk" ]
+  public_deps = [
+    ":copy_dev_compiler_js",
+    ":copy_dev_compiler_summary",
+    ":copy_dev_compiler_tools",
+  ]
+}
+
+# This rule copies header files to include/
+copy("copy_headers") {
+  visibility = [ ":create_common_sdk" ]
+  sources = [
+    "../runtime/include/dart_api.h",
+    "../runtime/include/dart_native_api.h",
+    "../runtime/include/dart_tools_api.h",
+  ]
+  outputs = [
+    "$root_out_dir/dart-sdk/include/{{source_file_part}}",
+  ]
+}
+
+# This rule copies libraries.json files to lib/
+copy("copy_libraries_specification") {
+  visibility = [ ":create_common_sdk" ]
+  sources = [
+    "lib/libraries.json",
+  ]
+  deps = [
+    ":copy_libraries",
+  ]
+  outputs = [
+    "$root_out_dir/dart-sdk/lib/{{source_file_part}}",
+  ]
+}
+
+# This is the main rule to copy libraries in _platform_sdk_libraries to lib/
+group("copy_platform_sdk_libraries") {
+  visibility = [
+    ":create_platform_sdk",
+    ":copy_libraries",
+  ]
+  public_deps = []
+  foreach(library, _platform_sdk_libraries) {
+    public_deps += [ ":copy_${library}_library" ]
+  }
+}
+
+# This is the main rule to copy libraries in _full_sdk_libraries to lib/
+group("copy_full_sdk_libraries") {
+  visibility = [
+    ":create_full_sdk",
+    ":copy_libraries",
+  ]
+  public_deps = []
+  foreach(library, _full_sdk_libraries) {
+    public_deps += [ ":copy_${library}_library" ]
+  }
+}
+
+group("copy_libraries") {
+  if (dart_platform_sdk) {
+    public_deps = [
+      ":copy_platform_sdk_libraries",
+    ]
+  } else {
+    public_deps = [
+      ":copy_full_sdk_libraries",
+    ]
+  }
+}
+
+# This rule writes the version file.
+action("write_version_file") {
+  visibility = [ ":create_common_sdk" ]
+  inputs = [
+    "../tools/VERSION",
+    "../.git/logs/HEAD",
+  ]
+  output = "$root_out_dir/dart-sdk/version"
+  outputs = [
+    output,
+  ]
+  script = "../tools/write_version_file.py"
+  args = [
+    "--output",
+    rebase_path(output),
+  ]
+}
+
+# This rule writes the revision file.
+action("write_revision_file") {
+  visibility = [ ":create_common_sdk" ]
+  inputs = [
+    "../.git/logs/HEAD",
+  ]
+  output = "$root_out_dir/dart-sdk/revision"
+  outputs = [
+    output,
+  ]
+  script = "../tools/write_revision_file.py"
+  args = [
+    "--output",
+    rebase_path(output),
+  ]
+}
+
+# Copy libraries.dart to lib/_internal/libraries.dart for backwards
+# compatibility.
+#
+# TODO(sigmund): stop copying libraries.dart. Old versions (<=0.25.1-alpha.4)
+# of the analyzer package do not support the new location of this file. We
+# should be able to remove the old file once we release a newer version of
+# analyzer and popular frameworks have migrated to use it.
+copy("copy_libraries_dart") {
+  visibility = [ ":create_common_sdk" ]
+  deps = [
+    ":copy_libraries",
+  ]
+  sources = [
+    "lib/_internal/sdk_library_metadata/lib/libraries.dart",
+  ]
+  outputs = [
+    "$root_out_dir/dart-sdk/lib/_internal/{{source_file_part}}",
+  ]
+}
+
+# This rule copies the README file.
+copy("copy_readme") {
+  visibility = [ ":create_common_sdk" ]
+  sources = [
+    "../README.dart-sdk",
+  ]
+  outputs = [
+    "$root_out_dir/dart-sdk/README",
+  ]
+}
+
+# This rule copies the LICENSE file.
+copy("copy_license") {
+  visibility = [ ":create_common_sdk" ]
+  sources = [
+    "../LICENSE",
+  ]
+  outputs = [
+    "$root_out_dir/dart-sdk/LICENSE",
+  ]
+}
+
+# This rule generates a custom dartdoc_options.yaml file.
+action("write_dartdoc_options") {
+  visibility = [ ":create_common_sdk" ]
+  inputs = [
+    "../.git/logs/HEAD",
+  ]
+  output = "$root_out_dir/dart-sdk/dartdoc_options.yaml"
+  outputs = [
+    output,
+  ]
+  script = "../tools/write_dartdoc_options_file.py"
+  args = [
+    "--output",
+    rebase_path(output),
+  ]
+}
+
+# This rule copies the API readme file to lib/
+copy("copy_api_readme") {
+  visibility = [ ":create_common_sdk" ]
+  sources = [
+    "api_readme.md",
+  ]
+  outputs = [
+    "$root_out_dir/dart-sdk/lib/api_readme.md",
+  ]
+}
+
+# Parts common to both platform and full SDKs.
+group("create_common_sdk") {
+  visibility = [ ":create_sdk" ]
+  public_deps = [
+    ":copy_analysis_summaries",
+    ":copy_api_readme",
+    ":copy_dart",
+    ":copy_dart2native",
+    ":copy_dartdoc_files",
+    ":copy_headers",
+    ":copy_libraries_dart",
+    ":copy_license",
+    ":copy_libraries_specification",
+    ":copy_readme",
+    ":copy_vm_dill_files",
+    ":write_dartdoc_options",
+    ":write_revision_file",
+    ":write_version_file",
+  ]
+  if (is_win) {
+    public_deps += [ ":copy_7zip" ]
+  }
+  if (target_cpu == "x64") {
+    public_deps += [
+      ":copy_language_model",
+      ":copy_libtensorflowlite_c",
+    ]
+  }
+}
+
+# Parts specific to the platform SDK.
+group("create_platform_sdk") {
+  visibility = [ ":create_sdk" ]
+  public_deps = [
+    ":copy_platform_sdk_libraries",
+    ":copy_platform_sdk_scripts",
+    ":copy_platform_sdk_snapshots",
+  ]
+}
+
+# Parts specific to the full SDK.
+group("create_full_sdk") {
+  visibility = [ ":create_sdk" ]
+
+  public_deps = [
+    ":copy_dart2js_dill_files",
+    ":copy_dev_compiler_sdk",
+    ":copy_full_sdk_libraries",
+    ":copy_full_sdk_scripts",
+    ":copy_full_sdk_snapshots",
+  ]
+}
+
+# The main target to depend on from ../BUILD.gn
+group("create_sdk") {
+  public_deps = [
+    ":create_common_sdk",
+  ]
+  if (dart_platform_sdk) {
+    public_deps += [ ":create_platform_sdk" ]
+  } else {
+    public_deps += [ ":create_full_sdk" ]
+  }
+}
+
+# Same as create_sdk, but with abi version files.
+group("create_sdk_with_abi_versions") {
+  public_deps = [
+    ":copy_abi_dill_files",
+    ":create_sdk",
+  ]
+}
diff --git a/sdk_nnbd/api_readme.md b/sdk_nnbd/api_readme.md
new file mode 100644
index 0000000..2f51f7e
--- /dev/null
+++ b/sdk_nnbd/api_readme.md
@@ -0,0 +1,32 @@
+Welcome to the Dart API reference documentation, covering the core Dart API
+libraries. Some of the most fundamental Dart libraries include:
+   
+  * [dart:core](dart-core/dart-core-library.html): Core functionality such as
+    strings, numbers, collections, errors, dates, and URIs.
+  * [dart:html](dart-html/dart-html-library.html): DOM manipulation for web apps
+    (available only to web apps).
+  * [dart:io](dart-io/dart-io-library.html): I/O for non-web apps.
+  
+Except for `dart:core`, you must import a library before you can use it. Here's
+an example of importing `dart:async` and `dart:math`:
+
+```dart
+import 'dart:async';
+import 'dart:math';
+```
+
+You can install more libraries using the
+[pub package manager](https://dart.dev/guides/packages).
+  
+The main site for learning and using Dart is
+[dart.dev](https://dart.dev). Check out these pages:
+  
+  * [Platforms](https://dart.dev/platforms)
+  * [Language tour](https://dart.dev/guides/language/language-tour)
+  * [Library tour](https://dart.dev/guides/libraries/library-tour)
+  * [Sample code](https://dart.dev/samples)
+  
+This API reference is automatically generated from source code in the [Dart
+SDK project](https://github.com/dart-lang/sdk).
+If you'd like to give feedback or edit this documentation, see
+[Contributing](https://github.com/dart-lang/sdk/wiki/Contributing).
diff --git a/sdk_nnbd/bin/dart b/sdk_nnbd/bin/dart
new file mode 100755
index 0000000..f50184b
--- /dev/null
+++ b/sdk_nnbd/bin/dart
@@ -0,0 +1,57 @@
+#!/usr/bin/env bash
+# Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+function follow_links() {
+  file="$1"
+  while [ -h "$file" ]; do
+    # On Mac OS, readlink -f doesn't work.
+    file="$(readlink "$file")"
+  done
+  echo "$file"
+}
+
+# Unlike $0, $BASH_SOURCE points to the absolute path of this file.
+PROG_NAME="$(follow_links "$BASH_SOURCE")"
+
+# Handle the case where dart-sdk/bin has been symlinked to.
+CUR_DIR="$(cd "${PROG_NAME%/*}" ; pwd -P)"
+
+if [[ `uname` == 'Darwin' ]];
+then
+  OUT_DIR="$CUR_DIR"/../../xcodebuild/
+else
+  OUT_DIR="$CUR_DIR"/../../out/
+fi
+
+if [ -z "$DART_CONFIGURATION" ];
+then
+  DIRS=$( ls "$OUT_DIR" )
+  # list of possible configurations in decreasing desirability
+  CONFIGS=("ReleaseX64" "ReleaseIA32" "DebugX64" "DebugIA32"
+    "ReleaseARM"    "ReleaseARM64"    "ReleaseARMV5TE"
+    "DebugARM"      "DebugARM64"      "DebugARMV5TE")
+  DART_CONFIGURATION="None"
+  for CONFIG in ${CONFIGS[*]}
+  do
+    for DIR in $DIRS;
+    do
+      if [ "$CONFIG" = "$DIR" ];
+      then
+        # choose most desirable configuration that is available and break
+        DART_CONFIGURATION="$DIR"
+        break 2
+      fi
+    done
+  done
+  if [ "$DART_CONFIGURATION" = "None" ]
+  then
+    echo "No valid dart configuration found in $OUT_DIR"
+    exit 1
+  fi
+fi
+
+BIN_DIR="$OUT_DIR$DART_CONFIGURATION"
+
+exec "$BIN_DIR"/dart "$@"
diff --git a/sdk_nnbd/bin/dart.bat b/sdk_nnbd/bin/dart.bat
new file mode 100644
index 0000000..a6a24de
--- /dev/null
+++ b/sdk_nnbd/bin/dart.bat
@@ -0,0 +1,16 @@
+@echo off
+REM Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+REM for details. All rights reserved. Use of this source code is governed by a
+REM BSD-style license that can be found in the LICENSE file.
+
+set SCRIPTPATH=%~dp0
+
+REM Does the path have a trailing slash? If so, remove it.
+if %SCRIPTPATH:~-1%== set SCRIPTPATH=%SCRIPTPATH:~0,-1%
+
+REM DART_CONFIGURATION defaults to ReleaseX64
+if "%DART_CONFIGURATION%"=="" set DART_CONFIGURATION=ReleaseX64
+
+set arguments=%*
+
+"%SCRIPTPATH%\..\..\out\%DART_CONFIGURATION%\dart.exe" %arguments%
diff --git a/sdk_nnbd/bin/dart2aot b/sdk_nnbd/bin/dart2aot
new file mode 100755
index 0000000..9390db6
--- /dev/null
+++ b/sdk_nnbd/bin/dart2aot
@@ -0,0 +1,111 @@
+#!/usr/bin/env bash
+# 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.
+
+# Script for generating AOT snapshot in two steps:
+# - Compilation to kernel with additional AOT specific transformations.
+# - Compilation of kernel into snapshot using gen_snapshot.
+
+# Parse incoming arguments and extract the value of --packages option if any
+# was passed. Split options (--xyz) and non-options into two separate arrays.
+# All options will be passed to gen_snapshot, while --packages will be
+# passed to the CFE (Common Front-End).
+
+set -e
+
+OPTIONS=()
+GEN_KERNEL_OPTIONS=()
+PACKAGES=
+BUILD_ELF=0
+
+ARGV=()
+for arg in "$@"; do
+  case $arg in
+    --packages=*)
+    PACKAGES="$arg"
+    ;;
+    --enable-asserts)
+    GEN_KERNEL_OPTIONS+=("$arg")
+    OPTIONS+=("$arg")
+    ;;
+    --tfa | \
+    --no-tfa | \
+    -D* )
+    GEN_KERNEL_OPTIONS+=("$arg")
+    ;;
+    --build-elf)
+    BUILD_ELF=1
+    ;;
+    --*)
+    OPTIONS+=("$arg")
+    ;;
+    *)
+    ARGV+=("$arg")
+    ;;
+  esac
+done
+
+if [ "${#ARGV[@]}" -ne 2 ]; then
+    echo "Usage: $0 [options] <dart-source-file> <dart-aot-file>"
+    echo ""
+    echo "Dart AOT (ahead-of-time) compile Dart source code into native machine code."
+    exit 1
+fi
+
+SOURCE_FILE="${ARGV[0]}"
+SNAPSHOT_FILE="${ARGV[1]}"
+
+if [ $BUILD_ELF -eq 1 ]; then
+  GEN_SNAPSHOT_OPTION="--snapshot-kind=app-aot-assembly"
+  GEN_SNAPSHOT_FILENAME="--assembly=${SNAPSHOT_FILE}.S"
+else
+  GEN_SNAPSHOT_OPTION="--snapshot-kind=app-aot-blobs"
+  GEN_SNAPSHOT_FILENAME="--blobs_container_filename=${SNAPSHOT_FILE}"
+fi
+
+function follow_links() {
+  file="$1"
+  while [ -h "$file" ]; do
+    # On Mac OS, readlink -f doesn't work.
+    file="$(readlink "$file")"
+  done
+  echo "$file"
+}
+
+# Unlike $0, $BASH_SOURCE points to the absolute path of this file.
+PROG_NAME="$(follow_links "$BASH_SOURCE")"
+
+# Handle the case where dart-sdk/bin has been symlinked to.
+BIN_DIR="$(cd "${PROG_NAME%/*}" ; pwd -P)"
+
+SDK_DIR="$(cd "${BIN_DIR}/.." ; pwd -P)"
+
+DART="$BIN_DIR/dart"
+GEN_SNAPSHOT="$BIN_DIR/utils/gen_snapshot"
+
+SNAPSHOT_DIR="$BIN_DIR/snapshots"
+SNAPSHOT="$SNAPSHOT_DIR/gen_kernel.dart.snapshot"
+
+# Step 1: Generate Kernel binary from the input Dart source.
+"$DART"                                                                        \
+     "${SNAPSHOT}"                                                             \
+     --platform "${SDK_DIR}/lib/_internal/vm_platform_strong.dill"             \
+     --aot                                                                     \
+     -Ddart.vm.product=true                                                    \
+     "${GEN_KERNEL_OPTIONS[@]}"                                                \
+     $PACKAGES                                                                 \
+     -o "$SNAPSHOT_FILE.dill"                                                  \
+     "$SOURCE_FILE"
+
+# Step 2: Generate snapshot from the Kernel binary.
+"$GEN_SNAPSHOT"                                                                \
+     "$GEN_SNAPSHOT_OPTION"                                                    \
+     "$GEN_SNAPSHOT_FILENAME"                                                  \
+     "${OPTIONS[@]}"                                                           \
+     "$SNAPSHOT_FILE.dill"
+
+# Step 3: Assemble the assembly file into an ELF object.
+if [ $BUILD_ELF -eq 1 ]; then
+    gcc -shared -o "$SNAPSHOT_FILE" "${SNAPSHOT_FILE}.S"
+fi
diff --git a/sdk_nnbd/bin/dart2aot.bat b/sdk_nnbd/bin/dart2aot.bat
new file mode 100644
index 0000000..321e867
--- /dev/null
+++ b/sdk_nnbd/bin/dart2aot.bat
@@ -0,0 +1,58 @@
+@echo off
+REM Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+REM for details. All rights reserved. Use of this source code is governed by a
+REM BSD-style license that can be found in the LICENSE file.
+
+setlocal
+rem Handle the case where dart-sdk/bin has been symlinked to.
+set DIR_NAME_WITH_SLASH=%~dp0
+set DIR_NAME=%DIR_NAME_WITH_SLASH:~0,-1%%
+call :follow_links "%DIR_NAME%", RETURNED_BIN_DIR
+rem Get rid of surrounding quotes.
+for %%i in ("%RETURNED_BIN_DIR%") do set BIN_DIR=%%~fi
+
+rem Get absolute full name for SDK_DIR.
+for %%i in ("%BIN_DIR%\..\") do set SDK_DIR=%%~fi
+
+rem Remove trailing backslash if there is one
+IF %SDK_DIR:~-1%==\ set SDK_DIR=%SDK_DIR:~0,-1%
+
+rem Get absolute full name for DART_ROOT.
+for %%i in ("%SDK_DIR%\..\") do set DART_ROOT=%%~fi
+
+rem Remove trailing backslash if there is one
+if %DART_ROOT:~-1%==\ set DART_ROOT=%DART_ROOT:~0,-1%
+
+set DART=%BIN_DIR%\dart.exe
+set GEN_KERNEL=%BIN_DIR%\snapshots\gen_kernel.dart.snapshot
+set VM_PLATFORM_STRONG=%SDK_DIR%\lib\_internal\vm_platform_strong.dill
+set GEN_SNAPSHOT=%BIN_DIR%\utils\gen_snapshot.exe
+
+set SOURCE_FILE=%1
+set SNAPSHOT_FILE=%2
+set GEN_SNAPSHOT_OPTION=--snapshot-kind=app-aot-blobs
+set GEN_SNAPSHOT_FILENAME=--blobs_container_filename=%SNAPSHOT_FILE%
+
+REM Step 1: Generate Kernel binary from the input Dart source.
+%DART% %GEN_KERNEL% --platform %VM_PLATFORM_STRONG% --aot -Ddart.vm.product=true -o %SNAPSHOT_FILE%.dill %SOURCE_FILE%
+
+REM Step 2: Generate snapshot from the Kernel binary.
+%GEN_SNAPSHOT% %GEN_SNAPSHOT_OPTION% %GEN_SNAPSHOT_FILENAME% %SNAPSHOT_FILE%.dill
+
+endlocal
+
+exit /b %errorlevel%
+
+:follow_links
+setlocal
+for %%i in (%1) do set result=%%~fi
+set current=
+for /f "usebackq tokens=2 delims=[]" %%i in (`dir /a:l "%~dp1" 2^>nul ^
+                                             ^| %SystemRoot%\System32\find.exe ">     %~n1 [" 2^>nul`) do (
+  set current=%%i
+)
+if not "%current%"=="" call :follow_links "%current%", result
+endlocal & set %~2=%result%
+goto :eof
+
+:end
diff --git a/sdk_nnbd/bin/dart2js b/sdk_nnbd/bin/dart2js
new file mode 100755
index 0000000..cfc91b1
--- /dev/null
+++ b/sdk_nnbd/bin/dart2js
@@ -0,0 +1,55 @@
+#!/usr/bin/env bash
+# Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+function follow_links() {
+  file="$1"
+  while [ -h "$file" ]; do
+    # On Mac OS, readlink -f doesn't work.
+    file="$(readlink "$file")"
+  done
+  echo "$file"
+}
+
+# Unlike $0, $BASH_SOURCE points to the absolute path of this file.
+PROG_NAME="$(follow_links "$BASH_SOURCE")"
+
+# Handle the case where dart-sdk/bin has been symlinked to.
+BIN_DIR="$(cd "${PROG_NAME%/*}" ; pwd -P)"
+
+SDK_DIR="$(cd "${BIN_DIR}/.." ; pwd -P)"
+
+DART="$BIN_DIR/dart"
+
+unset EXTRA_OPTIONS
+declare -a EXTRA_OPTIONS
+
+if test -t 1; then
+  # Stdout is a terminal.
+  if test 8 -le `tput colors`; then
+    # Stdout has at least 8 colors, so enable colors.
+    EXTRA_OPTIONS+=('--enable-diagnostic-colors')
+  fi
+fi
+
+unset EXTRA_VM_OPTIONS
+declare -a EXTRA_VM_OPTIONS
+
+case $0 in
+  *_developer)
+    EXTRA_VM_OPTIONS+=('--enable-asserts')
+    ;;
+esac
+
+# We allow extra vm options to be passed in through an environment variable.
+if [[ $DART_VM_OPTIONS ]]; then
+  read -a OPTIONS <<< "$DART_VM_OPTIONS"
+  EXTRA_VM_OPTIONS+=("${OPTIONS[@]}")
+fi
+
+DART_ROOT="$(cd "${SDK_DIR}/.." ; pwd -P)"
+
+DART2JS="package:compiler/src/dart2js.dart"
+
+exec "$DART" "--packages=$DART_ROOT/.packages" "${EXTRA_VM_OPTIONS[@]}" "$DART2JS" "${EXTRA_OPTIONS[@]}" "$@"
diff --git a/sdk_nnbd/bin/dart2js.bat b/sdk_nnbd/bin/dart2js.bat
new file mode 100644
index 0000000..9341ad8
--- /dev/null
+++ b/sdk_nnbd/bin/dart2js.bat
@@ -0,0 +1,60 @@
+@echo off
+REM Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+REM for details. All rights reserved. Use of this source code is governed by a
+REM BSD-style license that can be found in the LICENSE file.
+
+setlocal
+rem Handle the case where dart-sdk/bin has been symlinked to.
+set DIR_NAME_WITH_SLASH=%~dp0
+set DIR_NAME=%DIR_NAME_WITH_SLASH:~0,-1%%
+call :follow_links "%DIR_NAME%", RETURNED_BIN_DIR
+rem Get rid of surrounding quotes.
+for %%i in ("%RETURNED_BIN_DIR%") do set BIN_DIR=%%~fi
+
+rem Get absolute full name for SDK_DIR.
+for %%i in ("%BIN_DIR%\..\") do set SDK_DIR=%%~fi
+
+rem Remove trailing backslash if there is one
+IF %SDK_DIR:~-1%==\ set SDK_DIR=%SDK_DIR:~0,-1%
+
+set DART=%BIN_DIR%\dart
+
+set EXTRA_OPTIONS=
+set EXTRA_VM_OPTIONS=
+
+if _%DART2JS_DEVELOPER_MODE%_ == _1_ (
+  set EXTRA_VM_OPTIONS=%EXTRA_VM_OPTIONS% --enable-asserts
+)
+
+rem We allow extra vm options to be passed in through an environment variable.
+if not "_%DART_VM_OPTIONS%_" == "__" (
+  set EXTRA_VM_OPTIONS=%EXTRA_VM_OPTIONS% %DART_VM_OPTIONS%
+)
+
+rem Get absolute full name for DART_ROOT.
+for %%i in ("%SDK_DIR%\..\") do set DART_ROOT=%%~fi
+
+rem Remove trailing backslash if there is one
+if %DART_ROOT:~-1%==\ set DART_ROOT=%DART_ROOT:~0,-1%
+
+set DART2JS=%DART_ROOT%\pkg\compiler\lib\src\dart2js.dart
+
+"%DART%" "--packages=%DART_ROOT%\.packages" %EXTRA_VM_OPTIONS% "%DART2JS%" %EXTRA_OPTIONS% %*
+
+endlocal
+
+exit /b %errorlevel%
+
+:follow_links
+setlocal
+for %%i in (%1) do set result=%%~fi
+set current=
+for /f "usebackq tokens=2 delims=[]" %%i in (`dir /a:l "%~dp1" 2^>nul ^
+                                             ^| %SystemRoot%\System32\find.exe ">     %~n1 [" 2^>nul`) do (
+  set current=%%i
+)
+if not "%current%"=="" call :follow_links "%current%", result
+endlocal & set %~2=%result%
+goto :eof
+
+:end
diff --git a/sdk_nnbd/bin/dart2js_developer b/sdk_nnbd/bin/dart2js_developer
new file mode 100755
index 0000000..226d1a9
--- /dev/null
+++ b/sdk_nnbd/bin/dart2js_developer
@@ -0,0 +1,6 @@
+#!/usr/bin/env bash
+# Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+. ${BASH_SOURCE%_developer}
diff --git a/sdk_nnbd/bin/dart2js_developer.bat b/sdk_nnbd/bin/dart2js_developer.bat
new file mode 100644
index 0000000..c4a2959
--- /dev/null
+++ b/sdk_nnbd/bin/dart2js_developer.bat
@@ -0,0 +1,10 @@
+@echo off
+REM Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+REM for details. All rights reserved. Use of this source code is governed by a
+REM BSD-style license that can be found in the LICENSE file.
+
+setlocal
+set DART2JS_DEVELOPER_MODE=1
+call "%~dp0dart2js.bat" %*
+endlocal
+exit /b %errorlevel%
diff --git a/sdk_nnbd/bin/dart2js_sdk b/sdk_nnbd/bin/dart2js_sdk
new file mode 100755
index 0000000..e7999b4
--- /dev/null
+++ b/sdk_nnbd/bin/dart2js_sdk
@@ -0,0 +1,58 @@
+#!/usr/bin/env bash
+# Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+function follow_links() {
+  file="$1"
+  while [ -h "$file" ]; do
+    # On Mac OS, readlink -f doesn't work.
+    file="$(readlink "$file")"
+  done
+  echo "$file"
+}
+
+# Unlike $0, $BASH_SOURCE points to the absolute path of this file.
+PROG_NAME="$(follow_links "$BASH_SOURCE")"
+
+# Handle the case where dart-sdk/bin has been symlinked to.
+BIN_DIR="$(cd "${PROG_NAME%/*}" ; pwd -P)"
+
+SDK_DIR="$(cd "${BIN_DIR}/.." ; pwd -P)"
+
+DART="$BIN_DIR/dart"
+
+SNAPSHOT_DIR="$BIN_DIR/snapshots"
+SNAPSHOT="$SNAPSHOT_DIR/dart2js.dart.snapshot"
+
+unset EXTRA_OPTIONS
+declare -a EXTRA_OPTIONS
+
+if test -t 1; then
+  # Stdout is a terminal.
+  if test 8 -le `tput colors`; then
+    # Stdout has at least 8 colors, so enable colors.
+    EXTRA_OPTIONS+=('--enable-diagnostic-colors')
+  fi
+fi
+
+unset EXTRA_VM_OPTIONS
+declare -a EXTRA_VM_OPTIONS
+
+if test -f "$SNAPSHOT"; then
+  EXTRA_OPTIONS+=("--libraries-spec=$SDK_DIR/lib/libraries.json")
+fi
+
+case $0 in
+  *_developer)
+    EXTRA_VM_OPTIONS+=('--enable-asserts')
+    ;;
+esac
+
+# We allow extra vm options to be passed in through an environment variable.
+if [[ $DART_VM_OPTIONS ]]; then
+  read -a OPTIONS <<< "$DART_VM_OPTIONS"
+  EXTRA_VM_OPTIONS+=("${OPTIONS[@]}")
+fi
+
+exec "$DART" "${EXTRA_VM_OPTIONS[@]}" "$SNAPSHOT" "${EXTRA_OPTIONS[@]}" "$@"
diff --git a/sdk_nnbd/bin/dart2js_sdk.bat b/sdk_nnbd/bin/dart2js_sdk.bat
new file mode 100755
index 0000000..8485cdc
--- /dev/null
+++ b/sdk_nnbd/bin/dart2js_sdk.bat
@@ -0,0 +1,57 @@
+@echo off
+REM Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+REM for details. All rights reserved. Use of this source code is governed by a
+REM BSD-style license that can be found in the LICENSE file.
+
+setlocal
+rem Handle the case where dart-sdk/bin has been symlinked to.
+set DIR_NAME_WITH_SLASH=%~dp0
+set DIR_NAME=%DIR_NAME_WITH_SLASH:~0,-1%%
+call :follow_links "%DIR_NAME%", RETURNED_BIN_DIR
+rem Get rid of surrounding quotes.
+for %%i in ("%RETURNED_BIN_DIR%") do set BIN_DIR=%%~fi
+
+rem Get absolute full name for SDK_DIR.
+for %%i in ("%BIN_DIR%\..\") do set SDK_DIR=%%~fi
+
+rem Remove trailing backslash if there is one
+IF %SDK_DIR:~-1%==\ set SDK_DIR=%SDK_DIR:~0,-1%
+
+set DART=%BIN_DIR%\dart
+set SNAPSHOT=%BIN_DIR%\snapshots\dart2js.dart.snapshot
+
+set EXTRA_OPTIONS=
+set EXTRA_VM_OPTIONS=
+
+if _%DART2JS_DEVELOPER_MODE%_ == _1_ (
+  set EXTRA_VM_OPTIONS=%EXTRA_VM_OPTIONS% --enable-asserts
+)
+
+if exist "%SNAPSHOT%" (
+  set EXTRA_OPTIONS=%EXTRA_OPTIONS% "--libraries-spec=%SDK_DIR%\lib\libraries.json"
+)
+
+rem We allow extra vm options to be passed in through an environment variable.
+if not "_%DART_VM_OPTIONS%_" == "__" (
+  set EXTRA_VM_OPTIONS=%EXTRA_VM_OPTIONS% %DART_VM_OPTIONS%
+)
+
+"%DART%" %EXTRA_VM_OPTIONS% "%SNAPSHOT%" %EXTRA_OPTIONS% %*
+
+endlocal
+
+exit /b %errorlevel%
+
+:follow_links
+setlocal
+for %%i in (%1) do set result=%%~fi
+set current=
+for /f "usebackq tokens=2 delims=[]" %%i in (`dir /a:l "%~dp1" 2^>nul ^
+                                             ^| find ">     %~n1 [" 2^>nul`) do (
+  set current=%%i
+)
+if not "%current%"=="" call :follow_links "%current%", result
+endlocal & set %~2=%result%
+goto :eof
+
+:end
diff --git a/sdk_nnbd/bin/dart2native b/sdk_nnbd/bin/dart2native
new file mode 100755
index 0000000..29f29d7
--- /dev/null
+++ b/sdk_nnbd/bin/dart2native
@@ -0,0 +1,25 @@
+#!/usr/bin/env bash
+# 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.
+
+# Run dart2native.dart.snapshot on the Dart VM
+
+function follow_links() {
+  file="$1"
+  while [ -h "$file" ]; do
+    # On Mac OS, readlink -f doesn't work.
+    file="$(readlink "$file")"
+  done
+  echo "$file"
+}
+
+# Unlike $0, $BASH_SOURCE points to the absolute path of this file.
+PROG_NAME="$(follow_links "$BASH_SOURCE")"
+
+# Handle the case where dart-sdk/bin has been symlinked to.
+BIN_DIR="$(cd "${PROG_NAME%/*}" ; pwd -P)"
+SNAPSHOTS_DIR="${BIN_DIR}/snapshots"
+DART="$BIN_DIR/dart"
+
+exec "$DART" "${SNAPSHOTS_DIR}/dart2native.dart.snapshot" $*
diff --git a/sdk_nnbd/bin/dart2native.bat b/sdk_nnbd/bin/dart2native.bat
new file mode 100644
index 0000000..631dce8
--- /dev/null
+++ b/sdk_nnbd/bin/dart2native.bat
@@ -0,0 +1,43 @@
+@echo off
+REM Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+REM for details. All rights reserved. Use of this source code is governed by a
+REM BSD-style license that can be found in the LICENSE file.
+
+setlocal
+rem Handle the case where dart-sdk/bin has been symlinked to.
+set DIR_NAME_WITH_SLASH=%~dp0
+set DIR_NAME=%DIR_NAME_WITH_SLASH:~0,-1%%
+call :follow_links "%DIR_NAME%", RETURNED_BIN_DIR
+rem Get rid of surrounding quotes.
+for %%i in ("%RETURNED_BIN_DIR%") do set BIN_DIR=%%~fi
+
+set DART=%BIN_DIR%\dart
+
+"%DART%" "%BIN_DIR%\snapshots\dart2native.dart.snapshot" %*
+
+endlocal
+
+exit /b %errorlevel%
+
+rem Follow the symbolic links (junctions points) using `dir to determine the
+rem canonical path. Output with a link looks something like this
+rem
+rem 01/03/2013  10:11 PM    <JUNCTION>     abc def
+rem [c:\dart_bleeding\dart-repo.9\dart\out\ReleaseIA32\dart-sdk]
+rem
+rem So in the output of 'dir /a:l "targetdir"' we are looking for a filename
+rem surrounded by right angle bracket and left square bracket. Once we get
+rem the filename, which is name of the link, we recursively follow that.
+:follow_links
+setlocal
+for %%i in (%1) do set result=%%~fi
+set current=
+for /f "usebackq tokens=2 delims=[]" %%i in (`dir /a:l "%~dp1" 2^>nul ^
+                                             ^| %SystemRoot%\System32\find.exe ">     %~n1 [" 2^>nul`) do (
+  set current=%%i
+)
+if not "%current%"=="" call :follow_links "%current%", result
+endlocal & set %~2=%result%
+goto :eof
+
+:end
diff --git a/sdk_nnbd/bin/dartanalyzer b/sdk_nnbd/bin/dartanalyzer
new file mode 100755
index 0000000..7ea062c
--- /dev/null
+++ b/sdk_nnbd/bin/dartanalyzer
@@ -0,0 +1,50 @@
+#!/usr/bin/env bash
+# Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+# Run dartanalyzer.dart on the Dart VM. This script assumes the Dart repo's
+# directory structure.
+
+function follow_links() {
+  file="$1"
+  while [ -h "$file" ]; do
+    # On Mac OS, readlink -f doesn't work.
+    file="$(readlink "$file")"
+  done
+  echo "$file"
+}
+
+# Unlike $0, $BASH_SOURCE points to the absolute path of this file.
+PROG_NAME="$(follow_links "$BASH_SOURCE")"
+
+# Handle the case where dart-sdk/bin has been symlinked to.
+BIN_DIR="$(cd "${PROG_NAME%/*}" ; pwd -P)"
+SDK_DIR="$(cd "${BIN_DIR}/.." ; pwd -P)"
+
+SDK_ARG="--dart-sdk=$SDK_DIR"
+
+DART="$BIN_DIR/dart"
+
+unset EXTRA_VM_OPTIONS
+declare -a EXTRA_VM_OPTIONS
+
+case $0 in
+  *_developer)
+    EXTRA_VM_OPTIONS+=('--enable-asserts')
+    ;;
+esac
+
+# We allow extra vm options to be passed in through an environment variable.
+if [[ $DART_VM_OPTIONS ]]; then
+  read -a OPTIONS <<< "$DART_VM_OPTIONS"
+  EXTRA_VM_OPTIONS+=("${OPTIONS[@]}")
+fi
+
+DART_ROOT="$(cd "${SDK_DIR}/.." ; pwd -P)"
+
+ANALYZER="$DART_ROOT/pkg/analyzer_cli/bin/analyzer.dart"
+
+DEV_OPTIONS="--use-analysis-driver-memory-byte-store"
+
+exec "$DART" "--packages=$DART_ROOT/.packages" "${EXTRA_VM_OPTIONS[@]}" "$ANALYZER" "$DEV_OPTIONS" "$SDK_ARG" "$@"
diff --git a/sdk_nnbd/bin/dartanalyzer.bat b/sdk_nnbd/bin/dartanalyzer.bat
new file mode 100644
index 0000000..efa3a6a
--- /dev/null
+++ b/sdk_nnbd/bin/dartanalyzer.bat
@@ -0,0 +1,70 @@
+@echo off
+REM Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+REM for details. All rights reserved. Use of this source code is governed by a
+REM BSD-style license that can be found in the LICENSE file.
+
+setlocal
+rem Handle the case where dart-sdk/bin has been symlinked to.
+set DIR_NAME_WITH_SLASH=%~dp0
+set DIR_NAME=%DIR_NAME_WITH_SLASH:~0,-1%%
+call :follow_links "%DIR_NAME%", RETURNED_BIN_DIR
+rem Get rid of surrounding quotes.
+for %%i in ("%RETURNED_BIN_DIR%") do set BIN_DIR=%%~fi
+
+set DART=%BIN_DIR%\dart
+
+rem Get absolute full name for SDK_DIR.
+for %%i in ("%BIN_DIR%\..\") do set SDK_DIR=%%~fi
+
+rem Remove trailing backslash if there is one
+if %SDK_DIR:~-1%==\ set SDK_DIR=%SDK_DIR:~0,-1%
+
+set SDK_ARG=--dart-sdk=%SDK_DIR%
+
+set EXTRA_VM_OPTIONS=
+
+if _%DARTANALYZER_DEVELOPER_MODE%_ == _1_ (
+  set EXTRA_VM_OPTIONS=%EXTRA_VM_OPTIONS% --enable_asserts
+)
+
+rem We allow extra vm options to be passed in through an environment variable.
+if not "_%DART_VM_OPTIONS%_" == "__" (
+  set EXTRA_VM_OPTIONS=%EXTRA_VM_OPTIONS% %DART_VM_OPTIONS%
+)
+
+rem Get absolute full name for DART_ROOT.
+for %%i in ("%SDK_DIR%\..\") do set DART_ROOT=%%~fi
+
+rem Remove trailing backslash if there is one
+if %DART_ROOT:~-1%==\ set DART_ROOT=%DART_ROOT:~0,-1%
+
+set ANALYZER=%DART_ROOT%\pkg\analyzer_cli\bin\analyzer.dart
+
+"%DART%" "--packages=%DART_ROOT%\.packages" %EXTRA_VM_OPTIONS% "%ANALYZER%" "%SDK_ARG%" %*
+
+endlocal
+
+exit /b %errorlevel%
+
+rem Follow the symbolic links (junctions points) using `dir to determine the
+rem canonical path. Output with a link looks something like this
+rem
+rem 01/03/2013  10:11 PM    <JUNCTION>     abc def
+rem [c:\dart_bleeding\dart-repo.9\dart\out\ReleaseIA32\dart-sdk]
+rem
+rem So in the output of 'dir /a:l "targetdir"' we are looking for a filename
+rem surrounded by right angle bracket and left square bracket. Once we get
+rem the filename, which is name of the link, we recursively follow that.
+:follow_links
+setlocal
+for %%i in (%1) do set result=%%~fi
+set current=
+for /f "usebackq tokens=2 delims=[]" %%i in (`dir /a:l "%~dp1" 2^>nul ^
+                                             ^| %SystemRoot%\System32\find.exe ">     %~n1 [" 2^>nul`) do (
+  set current=%%i
+)
+if not "%current%"=="" call :follow_links "%current%", result
+endlocal & set %~2=%result%
+goto :eof
+
+:end
diff --git a/sdk_nnbd/bin/dartanalyzer_developer b/sdk_nnbd/bin/dartanalyzer_developer
new file mode 100755
index 0000000..373dc67
--- /dev/null
+++ b/sdk_nnbd/bin/dartanalyzer_developer
@@ -0,0 +1,6 @@
+#!/usr/bin/env bash
+# Copyright (c) 2014, 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.
+
+. ${BASH_SOURCE%_developer}
diff --git a/sdk_nnbd/bin/dartanalyzer_developer.bat b/sdk_nnbd/bin/dartanalyzer_developer.bat
new file mode 100644
index 0000000..b560fe8
--- /dev/null
+++ b/sdk_nnbd/bin/dartanalyzer_developer.bat
@@ -0,0 +1,10 @@
+@echo off
+REM Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+REM for details. All rights reserved. Use of this source code is governed by a
+REM BSD-style license that can be found in the LICENSE file.
+
+setlocal
+set DARTANALYZER_DEVELOPER_MODE=1
+call "%~dp0dartanalyzer.bat" %*
+endlocal
+exit /b %errorlevel%
diff --git a/sdk_nnbd/bin/dartanalyzer_sdk b/sdk_nnbd/bin/dartanalyzer_sdk
new file mode 100755
index 0000000..28f37ab
--- /dev/null
+++ b/sdk_nnbd/bin/dartanalyzer_sdk
@@ -0,0 +1,31 @@
+#!/usr/bin/env bash
+# Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+# Run dartanalyzer.dart on the Dart VM. This script assumes the Dart SDK's
+# directory structure.
+
+function follow_links() {
+  file="$1"
+  while [ -h "$file" ]; do
+    # On Mac OS, readlink -f doesn't work.
+    file="$(readlink "$file")"
+  done
+  echo "$file"
+}
+
+# Unlike $0, $BASH_SOURCE points to the absolute path of this file.
+PROG_NAME="$(follow_links "$BASH_SOURCE")"
+
+# Handle the case where dart-sdk/bin has been symlinked to.
+BIN_DIR="$(cd "${PROG_NAME%/*}" ; pwd -P)"
+SDK_DIR="$(cd "${BIN_DIR}/.." ; pwd -P)"
+
+SDK_ARG="--dart-sdk=$SDK_DIR"
+
+SNAPSHOT="$BIN_DIR/snapshots/dartanalyzer.dart.snapshot"
+
+# We are running the snapshot in the built SDK.
+DART="$BIN_DIR/dart"
+exec "$DART" "$SNAPSHOT" "$SDK_ARG" "$@"
diff --git a/sdk_nnbd/bin/dartanalyzer_sdk.bat b/sdk_nnbd/bin/dartanalyzer_sdk.bat
new file mode 100644
index 0000000..ab66885
--- /dev/null
+++ b/sdk_nnbd/bin/dartanalyzer_sdk.bat
@@ -0,0 +1,52 @@
+@echo off
+REM Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+REM for details. All rights reserved. Use of this source code is governed by a
+REM BSD-style license that can be found in the LICENSE file.
+
+setlocal
+rem Handle the case where dart-sdk/bin has been symlinked to.
+set DIR_NAME_WITH_SLASH=%~dp0
+set DIR_NAME=%DIR_NAME_WITH_SLASH:~0,-1%%
+call :follow_links "%DIR_NAME%", RETURNED_BIN_DIR
+rem Get rid of surrounding quotes.
+for %%i in ("%RETURNED_BIN_DIR%") do set BIN_DIR=%%~fi
+
+set DART=%BIN_DIR%\dart
+set SNAPSHOT=%BIN_DIR%\snapshots\dartanalyzer.dart.snapshot
+
+rem Get absolute full name for SDK_DIR.
+for %%i in ("%BIN_DIR%\..\") do set SDK_DIR=%%~fi
+
+rem Remove trailing backslash if there is one
+if %SDK_DIR:~-1%==\ set SDK_DIR=%SDK_DIR:~0,-1%
+
+set SDK_ARG=--dart-sdk=%SDK_DIR%
+
+"%DART%" "%SNAPSHOT%" "%SDK_ARG%" %*
+
+endlocal
+
+exit /b %errorlevel%
+
+rem Follow the symbolic links (junctions points) using `dir to determine the
+rem canonical path. Output with a link looks something like this
+rem
+rem 01/03/2013  10:11 PM    <JUNCTION>     abc def
+rem [c:\dart_bleeding\dart-repo.9\dart\out\ReleaseIA32\dart-sdk]
+rem
+rem So in the output of 'dir /a:l "targetdir"' we are looking for a filename
+rem surrounded by right angle bracket and left square bracket. Once we get
+rem the filename, which is name of the link, we recursively follow that.
+:follow_links
+setlocal
+for %%i in (%1) do set result=%%~fi
+set current=
+for /f "usebackq tokens=2 delims=[]" %%i in (`dir /a:l "%~dp1" 2^>nul ^
+                                             ^| find ">     %~n1 [" 2^>nul`) do (
+  set current=%%i
+)
+if not "%current%"=="" call :follow_links "%current%", result
+endlocal & set %~2=%result%
+goto :eof
+
+:end
diff --git a/sdk_nnbd/bin/dartdevc b/sdk_nnbd/bin/dartdevc
new file mode 100755
index 0000000..5b75ad2
--- /dev/null
+++ b/sdk_nnbd/bin/dartdevc
@@ -0,0 +1,48 @@
+#!/usr/bin/env bash
+# Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+# Run dev compiler on the Dart VM. This script assumes the Dart repo's
+# directory structure.
+
+function follow_links() {
+  file="$1"
+  while [ -h "$file" ]; do
+    # On Mac OS, readlink -f doesn't work.
+    file="$(readlink "$file")"
+  done
+  echo "$file"
+}
+
+# Unlike $0, $BASH_SOURCE points to the absolute path of this file.
+PROG_NAME="$(follow_links "$BASH_SOURCE")"
+
+# Handle the case where dart-sdk/bin has been symlinked to.
+BIN_DIR="$(cd "${PROG_NAME%/*}" ; pwd -P)"
+SDK_DIR="$(cd "${BIN_DIR}/.." ; pwd -P)"
+
+SDK_ARG="--dart-sdk=$SDK_DIR"
+
+DART="$BIN_DIR/dart"
+
+unset EXTRA_VM_OPTIONS
+declare -a EXTRA_VM_OPTIONS
+
+case $0 in
+  *_developer)
+    EXTRA_VM_OPTIONS+=('--checked')
+    ;;
+esac
+
+# We allow extra vm options to be passed in through an environment variable.
+if [[ $DART_VM_OPTIONS ]]; then
+  read -a OPTIONS <<< "$DART_VM_OPTIONS"
+  EXTRA_VM_OPTIONS+=("${OPTIONS[@]}")
+fi
+
+DART_ROOT="$(cd "${SDK_DIR}/.." ; pwd -P)"
+
+DEV_COMPILER="$DART_ROOT/pkg/dev_compiler/bin/dartdevc.dart"
+
+exec "$DART" "--packages=$DART_ROOT/.packages" "${EXTRA_VM_OPTIONS[@]}" "$DEV_COMPILER" "$SDK_ARG" "$@"
diff --git a/sdk_nnbd/bin/dartdevc.bat b/sdk_nnbd/bin/dartdevc.bat
new file mode 100644
index 0000000..fec39e4
--- /dev/null
+++ b/sdk_nnbd/bin/dartdevc.bat
@@ -0,0 +1,66 @@
+@echo off
+REM Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+REM for details. All rights reserved. Use of this source code is governed by a
+REM BSD-style license that can be found in the LICENSE file.
+
+setlocal
+rem Handle the case where dart-sdk/bin has been symlinked to.
+set DIR_NAME_WITH_SLASH=%~dp0
+set DIR_NAME=%DIR_NAME_WITH_SLASH:~0,-1%%
+call :follow_links "%DIR_NAME%", RETURNED_BIN_DIR
+rem Get rid of surrounding quotes.
+for %%i in ("%RETURNED_BIN_DIR%") do set BIN_DIR=%%~fi
+
+set DART=%BIN_DIR%\dart
+
+rem Get absolute full name for SDK_DIR.
+for %%i in ("%BIN_DIR%\..\") do set SDK_DIR=%%~fi
+
+rem Remove trailing backslash if there is one
+if %SDK_DIR:~-1%==\ set SDK_DIR=%SDK_DIR:~0,-1%
+
+set SDK_ARG=--dart-sdk=%SDK_DIR%
+
+set EXTRA_VM_OPTIONS=
+
+rem We allow extra vm options to be passed in through an environment variable.
+if not "_%DART_VM_OPTIONS%_" == "__" (
+  set EXTRA_VM_OPTIONS=%EXTRA_VM_OPTIONS% %DART_VM_OPTIONS%
+)
+
+rem Get absolute full name for DART_ROOT.
+for %%i in ("%SDK_DIR%\..\") do set DART_ROOT=%%~fi
+
+rem Remove trailing backslash if there is one
+if %DART_ROOT:~-1%==\ set DART_ROOT=%DART_ROOT:~0,-1%
+
+set DEV_COMPILER=%DART_ROOT%\third_party\pkg\dev_compiler\bin\dartdevc.dart
+
+"%DART%" "--packages=%DART_ROOT%\.packages" %EXTRA_VM_OPTIONS% "DEV_COMPILER%" "%SDK_ARG%" %*
+
+endlocal
+
+exit /b %errorlevel%
+
+rem Follow the symbolic links (junctions points) using `dir to determine the
+rem canonical path. Output with a link looks something like this
+rem
+rem 01/03/2013  10:11 PM    <JUNCTION>     abc def
+rem [c:\dart_bleeding\dart-repo.9\dart\out\ReleaseIA32\dart-sdk]
+rem
+rem So in the output of 'dir /a:l "targetdir"' we are looking for a filename
+rem surrounded by right angle bracket and left square bracket. Once we get
+rem the filename, which is name of the link, we recursively follow that.
+:follow_links
+setlocal
+for %%i in (%1) do set result=%%~fi
+set current=
+for /f "usebackq tokens=2 delims=[]" %%i in (`dir /a:l "%~dp1" 2^>nul ^
+                                             ^| find ">     %~n1 [" 2^>nul`) do (
+  set current=%%i
+)
+if not "%current%"=="" call :follow_links "%current%", result
+endlocal & set %~2=%result%
+goto :eof
+
+:end
diff --git a/sdk_nnbd/bin/dartdevc_sdk b/sdk_nnbd/bin/dartdevc_sdk
new file mode 100755
index 0000000..60d2fe1
--- /dev/null
+++ b/sdk_nnbd/bin/dartdevc_sdk
@@ -0,0 +1,28 @@
+#!/usr/bin/env bash
+# Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+# Run dev compiler on the Dart VM. This script assumes the Dart SDK's
+# directory structure.
+
+function follow_links() {
+  file="$1"
+  while [ -h "$file" ]; do
+    # On Mac OS, readlink -f doesn't work.
+    file="$(readlink "$file")"
+  done
+  echo "$file"
+}
+
+# Unlike $0, $BASH_SOURCE points to the absolute path of this file.
+PROG_NAME="$(follow_links "$BASH_SOURCE")"
+
+# Handle the case where dart-sdk/bin has been symlinked to.
+BIN_DIR="$(cd "${PROG_NAME%/*}" ; pwd -P)"
+
+SNAPSHOT="$BIN_DIR/snapshots/dartdevc.dart.snapshot"
+
+# We are running the snapshot in the built SDK.
+DART="$BIN_DIR/dart"
+exec "$DART" "$SNAPSHOT" "$@"
diff --git a/sdk_nnbd/bin/dartdevc_sdk.bat b/sdk_nnbd/bin/dartdevc_sdk.bat
new file mode 100644
index 0000000..5dbf707
--- /dev/null
+++ b/sdk_nnbd/bin/dartdevc_sdk.bat
@@ -0,0 +1,52 @@
+@echo off
+REM Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+REM for details. All rights reserved. Use of this source code is governed by a
+REM BSD-style license that can be found in the LICENSE file.
+
+setlocal
+rem Handle the case where dart-sdk/bin has been symlinked to.
+set DIR_NAME_WITH_SLASH=%~dp0
+set DIR_NAME=%DIR_NAME_WITH_SLASH:~0,-1%%
+call :follow_links "%DIR_NAME%", RETURNED_BIN_DIR
+rem Get rid of surrounding quotes.
+for %%i in ("%RETURNED_BIN_DIR%") do set BIN_DIR=%%~fi
+
+set DART=%BIN_DIR%\dart
+set SNAPSHOT=%BIN_DIR%\snapshots\dartdevc.dart.snapshot
+
+rem Get absolute full name for SDK_DIR.
+for %%i in ("%BIN_DIR%\..\") do set SDK_DIR=%%~fi
+
+rem Remove trailing backslash if there is one
+if %SDK_DIR:~-1%==\ set SDK_DIR=%SDK_DIR:~0,-1%
+
+set SDK_ARG=--dart-sdk=%SDK_DIR%
+
+"%DART%" "%SNAPSHOT%" "%SDK_ARG%" %*
+
+endlocal
+
+exit /b %errorlevel%
+
+rem Follow the symbolic links (junctions points) using `dir to determine the
+rem canonical path. Output with a link looks something like this
+rem
+rem 01/03/2013  10:11 PM    <JUNCTION>     abc def
+rem [c:\dart_bleeding\dart-repo.9\dart\out\ReleaseIA32\dart-sdk]
+rem
+rem So in the output of 'dir /a:l "targetdir"' we are looking for a filename
+rem surrounded by right angle bracket and left square bracket. Once we get
+rem the filename, which is name of the link, we recursively follow that.
+:follow_links
+setlocal
+for %%i in (%1) do set result=%%~fi
+set current=
+for /f "usebackq tokens=2 delims=[]" %%i in (`dir /a:l "%~dp1" 2^>nul ^
+                                             ^| find ">     %~n1 ["`) do (
+  set current=%%i
+)
+if not "%current%"=="" call :follow_links "%current%", result
+endlocal & set %~2=%result%
+goto :eof
+
+:end
diff --git a/sdk_nnbd/bin/dartdoc b/sdk_nnbd/bin/dartdoc
new file mode 100755
index 0000000..e9584c1
--- /dev/null
+++ b/sdk_nnbd/bin/dartdoc
@@ -0,0 +1,26 @@
+#!/usr/bin/env bash
+# Copyright (c) 2015, 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.
+
+function follow_links() {
+  file="$1"
+  while [ -h "$file" ]; do
+    # On Mac OS, readlink -f doesn't work.
+    file="$(readlink "$file")"
+  done
+  echo "$file"
+}
+
+# Unlike $0, $BASH_SOURCE points to the absolute path of this file.
+PROG_NAME="$(follow_links "$BASH_SOURCE")"
+
+# Handle the case where dart-sdk/bin has been symlinked to.
+BIN_DIR="$(cd "${PROG_NAME%/*}" ; pwd -P)"
+SDK_DIR="$(cd "${BIN_DIR}/.." ; pwd -P)"
+
+SNAPSHOT="$BIN_DIR/snapshots/dartdoc.dart.snapshot"
+
+# We are running the snapshot in the built SDK.
+DART="$BIN_DIR/dart"
+exec "$DART" "--packages=$BIN_DIR/resources/dartdoc/.packages" "$SNAPSHOT" "$@"
diff --git a/sdk_nnbd/bin/dartdoc.bat b/sdk_nnbd/bin/dartdoc.bat
new file mode 100644
index 0000000..876eb0e
--- /dev/null
+++ b/sdk_nnbd/bin/dartdoc.bat
@@ -0,0 +1,44 @@
+@echo off
+REM Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+REM for details. All rights reserved. Use of this source code is governed by a
+REM BSD-style license that can be found in the LICENSE file.
+
+setlocal
+rem Handle the case where dart-sdk/bin has been symlinked to.
+set DIR_NAME_WITH_SLASH=%~dp0
+set DIR_NAME=%DIR_NAME_WITH_SLASH:~0,-1%%
+call :follow_links "%DIR_NAME%", RETURNED_BIN_DIR
+rem Get rid of surrounding quotes.
+for %%i in ("%RETURNED_BIN_DIR%") do set BIN_DIR=%%~fi
+
+set DART=%BIN_DIR%\dart
+set SNAPSHOT=%BIN_DIR%\snapshots\dartdoc.dart.snapshot
+
+"%DART%" "--packages=%BIN_DIR%/resources/dartdoc/.packages" "%SNAPSHOT%" %*
+
+endlocal
+
+exit /b %errorlevel%
+
+rem Follow the symbolic links (junctions points) using `dir to determine the
+rem canonical path. Output with a link looks something like this
+rem
+rem 01/03/2013  10:11 PM    <JUNCTION>     abc def
+rem [c:\dart_bleeding\dart-repo.9\dart\out\ReleaseIA32\dart-sdk]
+rem
+rem So in the output of 'dir /a:l "targetdir"' we are looking for a filename
+rem surrounded by right angle bracket and left square bracket. Once we get
+rem the filename, which is name of the link, we recursively follow that.
+:follow_links
+setlocal
+for %%i in (%1) do set result=%%~fi
+set current=
+for /f "usebackq tokens=2 delims=[]" %%i in (`dir /a:l "%~dp1" 2^>nul ^
+                                             ^| %SystemRoot%\System32\find.exe ">     %~n1 [" 2^>nul`) do (
+  set current=%%i
+)
+if not "%current%"=="" call :follow_links "%current%", result
+endlocal & set %~2=%result%
+goto :eof
+
+:end
diff --git a/sdk_nnbd/bin/dartfmt b/sdk_nnbd/bin/dartfmt
new file mode 100755
index 0000000..ad54140
--- /dev/null
+++ b/sdk_nnbd/bin/dartfmt
@@ -0,0 +1,31 @@
+#!/usr/bin/env bash
+# Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+# Run dart_style/bin/format.dart on the Dart VM. This script assumes the Dart
+# repo's directory structure.
+
+function follow_links() {
+  file="$1"
+  while [ -h "$file" ]; do
+    # On Mac OS, readlink -f doesn't work.
+    file="$(readlink "$file")"
+  done
+  echo "$file"
+}
+
+# Unlike $0, $BASH_SOURCE points to the absolute path of this file.
+PROG_NAME="$(follow_links "$BASH_SOURCE")"
+
+# Handle the case where dart-sdk/bin has been symlinked to.
+BIN_DIR="$(cd "${PROG_NAME%/*}" ; pwd -P)"
+SDK_DIR="$(cd "${BIN_DIR}/.." ; pwd -P)"
+
+DART="$BIN_DIR/dart"
+
+DART_ROOT="$(cd "${SDK_DIR}/.." ; pwd -P)"
+
+DARTFMT="$DART_ROOT/third_party/pkg_tested/dart_style/bin/format.dart"
+
+exec "$DART" "--packages=$DART_ROOT/.packages" "$DARTFMT" "$@"
diff --git a/sdk_nnbd/bin/dartfmt.bat b/sdk_nnbd/bin/dartfmt.bat
new file mode 100644
index 0000000..7a7412b
--- /dev/null
+++ b/sdk_nnbd/bin/dartfmt.bat
@@ -0,0 +1,57 @@
+@echo off
+REM Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+REM for details. All rights reserved. Use of this source code is governed by a
+REM BSD-style license that can be found in the LICENSE file.
+
+setlocal
+rem Handle the case where dart-sdk/bin has been symlinked to.
+set DIR_NAME_WITH_SLASH=%~dp0
+set DIR_NAME=%DIR_NAME_WITH_SLASH:~0,-1%%
+call :follow_links "%DIR_NAME%", RETURNED_BIN_DIR
+rem Get rid of surrounding quotes.
+for %%i in ("%RETURNED_BIN_DIR%") do set BIN_DIR=%%~fi
+
+set DART=%BIN_DIR%\dart
+
+rem Get absolute full name for SDK_DIR.
+for %%i in ("%BIN_DIR%\..\") do set SDK_DIR=%%~fi
+
+rem Remove trailing backslash if there is one
+if %SDK_DIR:~-1%==\ set SDK_DIR=%SDK_DIR:~0,-1%
+
+rem Get absolute full name for DART_ROOT.
+for %%i in ("%SDK_DIR%\..\") do set DART_ROOT=%%~fi
+
+rem Remove trailing backslash if there is one
+if %DART_ROOT:~-1%==\ set DART_ROOT=%DART_ROOT:~0,-1%
+
+set DARTFMT=%DART_ROOT%\third_party\pkg_tested\dart_style\bin\format.dart
+
+"%DART%" "--packages=%DART_ROOT%\.packages" "%DARTFMT%" %*
+
+endlocal
+
+exit /b %errorlevel%
+
+rem Follow the symbolic links (junctions points) using `dir to determine the
+rem canonical path. Output with a link looks something like this
+rem
+rem 01/03/2013  10:11 PM    <JUNCTION>     abc def
+rem [c:\dart_bleeding\dart-repo.9\dart\out\ReleaseIA32\dart-sdk]
+rem
+rem So in the output of 'dir /a:l "targetdir"' we are looking for a filename
+rem surrounded by right angle bracket and left square bracket. Once we get
+rem the filename, which is name of the link, we recursively follow that.
+:follow_links
+setlocal
+for %%i in (%1) do set result=%%~fi
+set current=
+for /f "usebackq tokens=2 delims=[]" %%i in (`dir /a:l "%~dp1" 2^>nul ^
+                                             ^| %SystemRoot%\System32\find.exe ">     %~n1 [" 2^>nul`) do (
+  set current=%%i
+)
+if not "%current%"=="" call :follow_links "%current%", result
+endlocal & set %~2=%result%
+goto :eof
+
+:end
diff --git a/sdk_nnbd/bin/dartfmt_sdk b/sdk_nnbd/bin/dartfmt_sdk
new file mode 100755
index 0000000..273733c
--- /dev/null
+++ b/sdk_nnbd/bin/dartfmt_sdk
@@ -0,0 +1,29 @@
+#!/usr/bin/env bash
+# Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+# Run dart_style/bin/format.dart on the Dart VM. This script assumes the Dart
+# SDK's directory structure.
+
+function follow_links() {
+  file="$1"
+  while [ -h "$file" ]; do
+    # On Mac OS, readlink -f doesn't work.
+    file="$(readlink "$file")"
+  done
+  echo "$file"
+}
+
+# Unlike $0, $BASH_SOURCE points to the absolute path of this file.
+PROG_NAME="$(follow_links "$BASH_SOURCE")"
+
+# Handle the case where dart-sdk/bin has been symlinked to.
+BIN_DIR="$(cd "${PROG_NAME%/*}" ; pwd -P)"
+SDK_DIR="$(cd "${BIN_DIR}/.." ; pwd -P)"
+
+SNAPSHOT="$BIN_DIR/snapshots/dartfmt.dart.snapshot"
+
+# We are running the snapshot in the built SDK.
+DART="$BIN_DIR/dart"
+exec "$DART" "$SNAPSHOT" "$@"
diff --git a/sdk_nnbd/bin/dartfmt_sdk.bat b/sdk_nnbd/bin/dartfmt_sdk.bat
new file mode 100644
index 0000000..295b977
--- /dev/null
+++ b/sdk_nnbd/bin/dartfmt_sdk.bat
@@ -0,0 +1,44 @@
+@echo off
+REM Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+REM for details. All rights reserved. Use of this source code is governed by a
+REM BSD-style license that can be found in the LICENSE file.
+
+setlocal
+rem Handle the case where dart-sdk/bin has been symlinked to.
+set DIR_NAME_WITH_SLASH=%~dp0
+set DIR_NAME=%DIR_NAME_WITH_SLASH:~0,-1%%
+call :follow_links "%DIR_NAME%", RETURNED_BIN_DIR
+rem Get rid of surrounding quotes.
+for %%i in ("%RETURNED_BIN_DIR%") do set BIN_DIR=%%~fi
+
+set DART=%BIN_DIR%\dart
+set SNAPSHOT=%BIN_DIR%\snapshots\dartfmt.dart.snapshot
+
+"%DART%" "%SNAPSHOT%" %*
+
+endlocal
+
+exit /b %errorlevel%
+
+rem Follow the symbolic links (junctions points) using `dir to determine the
+rem canonical path. Output with a link looks something like this
+rem
+rem 01/03/2013  10:11 PM    <JUNCTION>     abc def
+rem [c:\dart_bleeding\dart-repo.9\dart\out\ReleaseIA32\dart-sdk]
+rem
+rem So in the output of 'dir /a:l "targetdir"' we are looking for a filename
+rem surrounded by right angle bracket and left square bracket. Once we get
+rem the filename, which is name of the link, we recursively follow that.
+:follow_links
+setlocal
+for %%i in (%1) do set result=%%~fi
+set current=
+for /f "usebackq tokens=2 delims=[]" %%i in (`dir /a:l "%~dp1" 2^>nul ^
+                                             ^| find ">     %~n1 ["`) do (
+  set current=%%i
+)
+if not "%current%"=="" call :follow_links "%current%", result
+endlocal & set %~2=%result%
+goto :eof
+
+:end
diff --git a/sdk_nnbd/bin/pub b/sdk_nnbd/bin/pub
new file mode 100755
index 0000000..5dda611
--- /dev/null
+++ b/sdk_nnbd/bin/pub
@@ -0,0 +1,85 @@
+#!/usr/bin/env bash
+# Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+# Run pub.dart on the Dart VM. This script is only used when running pub from
+# within the Dart source repo. The shipped SDK instead uses "pub_sdk", which is
+# renamed to "pub" when the SDK is built.
+
+function follow_links() {
+  file="$1"
+  while [ -h "$file" ]; do
+    # On Mac OS, readlink -f doesn't work.
+    file="$(readlink "$file")"
+  done
+  echo "$file"
+}
+
+# Unlike $0, $BASH_SOURCE points to the absolute path of this file.
+PROG_NAME="$(follow_links "$BASH_SOURCE")"
+
+# Handle the case where dart-sdk/bin has been symlinked to.
+BIN_DIR="$(cd "${PROG_NAME%/*}" ; pwd -P)"
+
+SDK_DIR="$(cd "${BIN_DIR}/.." ; pwd -P)"
+
+SNAPSHOT="$BIN_DIR/snapshots/pub.dart.snapshot"
+
+unset VM_OPTIONS
+declare -a VM_OPTIONS
+
+if [[ `uname` == 'Darwin' ]];
+then
+  OUT_DIR="$BIN_DIR"/../../xcodebuild/
+else
+  OUT_DIR="$BIN_DIR"/../../out/
+fi
+
+# Allow extra VM options to be passed in through an environment variable.
+if [[ $DART_VM_OPTIONS ]]; then
+  read -a OPTIONS <<< "$DART_VM_OPTIONS"
+  VM_OPTIONS+=("${OPTIONS[@]}")
+fi
+
+if [ -z "$DART_CONFIGURATION" ];
+then
+  DIRS=$( ls "$OUT_DIR" )
+  # list of possible configurations in decreasing desirability
+  CONFIGS=("ReleaseX64" "ReleaseIA32" "DebugX64" "DebugIA32"
+    "ReleaseARM"    "ReleaseARM64"    "ReleaseARMV5TE"
+    "DebugARM"      "DebugARM64"      "DebugARMV5TE")
+  DART_CONFIGURATION="None"
+  for CONFIG in ${CONFIGS[*]}
+  do
+    for DIR in $DIRS;
+    do
+      if [ "$CONFIG" = "$DIR" ];
+      then
+        # choose most desirable configuration that is available and break
+        DART_CONFIGURATION="$DIR"
+        break 2
+      fi
+    done
+  done
+  if [ "$DART_CONFIGURATION" = "None" ]
+  then
+    echo "No valid dart configuration found in $OUT_DIR"
+    exit 1
+  fi
+fi
+
+if [[ `uname` == 'Darwin' ]];
+then
+  BUILD_DIR="$SDK_DIR/../xcodebuild/$DART_CONFIGURATION"
+else
+  BUILD_DIR="$SDK_DIR/../out/$DART_CONFIGURATION"
+fi
+
+# Use the Dart binary in the built SDK so pub can find the version file next
+# to it.
+DART="$BUILD_DIR/dart-sdk/bin/dart"
+
+# Run pub.
+PUB="$SDK_DIR/../third_party/pkg/pub/bin/pub.dart"
+exec "$DART" "--packages=$SDK_DIR/../.packages" "${VM_OPTIONS[@]}" "$PUB" "$@"
diff --git a/sdk_nnbd/bin/pub.bat b/sdk_nnbd/bin/pub.bat
new file mode 100644
index 0000000..7eb8b0d
--- /dev/null
+++ b/sdk_nnbd/bin/pub.bat
@@ -0,0 +1,56 @@
+@echo off
+REM Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+REM for details. All rights reserved. Use of this source code is governed by a
+REM BSD-style license that can be found in the LICENSE file.
+
+rem Run pub.dart on the Dart VM. This script is only used when running pub from
+rem within the Dart source repo. The shipped SDK instead uses "pub_sdk.bat",
+rem which is renamed to "pub.bat" when the SDK is built.
+
+setlocal
+rem Handle the case where dart-sdk/bin has been symlinked to.
+set DIR_NAME_WITH_SLASH=%~dp0
+set DIR_NAME=%DIR_NAME_WITH_SLASH:~0,-1%%
+call :follow_links "%DIR_NAME%", RETURNED_BIN_DIR
+rem Get rid of surrounding quotes.
+for %%i in ("%RETURNED_BIN_DIR%") do set BIN_DIR=%%~fi
+
+rem Get absolute full name for SDK_DIR.
+for %%i in ("%BIN_DIR%\..\") do set SDK_DIR=%%~fi
+
+rem Remove trailing backslash if there is one
+IF %SDK_DIR:~-1%==\ set SDK_DIR=%SDK_DIR:~0,-1%
+
+set VM_OPTIONS=
+
+rem We allow extra vm options to be passed in through an environment variable.
+if not "_%DART_VM_OPTIONS%_" == "__" (
+  set VM_OPTIONS=%VM_OPTIONS% %DART_VM_OPTIONS%
+)
+
+rem Use the Dart binary in the built SDK so pub can find the version file next
+rem to it.
+set BUILD_DIR=%SDK_DIR%\..\out\ReleaseX64
+set DART=%BUILD_DIR%\dart-sdk\bin\dart
+
+rem Run pub.
+set PUB="%SDK_DIR%\..\third_party\pkg\pub\bin\pub.dart"
+"%DART%" "--packages=%SDK_DIR%\..\.packages" %VM_OPTIONS% "%PUB%" %*
+
+endlocal
+
+exit /b %errorlevel%
+
+:follow_links
+setlocal
+for %%i in (%1) do set result=%%~fi
+set current=
+for /f "usebackq tokens=2 delims=[]" %%i in (`dir /a:l "%~dp1" 2^>nul ^
+                                             ^| %SystemRoot%\System32\find.exe ">     %~n1 [" 2^>nul`) do (
+  set current=%%i
+)
+if not "%current%"=="" call :follow_links "%current%", result
+endlocal & set %~2=%result%
+goto :eof
+
+:end
diff --git a/sdk_nnbd/bin/pub_sdk b/sdk_nnbd/bin/pub_sdk
new file mode 100755
index 0000000..4d29878
--- /dev/null
+++ b/sdk_nnbd/bin/pub_sdk
@@ -0,0 +1,50 @@
+#!/usr/bin/env bash
+# Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+# Run pub.dart on the Dart VM. This script assumes the Dart SDK's directory
+# structure.
+
+function follow_links() {
+  file="$1"
+  while [ -h "$file" ]; do
+    # On Mac OS, readlink -f doesn't work.
+    file="$(readlink "$file")"
+  done
+  echo "$file"
+}
+
+function array_contains() {
+  local needle="$1"
+  local element
+  shift
+  for element; do [ "$element" = "$needle" ] && return 0; done
+  return 1
+}
+
+# Unlike $0, $BASH_SOURCE points to the absolute path of this file.
+PROG_NAME="$(follow_links "$BASH_SOURCE")"
+
+# Handle the case where dart-sdk/bin has been symlinked to.
+BIN_DIR="$(cd "${PROG_NAME%/*}" ; pwd -P)"
+
+
+unset VM_OPTIONS
+declare -a VM_OPTIONS
+
+# Allow extra VM options to be passed in through an environment variable.
+if [[ $DART_VM_OPTIONS ]]; then
+  read -a OPTIONS <<< "$DART_VM_OPTIONS"
+  VM_OPTIONS+=("${OPTIONS[@]}")
+fi
+
+# Run the pub snapshot.
+DART="$BIN_DIR/dart"
+if array_contains "--no-preview-dart-2" "${VM_OPTIONS[@]}"; then
+  echo "Pub no longer supports Dart 1"
+  exit -1
+else
+  SNAPSHOT="$BIN_DIR/snapshots/pub.dart.snapshot"
+  exec "$DART" "${VM_OPTIONS[@]}" "$SNAPSHOT" "$@"
+fi
diff --git a/sdk_nnbd/bin/pub_sdk.bat b/sdk_nnbd/bin/pub_sdk.bat
new file mode 100644
index 0000000..bde0e4a
--- /dev/null
+++ b/sdk_nnbd/bin/pub_sdk.bat
@@ -0,0 +1,53 @@
+@echo off
+REM Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+REM for details. All rights reserved. Use of this source code is governed by a
+REM BSD-style license that can be found in the LICENSE file.
+
+setlocal
+rem Handle the case where dart-sdk/bin has been symlinked to.
+set DIR_NAME_WITH_SLASH=%~dp0
+set DIR_NAME=%DIR_NAME_WITH_SLASH:~0,-1%%
+call :follow_links "%DIR_NAME%", RETURNED_BIN_DIR
+rem Get rid of surrounding quotes.
+for %%i in ("%RETURNED_BIN_DIR%") do set BIN_DIR=%%~fi
+
+rem Get absolute full name for SDK_DIR.
+for %%i in ("%BIN_DIR%\..\") do set SDK_DIR=%%~fi
+
+rem Remove trailing backslash if there is one
+IF %SDK_DIR:~-1%==\ set SDK_DIR=%SDK_DIR:~0,-1%
+
+set VM_OPTIONS=
+set USING_DART_1=
+
+rem We allow extra vm options to be passed in through an environment variable.
+if not "_%DART_VM_OPTIONS%_" == "__" (
+  set VM_OPTIONS=%VM_OPTIONS% %DART_VM_OPTIONS%
+  for %%o in (%DART_VM_OPTIONS%) do (
+    if "%%o" equ "--no-preview-dart-2" set USING_DART_1=y
+  )
+)
+
+if defined USING_DART_1 (
+  echo "Pub no longer supports Dart 1"
+) else (
+  "%BIN_DIR%\dart" %VM_OPTIONS% "%BIN_DIR%\snapshots\pub.dart.snapshot" %*
+)
+
+endlocal
+
+exit /b %errorlevel%
+
+:follow_links
+setlocal
+for %%i in (%1) do set result=%%~fi
+set current=
+for /f "usebackq tokens=2 delims=[]" %%i in (`dir /a:l "%~dp1" 2^>nul ^
+                                             ^| find ">     %~n1 [" 2^>nul`) do (
+  set current=%%i
+)
+if not "%current%"=="" call :follow_links "%current%", result
+endlocal & set %~2=%result%
+goto :eof
+
+:end
diff --git a/sdk_nnbd/lib/_chrome/dart2js/chrome_dart2js.dart b/sdk_nnbd/lib/_chrome/dart2js/chrome_dart2js.dart
new file mode 100644
index 0000000..023afe4
--- /dev/null
+++ b/sdk_nnbd/lib/_chrome/dart2js/chrome_dart2js.dart
@@ -0,0 +1,1258 @@
+/// Native wrappers for the Chrome packaged app APIs.
+///
+/// These functions allow direct access to the chrome.* APIs, allowing
+/// Chrome packaged apps to be written using Dart.
+///
+/// For more information on these APIs, see the
+/// [chrome.* API documentation](http://developer.chrome.com/apps/api_index.html).
+library _chrome;
+
+import 'dart:_foreign_helper' show JS;
+import 'dart:_js_helper';
+import 'dart:html_common';
+import 'dart:html';
+
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// DO NOT EDIT
+// Auto-generated dart:_chrome library.
+
+/* TODO(sashab): Add "show convertDartClosureToJS" once 'show' works. */
+
+// Generated files below this line.
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/**
+ * A set of utilities for use with the Chrome Extension APIs.
+ *
+ * Allows for easy access to required JS objects.
+ */
+
+/**
+ * A dart object, that is convertible to JS. Used for creating objects in dart,
+ * then passing them to JS.
+ *
+ * Objects that are passable to JS need to implement this interface.
+ */
+abstract class ChromeObject {
+  /*
+   * Default Constructor
+   *
+   * Called by child objects during their regular construction.
+   */
+  ChromeObject() : _jsObject = JS('var', '{}');
+
+  /*
+   * Internal proxy constructor
+   *
+   * Creates a new Dart object using this existing proxy.
+   */
+  ChromeObject._proxy(this._jsObject);
+
+  /*
+   * JS Object Representation
+   */
+  final Object _jsObject;
+}
+
+/**
+ * Useful functions for converting arguments.
+ */
+
+/**
+ * Converts the given map-type argument to js-friendly format, recursively.
+ * Returns the new Map object.
+ */
+Object _convertMapArgument(Map argument) {
+  Map m = new Map();
+  for (Object key in argument.keys) m[key] = convertArgument(argument[key]);
+  return convertDartToNative_Dictionary(m);
+}
+
+/**
+ * Converts the given list-type argument to js-friendly format, recursively.
+ * Returns the new List object.
+ */
+List _convertListArgument(List argument) {
+  List l = new List();
+  for (var i = 0; i < argument.length; i++) l.add(convertArgument(argument[i]));
+  return l;
+}
+
+/**
+ * Converts the given argument Object to js-friendly format, recursively.
+ *
+ * Flattens out all Chrome objects into their corresponding ._toMap()
+ * definitions, then converts them to JS objects.
+ *
+ * Returns the new argument.
+ *
+ * Cannot be used for functions.
+ */
+Object convertArgument(var argument) {
+  if (argument == null) return argument;
+
+  if (argument is num || argument is String || argument is bool)
+    return argument;
+
+  if (argument is ChromeObject) return argument._jsObject;
+
+  if (argument is List) return _convertListArgument(argument);
+
+  if (argument is Map) return _convertMapArgument(argument);
+
+  if (argument is Function)
+    throw new Exception("Cannot serialize Function argument ${argument}.");
+
+  // TODO(sashab): Try and detect whether the argument is already serialized.
+  return argument;
+}
+
+/// Description of a declarative rule for handling events.
+class Rule extends ChromeObject {
+  /*
+   * Public (Dart) constructor
+   */
+  Rule({String id, List conditions, List actions, int priority}) {
+    this.id = id;
+    this.conditions = conditions;
+    this.actions = actions;
+    this.priority = priority;
+  }
+
+  /*
+   * Private (JS) constructor
+   */
+  Rule._proxy(_jsObject) : super._proxy(_jsObject);
+
+  /*
+   * Public accessors
+   */
+  String get id => JS('String', '#.id', this._jsObject);
+
+  void set id(String id) {
+    JS('void', '#.id = #', this._jsObject, id);
+  }
+
+  // TODO(sashab): Wrap these generic Lists somehow.
+  List get conditions => JS('List', '#.conditions', this._jsObject);
+
+  void set conditions(List conditions) {
+    JS('void', '#.conditions = #', this._jsObject, convertArgument(conditions));
+  }
+
+  // TODO(sashab): Wrap these generic Lists somehow.
+  List get actions => JS('List', '#.actions', this._jsObject);
+
+  void set actions(List actions) {
+    JS('void', '#.actions = #', this._jsObject, convertArgument(actions));
+  }
+
+  int get priority => JS('int', '#.priority', this._jsObject);
+
+  void set priority(int priority) {
+    JS('void', '#.priority = #', this._jsObject, priority);
+  }
+}
+
+/**
+ * The Event class.
+ *
+ * Chrome Event classes extend this interface.
+ *
+ * e.g.
+ *
+ *  // chrome.app.runtime.onLaunched
+ *  class Event_ChromeAppRuntimeOnLaunched extends Event {
+ *    // constructor, passing the arity of the callback
+ *    Event_ChromeAppRuntimeOnLaunched(jsObject) :
+ *     super._(jsObject, 1);
+ *
+ *    // methods, strengthening the Function parameter specificity
+ *    void addListener(void callback(LaunchData launchData))
+ *        => super.addListener(callback);
+ *    void removeListener(void callback(LaunchData launchData))
+ *        => super.removeListener(callback);
+ *    bool hasListener(void callback(LaunchData launchData))
+ *        => super.hasListener(callback);
+ *  }
+ *
+ */
+class Event {
+  /*
+   * JS Object Representation
+   */
+  final Object _jsObject;
+
+  /*
+   * Number of arguments the callback takes.
+   */
+  final int _callbackArity;
+
+  /*
+   * Private constructor
+   */
+  Event._(this._jsObject, this._callbackArity);
+
+  /*
+   * Methods
+   */
+
+  /// Registers an event listener <em>callback</em> to an event.
+  void addListener(covariant Function callback) => JS(
+      'void',
+      '#.addListener(#)',
+      this._jsObject,
+      convertDartClosureToJS(callback, this._callbackArity));
+
+  /// Deregisters an event listener <em>callback</em> from an event.
+  void removeListener(covariant Function callback) => JS(
+      'void',
+      '#.removeListener(#)',
+      this._jsObject,
+      convertDartClosureToJS(callback, this._callbackArity));
+
+  /// Returns True if <em>callback</em> is registered to the event.
+  bool hasListener(covariant Function callback) => JS(
+      'bool',
+      '#.hasListener(#)',
+      this._jsObject,
+      convertDartClosureToJS(callback, this._callbackArity));
+
+  /// Returns true if any event listeners are registered to the event.
+  bool hasListeners() => JS('bool', '#.hasListeners()', this._jsObject);
+
+  /// Registers rules to handle events.
+  ///
+  /// [eventName] is the name of the event this function affects and [rules] are
+  /// the rules to be registered. These do not replace previously registered
+  /// rules. [callback] is called with registered rules.
+  ///
+  void addRules(String eventName, List<Rule> rules,
+      [void callback(List<Rule> rules)]) {
+    // proxy the callback
+    void __proxy_callback(List rules) {
+      if (callback != null) {
+        List<Rule> __proxy_rules = new List<Rule>();
+
+        for (Object o in rules) __proxy_rules.add(new Rule._proxy(o));
+
+        callback(__proxy_rules);
+      }
+    }
+
+    JS(
+        'void',
+        '#.addRules(#, #, #)',
+        this._jsObject,
+        convertArgument(eventName),
+        convertArgument(rules),
+        convertDartClosureToJS(__proxy_callback, 1));
+  }
+
+  /// Returns currently registered rules.
+  ///
+  /// [eventName] is the name of the event this function affects and, if an array
+  /// is passed as [ruleIdentifiers], only rules with identifiers contained in
+  /// this array are returned. [callback] is called with registered rules.
+  ///
+  void getRules(String eventName,
+      [List<String> ruleIdentifiers, void callback(List<Rule> rules)]) {
+    // proxy the callback
+    void __proxy_callback(List rules) {
+      if (callback != null) {
+        List<Rule> __proxy_rules = new List<Rule>();
+
+        for (Object o in rules) __proxy_rules.add(new Rule._proxy(o));
+
+        callback(__proxy_rules);
+      }
+    }
+
+    JS(
+        'void',
+        '#.getRules(#, #, #)',
+        this._jsObject,
+        convertArgument(eventName),
+        convertArgument(ruleIdentifiers),
+        convertDartClosureToJS(__proxy_callback, 1));
+  }
+
+  /// Unregisters currently registered rules.
+  ///
+  /// [eventName] is the name of the event this function affects and, if an array
+  /// is passed as [ruleIdentifiers], only rules with identifiers contained in
+  /// this array are unregistered. [callback] is called when the rules are
+  /// unregistered.
+  ///
+  void removeRules(String eventName,
+          [List<String> ruleIdentifiers, void callback()]) =>
+      JS(
+          'void',
+          '#.removeRules(#, #, #)',
+          this._jsObject,
+          convertArgument(eventName),
+          convertArgument(ruleIdentifiers),
+          convertDartClosureToJS(callback, 0));
+}
+
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// chrome.app
+class API_ChromeApp {
+  /*
+   * JS Variable
+   */
+  final Object _jsObject;
+
+  /*
+   * Members
+   */
+  API_app_window window;
+  API_app_runtime runtime;
+
+  /*
+   * Constructor
+   */
+  API_ChromeApp(this._jsObject) {
+    var window_object = JS('', '#.window', this._jsObject);
+    if (window_object == null)
+      throw new UnsupportedError('Not supported by current browser.');
+    window = new API_app_window(window_object);
+
+    var runtime_object = JS('', '#.runtime', this._jsObject);
+    if (runtime_object == null)
+      throw new UnsupportedError('Not supported by current browser.');
+    runtime = new API_app_runtime(runtime_object);
+  }
+}
+
+// chrome
+class API_Chrome {
+  /*
+   * JS Variable
+   */
+  Object _jsObject;
+
+  /*
+   * Members
+   */
+  API_ChromeApp app;
+  API_file_system fileSystem;
+
+  /*
+   * Constructor
+   */
+  API_Chrome() {
+    this._jsObject = JS("Object", "chrome");
+    if (this._jsObject == null)
+      throw new UnsupportedError('Not supported by current browser.');
+
+    var app_object = JS('', '#.app', this._jsObject);
+    if (app_object == null)
+      throw new UnsupportedError('Not supported by current browser.');
+    app = new API_ChromeApp(app_object);
+
+    var file_system_object = JS('', '#.fileSystem', this._jsObject);
+    if (file_system_object == null)
+      throw new UnsupportedError('Not supported by current browser.');
+    fileSystem = new API_file_system(file_system_object);
+  }
+}
+
+// The final chrome objects
+final API_Chrome chrome = new API_Chrome();
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Generated from namespace: app.window
+
+/**
+ * Types
+ */
+
+class AppWindowBounds extends ChromeObject {
+  /*
+   * Public constructor
+   */
+  AppWindowBounds({int left, int top, int width, int height}) {
+    if (left != null) this.left = left;
+    if (top != null) this.top = top;
+    if (width != null) this.width = width;
+    if (height != null) this.height = height;
+  }
+
+  /*
+   * Private constructor
+   */
+  AppWindowBounds._proxy(_jsObject) : super._proxy(_jsObject);
+
+  /*
+   * Public accessors
+   */
+  int get left => JS('int', '#.left', this._jsObject);
+
+  void set left(int left) {
+    JS('void', '#.left = #', this._jsObject, left);
+  }
+
+  int get top => JS('int', '#.top', this._jsObject);
+
+  void set top(int top) {
+    JS('void', '#.top = #', this._jsObject, top);
+  }
+
+  int get width => JS('int', '#.width', this._jsObject);
+
+  void set width(int width) {
+    JS('void', '#.width = #', this._jsObject, width);
+  }
+
+  int get height => JS('int', '#.height', this._jsObject);
+
+  void set height(int height) {
+    JS('void', '#.height = #', this._jsObject, height);
+  }
+}
+
+class AppWindowCreateWindowOptions extends ChromeObject {
+  /*
+   * Public constructor
+   */
+  AppWindowCreateWindowOptions(
+      {String id,
+      int defaultWidth,
+      int defaultHeight,
+      int defaultLeft,
+      int defaultTop,
+      int width,
+      int height,
+      int left,
+      int top,
+      int minWidth,
+      int minHeight,
+      int maxWidth,
+      int maxHeight,
+      String type,
+      String frame,
+      AppWindowBounds bounds,
+      bool transparentBackground,
+      String state,
+      bool hidden,
+      bool resizable,
+      bool singleton}) {
+    if (id != null) this.id = id;
+    if (defaultWidth != null) this.defaultWidth = defaultWidth;
+    if (defaultHeight != null) this.defaultHeight = defaultHeight;
+    if (defaultLeft != null) this.defaultLeft = defaultLeft;
+    if (defaultTop != null) this.defaultTop = defaultTop;
+    if (width != null) this.width = width;
+    if (height != null) this.height = height;
+    if (left != null) this.left = left;
+    if (top != null) this.top = top;
+    if (minWidth != null) this.minWidth = minWidth;
+    if (minHeight != null) this.minHeight = minHeight;
+    if (maxWidth != null) this.maxWidth = maxWidth;
+    if (maxHeight != null) this.maxHeight = maxHeight;
+    if (type != null) this.type = type;
+    if (frame != null) this.frame = frame;
+    if (bounds != null) this.bounds = bounds;
+    if (transparentBackground != null)
+      this.transparentBackground = transparentBackground;
+    if (state != null) this.state = state;
+    if (hidden != null) this.hidden = hidden;
+    if (resizable != null) this.resizable = resizable;
+    if (singleton != null) this.singleton = singleton;
+  }
+
+  /*
+   * Private constructor
+   */
+  AppWindowCreateWindowOptions._proxy(_jsObject) : super._proxy(_jsObject);
+
+  /*
+   * Public accessors
+   */
+  /// Id to identify the window. This will be used to remember the size and
+  /// position of the window and restore that geometry when a window with the
+  /// same id is later opened.
+  String get id => JS('String', '#.id', this._jsObject);
+
+  void set id(String id) {
+    JS('void', '#.id = #', this._jsObject, id);
+  }
+
+  /// Default width of the window. (Deprecated; regular bounds act like this
+  /// now.)
+  int get defaultWidth => JS('int', '#.defaultWidth', this._jsObject);
+
+  void set defaultWidth(int defaultWidth) {
+    JS('void', '#.defaultWidth = #', this._jsObject, defaultWidth);
+  }
+
+  /// Default height of the window. (Deprecated; regular bounds act like this
+  /// now.)
+  int get defaultHeight => JS('int', '#.defaultHeight', this._jsObject);
+
+  void set defaultHeight(int defaultHeight) {
+    JS('void', '#.defaultHeight = #', this._jsObject, defaultHeight);
+  }
+
+  /// Default X coordinate of the window. (Deprecated; regular bounds act like
+  /// this now.)
+  int get defaultLeft => JS('int', '#.defaultLeft', this._jsObject);
+
+  void set defaultLeft(int defaultLeft) {
+    JS('void', '#.defaultLeft = #', this._jsObject, defaultLeft);
+  }
+
+  /// Default Y coordinate of the window. (Deprecated; regular bounds act like
+  /// this now.)
+  int get defaultTop => JS('int', '#.defaultTop', this._jsObject);
+
+  void set defaultTop(int defaultTop) {
+    JS('void', '#.defaultTop = #', this._jsObject, defaultTop);
+  }
+
+  /// Width of the window. (Deprecated; use 'bounds'.)
+  int get width => JS('int', '#.width', this._jsObject);
+
+  void set width(int width) {
+    JS('void', '#.width = #', this._jsObject, width);
+  }
+
+  /// Height of the window. (Deprecated; use 'bounds'.)
+  int get height => JS('int', '#.height', this._jsObject);
+
+  void set height(int height) {
+    JS('void', '#.height = #', this._jsObject, height);
+  }
+
+  /// X coordinate of the window. (Deprecated; use 'bounds'.)
+  int get left => JS('int', '#.left', this._jsObject);
+
+  void set left(int left) {
+    JS('void', '#.left = #', this._jsObject, left);
+  }
+
+  /// Y coordinate of the window. (Deprecated; use 'bounds'.)
+  int get top => JS('int', '#.top', this._jsObject);
+
+  void set top(int top) {
+    JS('void', '#.top = #', this._jsObject, top);
+  }
+
+  /// Minimum width for the lifetime of the window.
+  int get minWidth => JS('int', '#.minWidth', this._jsObject);
+
+  void set minWidth(int minWidth) {
+    JS('void', '#.minWidth = #', this._jsObject, minWidth);
+  }
+
+  /// Minimum height for the lifetime of the window.
+  int get minHeight => JS('int', '#.minHeight', this._jsObject);
+
+  void set minHeight(int minHeight) {
+    JS('void', '#.minHeight = #', this._jsObject, minHeight);
+  }
+
+  /// Maximum width for the lifetime of the window.
+  int get maxWidth => JS('int', '#.maxWidth', this._jsObject);
+
+  void set maxWidth(int maxWidth) {
+    JS('void', '#.maxWidth = #', this._jsObject, maxWidth);
+  }
+
+  /// Maximum height for the lifetime of the window.
+  int get maxHeight => JS('int', '#.maxHeight', this._jsObject);
+
+  void set maxHeight(int maxHeight) {
+    JS('void', '#.maxHeight = #', this._jsObject, maxHeight);
+  }
+
+  /// Type of window to create.
+  String get type => JS('String', '#.type', this._jsObject);
+
+  void set type(String type) {
+    JS('void', '#.type = #', this._jsObject, type);
+  }
+
+  /// Frame type: 'none' or 'chrome' (defaults to 'chrome').
+  String get frame => JS('String', '#.frame', this._jsObject);
+
+  void set frame(String frame) {
+    JS('void', '#.frame = #', this._jsObject, frame);
+  }
+
+  /// Size and position of the content in the window (excluding the titlebar). If
+  /// an id is also specified and a window with a matching id has been shown
+  /// before, the remembered bounds of the window will be used instead.
+  AppWindowBounds get bounds =>
+      new AppWindowBounds._proxy(JS('', '#.bounds', this._jsObject));
+
+  void set bounds(AppWindowBounds bounds) {
+    JS('void', '#.bounds = #', this._jsObject, convertArgument(bounds));
+  }
+
+  /// Enable window background transparency. Only supported in ash. Requires
+  /// experimental API permission.
+  bool get transparentBackground =>
+      JS('bool', '#.transparentBackground', this._jsObject);
+
+  void set transparentBackground(bool transparentBackground) {
+    JS('void', '#.transparentBackground = #', this._jsObject,
+        transparentBackground);
+  }
+
+  /// The initial state of the window, allowing it to be created already
+  /// fullscreen, maximized, or minimized. Defaults to 'normal'.
+  String get state => JS('String', '#.state', this._jsObject);
+
+  void set state(String state) {
+    JS('void', '#.state = #', this._jsObject, state);
+  }
+
+  /// If true, the window will be created in a hidden state. Call show() on the
+  /// window to show it once it has been created. Defaults to false.
+  bool get hidden => JS('bool', '#.hidden', this._jsObject);
+
+  void set hidden(bool hidden) {
+    JS('void', '#.hidden = #', this._jsObject, hidden);
+  }
+
+  /// If true, the window will be resizable by the user. Defaults to true.
+  bool get resizable => JS('bool', '#.resizable', this._jsObject);
+
+  void set resizable(bool resizable) {
+    JS('void', '#.resizable = #', this._jsObject, resizable);
+  }
+
+  /// By default if you specify an id for the window, the window will only be
+  /// created if another window with the same id doesn't already exist. If a
+  /// window with the same id already exists that window is activated instead. If
+  /// you do want to create multiple windows with the same id, you can set this
+  /// property to false.
+  bool get singleton => JS('bool', '#.singleton', this._jsObject);
+
+  void set singleton(bool singleton) {
+    JS('void', '#.singleton = #', this._jsObject, singleton);
+  }
+}
+
+class AppWindowAppWindow extends ChromeObject {
+  /*
+   * Private constructor
+   */
+  AppWindowAppWindow._proxy(_jsObject) : super._proxy(_jsObject);
+
+  /*
+   * Public accessors
+   */
+  /// The JavaScript 'window' object for the created child.
+  // Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+  // for details. All rights reserved. Use of this source code is governed by a
+  // BSD-style license that can be found in the LICENSE file.
+
+  // TODO(sashab, sra): Detect whether this is the current window, or an
+  // external one, and return an appropriately-typed object
+  WindowBase get contentWindow =>
+      JS("Window", "#.contentWindow", this._jsObject);
+
+  /*
+   * Methods
+   */
+  /// Focus the window.
+  void focus() => JS('void', '#.focus()', this._jsObject);
+
+  /// Fullscreens the window.
+  void fullscreen() => JS('void', '#.fullscreen()', this._jsObject);
+
+  /// Is the window fullscreen?
+  bool isFullscreen() => JS('bool', '#.isFullscreen()', this._jsObject);
+
+  /// Minimize the window.
+  void minimize() => JS('void', '#.minimize()', this._jsObject);
+
+  /// Is the window minimized?
+  bool isMinimized() => JS('bool', '#.isMinimized()', this._jsObject);
+
+  /// Maximize the window.
+  void maximize() => JS('void', '#.maximize()', this._jsObject);
+
+  /// Is the window maximized?
+  bool isMaximized() => JS('bool', '#.isMaximized()', this._jsObject);
+
+  /// Restore the window, exiting a maximized, minimized, or fullscreen state.
+  void restore() => JS('void', '#.restore()', this._jsObject);
+
+  /// Move the window to the position (|left|, |top|).
+  void moveTo(int left, int top) =>
+      JS('void', '#.moveTo(#, #)', this._jsObject, left, top);
+
+  /// Resize the window to |width|x|height| pixels in size.
+  void resizeTo(int width, int height) =>
+      JS('void', '#.resizeTo(#, #)', this._jsObject, width, height);
+
+  /// Draw attention to the window.
+  void drawAttention() => JS('void', '#.drawAttention()', this._jsObject);
+
+  /// Clear attention to the window.
+  void clearAttention() => JS('void', '#.clearAttention()', this._jsObject);
+
+  /// Close the window.
+  void close() => JS('void', '#.close()', this._jsObject);
+
+  /// Show the window. Does nothing if the window is already visible.
+  void show() => JS('void', '#.show()', this._jsObject);
+
+  /// Hide the window. Does nothing if the window is already hidden.
+  void hide() => JS('void', '#.hide()', this._jsObject);
+
+  /// Get the window's bounds as a $ref:Bounds object.
+  // Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+  // for details. All rights reserved. Use of this source code is governed by a
+  // BSD-style license that can be found in the LICENSE file.
+
+  // TODO(sashab, kalman): Fix IDL parser to read function return values
+  // correctly. Currently, it just reads void for all functions.
+  AppWindowBounds getBounds() =>
+      new AppWindowBounds._proxy(JS('void', '#.getBounds()', this._jsObject));
+
+  /// Set the window's bounds.
+  void setBounds(AppWindowBounds bounds) =>
+      JS('void', '#.setBounds(#)', this._jsObject, convertArgument(bounds));
+
+  /// Set the app icon for the window (experimental). Currently this is only
+  /// being implemented on Ash. TODO(stevenjb): Investigate implementing this on
+  /// Windows and OSX.
+  void setIcon(String icon_url) =>
+      JS('void', '#.setIcon(#)', this._jsObject, icon_url);
+}
+
+/**
+ * Events
+ */
+
+/// Fired when the window is resized.
+class Event_app_window_onBoundsChanged extends Event {
+  void addListener(void callback()) => super.addListener(callback);
+
+  void removeListener(void callback()) => super.removeListener(callback);
+
+  bool hasListener(void callback()) => super.hasListener(callback);
+
+  Event_app_window_onBoundsChanged(jsObject) : super._(jsObject, 0);
+}
+
+/// Fired when the window is closed.
+class Event_app_window_onClosed extends Event {
+  void addListener(void callback()) => super.addListener(callback);
+
+  void removeListener(void callback()) => super.removeListener(callback);
+
+  bool hasListener(void callback()) => super.hasListener(callback);
+
+  Event_app_window_onClosed(jsObject) : super._(jsObject, 0);
+}
+
+/// Fired when the window is fullscreened.
+class Event_app_window_onFullscreened extends Event {
+  void addListener(void callback()) => super.addListener(callback);
+
+  void removeListener(void callback()) => super.removeListener(callback);
+
+  bool hasListener(void callback()) => super.hasListener(callback);
+
+  Event_app_window_onFullscreened(jsObject) : super._(jsObject, 0);
+}
+
+/// Fired when the window is maximized.
+class Event_app_window_onMaximized extends Event {
+  void addListener(void callback()) => super.addListener(callback);
+
+  void removeListener(void callback()) => super.removeListener(callback);
+
+  bool hasListener(void callback()) => super.hasListener(callback);
+
+  Event_app_window_onMaximized(jsObject) : super._(jsObject, 0);
+}
+
+/// Fired when the window is minimized.
+class Event_app_window_onMinimized extends Event {
+  void addListener(void callback()) => super.addListener(callback);
+
+  void removeListener(void callback()) => super.removeListener(callback);
+
+  bool hasListener(void callback()) => super.hasListener(callback);
+
+  Event_app_window_onMinimized(jsObject) : super._(jsObject, 0);
+}
+
+/// Fired when the window is restored from being minimized or maximized.
+class Event_app_window_onRestored extends Event {
+  void addListener(void callback()) => super.addListener(callback);
+
+  void removeListener(void callback()) => super.removeListener(callback);
+
+  bool hasListener(void callback()) => super.hasListener(callback);
+
+  Event_app_window_onRestored(jsObject) : super._(jsObject, 0);
+}
+
+/**
+ * Functions
+ */
+
+class API_app_window {
+  /*
+   * API connection
+   */
+  Object _jsObject;
+
+  /*
+   * Events
+   */
+  Event_app_window_onBoundsChanged onBoundsChanged;
+  Event_app_window_onClosed onClosed;
+  Event_app_window_onFullscreened onFullscreened;
+  Event_app_window_onMaximized onMaximized;
+  Event_app_window_onMinimized onMinimized;
+  Event_app_window_onRestored onRestored;
+
+  /*
+   * Functions
+   */
+  /// The size and position of a window can be specified in a number of different
+  /// ways. The most simple option is not specifying anything at all, in which
+  /// case a default size and platform dependent position will be used.<br/><br/>
+  /// Another option is to use the bounds property, which will put the window at
+  /// the specified coordinates with the specified size. If the window has a
+  /// frame, it's total size will be the size given plus the size of the frame;
+  /// that is, the size in bounds is the content size, not the window
+  /// size.<br/><br/> To automatically remember the positions of windows you can
+  /// give them ids. If a window has an id, This id is used to remember the size
+  /// and position of the window whenever it is moved or resized. This size and
+  /// position is then used instead of the specified bounds on subsequent opening
+  /// of a window with the same id. If you need to open a window with an id at a
+  /// location other than the remembered default, you can create it hidden, move
+  /// it to the desired location, then show it.
+  // Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+  // for details. All rights reserved. Use of this source code is governed by a
+  // BSD-style license that can be found in the LICENSE file.
+
+  // TODO(sashab): This override is no longer needed once prefixes are removed.
+  void create(String url,
+      [AppWindowCreateWindowOptions options,
+      void callback(AppWindowAppWindow created_window)]) {
+    void __proxy_callback(created_window) {
+      if (callback != null)
+        callback(new AppWindowAppWindow._proxy(created_window));
+    }
+
+    JS('void', '#.create(#, #, #)', this._jsObject, url,
+        convertArgument(options), convertDartClosureToJS(__proxy_callback, 1));
+  }
+
+  /// Returns an $ref:AppWindow object for the current script context (ie
+  /// JavaScript 'window' object). This can also be called on a handle to a
+  /// script context for another page, for example:
+  /// otherWindow.chrome.app.window.current().
+  // Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+  // for details. All rights reserved. Use of this source code is governed by a
+  // BSD-style license that can be found in the LICENSE file.
+
+  // TODO(sashab, kalman): Fix IDL parser to read function return values
+  // correctly. Currently, it just reads void for all functions.
+  AppWindowAppWindow current() =>
+      new AppWindowAppWindow._proxy(JS('void', '#.current()', this._jsObject));
+
+  void initializeAppWindow(Object state) => JS('void',
+      '#.initializeAppWindow(#)', this._jsObject, convertArgument(state));
+
+  API_app_window(this._jsObject) {
+    onBoundsChanged = new Event_app_window_onBoundsChanged(
+        JS('', '#.onBoundsChanged', this._jsObject));
+    onClosed =
+        new Event_app_window_onClosed(JS('', '#.onClosed', this._jsObject));
+    onFullscreened = new Event_app_window_onFullscreened(
+        JS('', '#.onFullscreened', this._jsObject));
+    onMaximized = new Event_app_window_onMaximized(
+        JS('', '#.onMaximized', this._jsObject));
+    onMinimized = new Event_app_window_onMinimized(
+        JS('', '#.onMinimized', this._jsObject));
+    onRestored =
+        new Event_app_window_onRestored(JS('', '#.onRestored', this._jsObject));
+  }
+}
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Generated from namespace: app.runtime
+
+/**
+ * Types
+ */
+
+class AppRuntimeLaunchItem extends ChromeObject {
+  /*
+   * Public constructor
+   */
+  AppRuntimeLaunchItem({FileEntry entry, String type}) {
+    if (entry != null) this.entry = entry;
+    if (type != null) this.type = type;
+  }
+
+  /*
+   * Private constructor
+   */
+  AppRuntimeLaunchItem._proxy(_jsObject) : super._proxy(_jsObject);
+
+  /*
+   * Public accessors
+   */
+  /// FileEntry for the file.
+  FileEntry get entry => JS('FileEntry', '#.entry', this._jsObject);
+
+  void set entry(FileEntry entry) {
+    JS('void', '#.entry = #', this._jsObject, convertArgument(entry));
+  }
+
+  /// The MIME type of the file.
+  String get type => JS('String', '#.type', this._jsObject);
+
+  void set type(String type) {
+    JS('void', '#.type = #', this._jsObject, type);
+  }
+}
+
+class AppRuntimeLaunchData extends ChromeObject {
+  /*
+   * Public constructor
+   */
+  AppRuntimeLaunchData({String id, List<AppRuntimeLaunchItem> items}) {
+    if (id != null) this.id = id;
+    if (items != null) this.items = items;
+  }
+
+  /*
+   * Private constructor
+   */
+  AppRuntimeLaunchData._proxy(_jsObject) : super._proxy(_jsObject);
+
+  /*
+   * Public accessors
+   */
+  /// The id of the file handler that the app is being invoked with.
+  String get id => JS('String', '#.id', this._jsObject);
+
+  void set id(String id) {
+    JS('void', '#.id = #', this._jsObject, id);
+  }
+
+  List<AppRuntimeLaunchItem> get items {
+    List<AppRuntimeLaunchItem> __proxy_items = new List<AppRuntimeLaunchItem>();
+    int count = JS('int', '#.items.length', this._jsObject);
+    for (int i = 0; i < count; i++) {
+      var item = JS('', '#.items[#]', this._jsObject, i);
+      __proxy_items.add(new AppRuntimeLaunchItem._proxy(item));
+    }
+    return __proxy_items;
+  }
+
+  void set items(List<AppRuntimeLaunchItem> items) {
+    JS('void', '#.items = #', this._jsObject, convertArgument(items));
+  }
+}
+
+/**
+ * Events
+ */
+
+/// Fired when an app is launched from the launcher.
+class Event_app_runtime_onLaunched extends Event {
+  void addListener(void callback(AppRuntimeLaunchData launchData)) {
+    void __proxy_callback(launchData) {
+      if (callback != null) {
+        callback(new AppRuntimeLaunchData._proxy(launchData));
+      }
+    }
+
+    super.addListener(__proxy_callback);
+  }
+
+  void removeListener(void callback(AppRuntimeLaunchData launchData)) {
+    void __proxy_callback(launchData) {
+      if (callback != null) {
+        callback(new AppRuntimeLaunchData._proxy(launchData));
+      }
+    }
+
+    super.removeListener(__proxy_callback);
+  }
+
+  bool hasListener(void callback(AppRuntimeLaunchData launchData)) {
+    void __proxy_callback(launchData) {
+      if (callback != null) {
+        callback(new AppRuntimeLaunchData._proxy(launchData));
+      }
+    }
+
+    super.hasListener(__proxy_callback);
+  }
+
+  Event_app_runtime_onLaunched(jsObject) : super._(jsObject, 1);
+}
+
+/// Fired at Chrome startup to apps that were running when Chrome last shut
+/// down.
+class Event_app_runtime_onRestarted extends Event {
+  void addListener(void callback()) => super.addListener(callback);
+
+  void removeListener(void callback()) => super.removeListener(callback);
+
+  bool hasListener(void callback()) => super.hasListener(callback);
+
+  Event_app_runtime_onRestarted(jsObject) : super._(jsObject, 0);
+}
+
+/**
+ * Functions
+ */
+
+class API_app_runtime {
+  /*
+   * API connection
+   */
+  Object _jsObject;
+
+  /*
+   * Events
+   */
+  Event_app_runtime_onLaunched onLaunched;
+  Event_app_runtime_onRestarted onRestarted;
+  API_app_runtime(this._jsObject) {
+    onLaunched = new Event_app_runtime_onLaunched(
+        JS('', '#.onLaunched', this._jsObject));
+    onRestarted = new Event_app_runtime_onRestarted(
+        JS('', '#.onRestarted', this._jsObject));
+  }
+}
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Generated from namespace: fileSystem
+
+/**
+ * Types
+ */
+
+class FilesystemAcceptOption extends ChromeObject {
+  /*
+   * Public constructor
+   */
+  FilesystemAcceptOption(
+      {String description, List<String> mimeTypes, List<String> extensions}) {
+    if (description != null) this.description = description;
+    if (mimeTypes != null) this.mimeTypes = mimeTypes;
+    if (extensions != null) this.extensions = extensions;
+  }
+
+  /*
+   * Private constructor
+   */
+  FilesystemAcceptOption._proxy(_jsObject) : super._proxy(_jsObject);
+
+  /*
+   * Public accessors
+   */
+  /// This is the optional text description for this option. If not present, a
+  /// description will be automatically generated; typically containing an
+  /// expanded list of valid extensions (e.g. "text/html" may expand to "*.html,
+  /// *.htm").
+  String get description => JS('String', '#.description', this._jsObject);
+
+  void set description(String description) {
+    JS('void', '#.description = #', this._jsObject, description);
+  }
+
+  /// Mime-types to accept, e.g. "image/jpeg" or "audio/*". One of mimeTypes or
+  /// extensions must contain at least one valid element.
+  List<String> get mimeTypes =>
+      JS('List<String>', '#.mimeTypes', this._jsObject);
+
+  void set mimeTypes(List<String> mimeTypes) {
+    JS('void', '#.mimeTypes = #', this._jsObject, mimeTypes);
+  }
+
+  /// Extensions to accept, e.g. "jpg", "gif", "crx".
+  List<String> get extensions =>
+      JS('List<String>', '#.extensions', this._jsObject);
+
+  void set extensions(List<String> extensions) {
+    JS('void', '#.extensions = #', this._jsObject, extensions);
+  }
+}
+
+class FilesystemChooseEntryOptions extends ChromeObject {
+  /*
+   * Public constructor
+   */
+  FilesystemChooseEntryOptions(
+      {String type,
+      String suggestedName,
+      List<FilesystemAcceptOption> accepts,
+      bool acceptsAllTypes}) {
+    if (type != null) this.type = type;
+    if (suggestedName != null) this.suggestedName = suggestedName;
+    if (accepts != null) this.accepts = accepts;
+    if (acceptsAllTypes != null) this.acceptsAllTypes = acceptsAllTypes;
+  }
+
+  /*
+   * Private constructor
+   */
+  FilesystemChooseEntryOptions._proxy(_jsObject) : super._proxy(_jsObject);
+
+  /*
+   * Public accessors
+   */
+  /// Type of the prompt to show. The default is 'openFile'.
+  String get type => JS('String', '#.type', this._jsObject);
+
+  void set type(String type) {
+    JS('void', '#.type = #', this._jsObject, type);
+  }
+
+  /// The suggested file name that will be presented to the user as the default
+  /// name to read or write. This is optional.
+  String get suggestedName => JS('String', '#.suggestedName', this._jsObject);
+
+  void set suggestedName(String suggestedName) {
+    JS('void', '#.suggestedName = #', this._jsObject, suggestedName);
+  }
+
+  /// The optional list of accept options for this file opener. Each option will
+  /// be presented as a unique group to the end-user.
+  List<FilesystemAcceptOption> get accepts {
+    List<FilesystemAcceptOption> __proxy_accepts =
+        new List<FilesystemAcceptOption>();
+    int count = JS('int', '#.accepts.length', this._jsObject);
+    for (int i = 0; i < count; i++) {
+      var item = JS('', '#.accepts[#]', this._jsObject, i);
+      __proxy_accepts.add(new FilesystemAcceptOption._proxy(item));
+    }
+    return __proxy_accepts;
+  }
+
+  void set accepts(List<FilesystemAcceptOption> accepts) {
+    JS('void', '#.accepts = #', this._jsObject, convertArgument(accepts));
+  }
+
+  /// Whether to accept all file types, in addition to the options specified in
+  /// the accepts argument. The default is true. If the accepts field is unset or
+  /// contains no valid entries, this will always be reset to true.
+  bool get acceptsAllTypes => JS('bool', '#.acceptsAllTypes', this._jsObject);
+
+  void set acceptsAllTypes(bool acceptsAllTypes) {
+    JS('void', '#.acceptsAllTypes = #', this._jsObject, acceptsAllTypes);
+  }
+}
+
+/**
+ * Functions
+ */
+
+class API_file_system {
+  /*
+   * API connection
+   */
+  Object _jsObject;
+
+  /*
+   * Functions
+   */
+  /// Get the display path of a FileEntry object. The display path is based on
+  /// the full path of the file on the local file system, but may be made more
+  /// readable for display purposes.
+  void getDisplayPath(FileEntry fileEntry, void callback(String displayPath)) =>
+      JS('void', '#.getDisplayPath(#, #)', this._jsObject,
+          convertArgument(fileEntry), convertDartClosureToJS(callback, 1));
+
+  /// Get a writable FileEntry from another FileEntry. This call will fail if the
+  /// application does not have the 'write' permission under 'fileSystem'.
+  void getWritableEntry(
+      FileEntry fileEntry, void callback(FileEntry fileEntry)) {
+    void __proxy_callback(fileEntry) {
+      if (callback != null) {
+        callback(fileEntry);
+      }
+    }
+
+    JS(
+        'void',
+        '#.getWritableEntry(#, #)',
+        this._jsObject,
+        convertArgument(fileEntry),
+        convertDartClosureToJS(__proxy_callback, 1));
+  }
+
+  /// Gets whether this FileEntry is writable or not.
+  void isWritableEntry(FileEntry fileEntry, void callback(bool isWritable)) =>
+      JS('void', '#.isWritableEntry(#, #)', this._jsObject,
+          convertArgument(fileEntry), convertDartClosureToJS(callback, 1));
+
+  /// Ask the user to choose a file.
+  void chooseEntry(void callback(FileEntry fileEntry),
+      [FilesystemChooseEntryOptions options]) {
+    void __proxy_callback(fileEntry) {
+      if (callback != null) {
+        callback(fileEntry);
+      }
+    }
+
+    JS('void', '#.chooseEntry(#, #)', this._jsObject, convertArgument(options),
+        convertDartClosureToJS(__proxy_callback, 1));
+  }
+
+  /// Returns the file entry with the given id if it can be restored. This call
+  /// will fail otherwise.
+  void restoreEntry(String id, void callback(FileEntry fileEntry)) {
+    void __proxy_callback(fileEntry) {
+      if (callback != null) {
+        callback(fileEntry);
+      }
+    }
+
+    JS('void', '#.restoreEntry(#, #)', this._jsObject, id,
+        convertDartClosureToJS(__proxy_callback, 1));
+  }
+
+  /// Returns whether a file entry for the given id can be restored, i.e. whether
+  /// restoreEntry would succeed with this id now.
+  void isRestorable(String id, void callback(bool isRestorable)) => JS(
+      'void',
+      '#.isRestorable(#, #)',
+      this._jsObject,
+      id,
+      convertDartClosureToJS(callback, 1));
+
+  /// Returns an id that can be passed to restoreEntry to regain access to a
+  /// given file entry. Only the 500 most recently used entries are retained,
+  /// where calls to retainEntry and restoreEntry count as use. If the app has
+  /// the 'retainEntries' permission under 'fileSystem', entries are retained
+  /// indefinitely. Otherwise, entries are retained only while the app is running
+  /// and across restarts.
+  String retainEntry(FileEntry fileEntry) => JS(
+      'String', '#.retainEntry(#)', this._jsObject, convertArgument(fileEntry));
+
+  API_file_system(this._jsObject) {}
+}
diff --git a/sdk_nnbd/lib/_http/crypto.dart b/sdk_nnbd/lib/_http/crypto.dart
new file mode 100644
index 0000000..28b65ee
--- /dev/null
+++ b/sdk_nnbd/lib/_http/crypto.dart
@@ -0,0 +1,458 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart._http;
+
+class _CryptoUtils {
+  static const int PAD = 61; // '='
+  static const int CR = 13; // '\r'
+  static const int LF = 10; // '\n'
+  static const int LINE_LENGTH = 76;
+
+  static const String _encodeTable =
+      "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+  static const String _encodeTableUrlSafe =
+      "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
+
+  // Lookup table used for finding Base 64 alphabet index of a given byte.
+  // -2 : Outside Base 64 alphabet.
+  // -1 : '\r' or '\n'
+  //  0 : = (Padding character).
+  // >0 : Base 64 alphabet index of given byte.
+  static const List<int> _decodeTable = const [
+    -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -1, -2, -2, -1, -2, -2, //
+    -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, //
+    -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, 62, -2, 62, -2, 63, //
+    52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -2, -2, -2, 00, -2, -2, //
+    -2, 00, 01, 02, 03, 04, 05, 06, 07, 08, 09, 10, 11, 12, 13, 14, //
+    15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -2, -2, -2, -2, 63, //
+    -2, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, //
+    41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -2, -2, -2, -2, -2, //
+    -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, //
+    -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, //
+    -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, //
+    -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, //
+    -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, //
+    -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, //
+    -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, //
+    -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2
+  ];
+
+  static Random _rng = new Random.secure();
+
+  static Uint8List getRandomBytes(int count) {
+    final Uint8List result = new Uint8List(count);
+    for (int i = 0; i < count; i++) {
+      result[i] = _rng.nextInt(0xff);
+    }
+    return result;
+  }
+
+  static String bytesToHex(List<int> bytes) {
+    var result = new StringBuffer();
+    for (var part in bytes) {
+      result.write('${part < 16 ? '0' : ''}${part.toRadixString(16)}');
+    }
+    return result.toString();
+  }
+
+  static String bytesToBase64(List<int> bytes,
+      [bool urlSafe = false, bool addLineSeparator = false]) {
+    int len = bytes.length;
+    if (len == 0) {
+      return "";
+    }
+    final String lookup = urlSafe ? _encodeTableUrlSafe : _encodeTable;
+    // Size of 24 bit chunks.
+    final int remainderLength = len.remainder(3);
+    final int chunkLength = len - remainderLength;
+    // Size of base output.
+    int outputLen = ((len ~/ 3) * 4) + ((remainderLength > 0) ? 4 : 0);
+    // Add extra for line separators.
+    if (addLineSeparator) {
+      outputLen += ((outputLen - 1) ~/ LINE_LENGTH) << 1;
+    }
+    List<int> out = new List<int>(outputLen);
+
+    // Encode 24 bit chunks.
+    int j = 0, i = 0, c = 0;
+    while (i < chunkLength) {
+      int x = ((bytes[i++] << 16) & 0xFFFFFF) |
+          ((bytes[i++] << 8) & 0xFFFFFF) |
+          bytes[i++];
+      out[j++] = lookup.codeUnitAt(x >> 18);
+      out[j++] = lookup.codeUnitAt((x >> 12) & 0x3F);
+      out[j++] = lookup.codeUnitAt((x >> 6) & 0x3F);
+      out[j++] = lookup.codeUnitAt(x & 0x3f);
+      // Add optional line separator for each 76 char output.
+      if (addLineSeparator && ++c == 19 && j < outputLen - 2) {
+        out[j++] = CR;
+        out[j++] = LF;
+        c = 0;
+      }
+    }
+
+    // If input length if not a multiple of 3, encode remaining bytes and
+    // add padding.
+    if (remainderLength == 1) {
+      int x = bytes[i];
+      out[j++] = lookup.codeUnitAt(x >> 2);
+      out[j++] = lookup.codeUnitAt((x << 4) & 0x3F);
+      out[j++] = PAD;
+      out[j++] = PAD;
+    } else if (remainderLength == 2) {
+      int x = bytes[i];
+      int y = bytes[i + 1];
+      out[j++] = lookup.codeUnitAt(x >> 2);
+      out[j++] = lookup.codeUnitAt(((x << 4) | (y >> 4)) & 0x3F);
+      out[j++] = lookup.codeUnitAt((y << 2) & 0x3F);
+      out[j++] = PAD;
+    }
+
+    return new String.fromCharCodes(out);
+  }
+
+  static List<int> base64StringToBytes(String input,
+      [bool ignoreInvalidCharacters = true]) {
+    int len = input.length;
+    if (len == 0) {
+      return new List<int>(0);
+    }
+
+    // Count '\r', '\n' and illegal characters, For illegal characters,
+    // if [ignoreInvalidCharacters] is false, throw an exception.
+    int extrasLen = 0;
+    for (int i = 0; i < len; i++) {
+      int c = _decodeTable[input.codeUnitAt(i)];
+      if (c < 0) {
+        extrasLen++;
+        if (c == -2 && !ignoreInvalidCharacters) {
+          throw new FormatException('Invalid character: ${input[i]}');
+        }
+      }
+    }
+
+    if ((len - extrasLen) % 4 != 0) {
+      throw new FormatException('''Size of Base 64 characters in Input
+          must be a multiple of 4. Input: $input''');
+    }
+
+    // Count pad characters, ignore illegal characters at the end.
+    int padLength = 0;
+    for (int i = len - 1; i >= 0; i--) {
+      int currentCodeUnit = input.codeUnitAt(i);
+      if (_decodeTable[currentCodeUnit] > 0) break;
+      if (currentCodeUnit == PAD) padLength++;
+    }
+    int outputLen = (((len - extrasLen) * 6) >> 3) - padLength;
+    List<int> out = new List<int>(outputLen);
+
+    for (int i = 0, o = 0; o < outputLen;) {
+      // Accumulate 4 valid 6 bit Base 64 characters into an int.
+      int x = 0;
+      for (int j = 4; j > 0;) {
+        int c = _decodeTable[input.codeUnitAt(i++)];
+        if (c >= 0) {
+          x = ((x << 6) & 0xFFFFFF) | c;
+          j--;
+        }
+      }
+      out[o++] = x >> 16;
+      if (o < outputLen) {
+        out[o++] = (x >> 8) & 0xFF;
+        if (o < outputLen) out[o++] = x & 0xFF;
+      }
+    }
+    return out;
+  }
+}
+
+// Constants.
+const _MASK_8 = 0xff;
+const _MASK_32 = 0xffffffff;
+const _BITS_PER_BYTE = 8;
+const _BYTES_PER_WORD = 4;
+
+// Base class encapsulating common behavior for cryptographic hash
+// functions.
+abstract class _HashBase {
+  // Hasher state.
+  final int _chunkSizeInWords;
+  final int _digestSizeInWords;
+  final bool _bigEndianWords;
+  int _lengthInBytes = 0;
+  List<int> _pendingData;
+  List<int> _currentChunk;
+  List<int> _h;
+  bool _digestCalled = false;
+
+  _HashBase(
+      this._chunkSizeInWords, this._digestSizeInWords, this._bigEndianWords)
+      : _pendingData = [] {
+    _currentChunk = new List(_chunkSizeInWords);
+    _h = new List(_digestSizeInWords);
+  }
+
+  // Update the hasher with more data.
+  add(List<int> data) {
+    if (_digestCalled) {
+      throw new StateError(
+          'Hash update method called after digest was retrieved');
+    }
+    _lengthInBytes += data.length;
+    _pendingData.addAll(data);
+    _iterate();
+  }
+
+  // Finish the hash computation and return the digest string.
+  List<int> close() {
+    if (_digestCalled) {
+      return _resultAsBytes();
+    }
+    _digestCalled = true;
+    _finalizeData();
+    _iterate();
+    assert(_pendingData.length == 0);
+    return _resultAsBytes();
+  }
+
+  // Returns the block size of the hash in bytes.
+  int get blockSize {
+    return _chunkSizeInWords * _BYTES_PER_WORD;
+  }
+
+  // Create a fresh instance of this Hash.
+  newInstance();
+
+  // One round of the hash computation.
+  _updateHash(List<int> m);
+
+  // Helper methods.
+  _add32(x, y) => (x + y) & _MASK_32;
+  _roundUp(val, n) => (val + n - 1) & -n;
+
+  // Rotate left limiting to unsigned 32-bit values.
+  int _rotl32(int val, int shift) {
+    var mod_shift = shift & 31;
+    return ((val << mod_shift) & _MASK_32) |
+        ((val & _MASK_32) >> (32 - mod_shift));
+  }
+
+  // Compute the final result as a list of bytes from the hash words.
+  List<int> _resultAsBytes() {
+    var result = <int>[];
+    for (var i = 0; i < _h.length; i++) {
+      result.addAll(_wordToBytes(_h[i]));
+    }
+    return result;
+  }
+
+  // Converts a list of bytes to a chunk of 32-bit words.
+  _bytesToChunk(List<int> data, int dataIndex) {
+    assert((data.length - dataIndex) >= (_chunkSizeInWords * _BYTES_PER_WORD));
+
+    for (var wordIndex = 0; wordIndex < _chunkSizeInWords; wordIndex++) {
+      var w3 = _bigEndianWords ? data[dataIndex] : data[dataIndex + 3];
+      var w2 = _bigEndianWords ? data[dataIndex + 1] : data[dataIndex + 2];
+      var w1 = _bigEndianWords ? data[dataIndex + 2] : data[dataIndex + 1];
+      var w0 = _bigEndianWords ? data[dataIndex + 3] : data[dataIndex];
+      dataIndex += 4;
+      var word = (w3 & 0xff) << 24;
+      word |= (w2 & _MASK_8) << 16;
+      word |= (w1 & _MASK_8) << 8;
+      word |= (w0 & _MASK_8);
+      _currentChunk[wordIndex] = word;
+    }
+  }
+
+  // Convert a 32-bit word to four bytes.
+  List<int> _wordToBytes(int word) {
+    List<int> bytes = new List(_BYTES_PER_WORD);
+    bytes[0] = (word >> (_bigEndianWords ? 24 : 0)) & _MASK_8;
+    bytes[1] = (word >> (_bigEndianWords ? 16 : 8)) & _MASK_8;
+    bytes[2] = (word >> (_bigEndianWords ? 8 : 16)) & _MASK_8;
+    bytes[3] = (word >> (_bigEndianWords ? 0 : 24)) & _MASK_8;
+    return bytes;
+  }
+
+  // Iterate through data updating the hash computation for each
+  // chunk.
+  _iterate() {
+    var len = _pendingData.length;
+    var chunkSizeInBytes = _chunkSizeInWords * _BYTES_PER_WORD;
+    if (len >= chunkSizeInBytes) {
+      var index = 0;
+      for (; (len - index) >= chunkSizeInBytes; index += chunkSizeInBytes) {
+        _bytesToChunk(_pendingData, index);
+        _updateHash(_currentChunk);
+      }
+      _pendingData = _pendingData.sublist(index, len);
+    }
+  }
+
+  // Finalize the data. Add a 1 bit to the end of the message. Expand with
+  // 0 bits and add the length of the message.
+  _finalizeData() {
+    _pendingData.add(0x80);
+    var contentsLength = _lengthInBytes + 9;
+    var chunkSizeInBytes = _chunkSizeInWords * _BYTES_PER_WORD;
+    var finalizedLength = _roundUp(contentsLength, chunkSizeInBytes);
+    var zeroPadding = finalizedLength - contentsLength;
+    for (var i = 0; i < zeroPadding; i++) {
+      _pendingData.add(0);
+    }
+    var lengthInBits = _lengthInBytes * _BITS_PER_BYTE;
+    assert(lengthInBits < pow(2, 32));
+    if (_bigEndianWords) {
+      _pendingData.addAll(_wordToBytes(0));
+      _pendingData.addAll(_wordToBytes(lengthInBits & _MASK_32));
+    } else {
+      _pendingData.addAll(_wordToBytes(lengthInBits & _MASK_32));
+      _pendingData.addAll(_wordToBytes(0));
+    }
+  }
+}
+
+// The MD5 hasher is used to compute an MD5 message digest.
+class _MD5 extends _HashBase {
+  _MD5() : super(16, 4, false) {
+    _h[0] = 0x67452301;
+    _h[1] = 0xefcdab89;
+    _h[2] = 0x98badcfe;
+    _h[3] = 0x10325476;
+  }
+
+  // Returns a new instance of this Hash.
+  _MD5 newInstance() {
+    return new _MD5();
+  }
+
+  static const _k = const [
+    0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, 0xf57c0faf, 0x4787c62a, //
+    0xa8304613, 0xfd469501, 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, //
+    0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, 0xf61e2562, 0xc040b340, //
+    0x265e5a51, 0xe9b6c7aa, 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8, //
+    0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, 0xa9e3e905, 0xfcefa3f8, //
+    0x676f02d9, 0x8d2a4c8a, 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, //
+    0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, 0x289b7ec6, 0xeaa127fa, //
+    0xd4ef3085, 0x04881d05, 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, //
+    0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, 0x655b59c3, 0x8f0ccc92, //
+    0xffeff47d, 0x85845dd1, 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, //
+    0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391
+  ];
+
+  static const _r = const [
+    7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 5, 9, 14, //
+    20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 4, 11, 16, 23, 4, 11, //
+    16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 6, 10, 15, 21, 6, 10, 15, 21, 6, //
+    10, 15, 21, 6, 10, 15, 21
+  ];
+
+  // Compute one iteration of the MD5 algorithm with a chunk of
+  // 16 32-bit pieces.
+  void _updateHash(List<int> m) {
+    assert(m.length == 16);
+
+    var a = _h[0];
+    var b = _h[1];
+    var c = _h[2];
+    var d = _h[3];
+
+    var t0;
+    var t1;
+
+    for (var i = 0; i < 64; i++) {
+      if (i < 16) {
+        t0 = (b & c) | ((~b & _MASK_32) & d);
+        t1 = i;
+      } else if (i < 32) {
+        t0 = (d & b) | ((~d & _MASK_32) & c);
+        t1 = ((5 * i) + 1) % 16;
+      } else if (i < 48) {
+        t0 = b ^ c ^ d;
+        t1 = ((3 * i) + 5) % 16;
+      } else {
+        t0 = c ^ (b | (~d & _MASK_32));
+        t1 = (7 * i) % 16;
+      }
+
+      var temp = d;
+      d = c;
+      c = b;
+      b = _add32(
+          b, _rotl32(_add32(_add32(a, t0), _add32(_k[i], m[t1])), _r[i]));
+      a = temp;
+    }
+
+    _h[0] = _add32(a, _h[0]);
+    _h[1] = _add32(b, _h[1]);
+    _h[2] = _add32(c, _h[2]);
+    _h[3] = _add32(d, _h[3]);
+  }
+}
+
+// The SHA1 hasher is used to compute an SHA1 message digest.
+class _SHA1 extends _HashBase {
+  // Construct a SHA1 hasher object.
+  _SHA1()
+      : _w = new List(80),
+        super(16, 5, true) {
+    _h[0] = 0x67452301;
+    _h[1] = 0xEFCDAB89;
+    _h[2] = 0x98BADCFE;
+    _h[3] = 0x10325476;
+    _h[4] = 0xC3D2E1F0;
+  }
+
+  // Returns a new instance of this Hash.
+  _SHA1 newInstance() {
+    return new _SHA1();
+  }
+
+  // Compute one iteration of the SHA1 algorithm with a chunk of
+  // 16 32-bit pieces.
+  void _updateHash(List<int> m) {
+    assert(m.length == 16);
+
+    var a = _h[0];
+    var b = _h[1];
+    var c = _h[2];
+    var d = _h[3];
+    var e = _h[4];
+
+    for (var i = 0; i < 80; i++) {
+      if (i < 16) {
+        _w[i] = m[i];
+      } else {
+        var n = _w[i - 3] ^ _w[i - 8] ^ _w[i - 14] ^ _w[i - 16];
+        _w[i] = _rotl32(n, 1);
+      }
+      var t = _add32(_add32(_rotl32(a, 5), e), _w[i]);
+      if (i < 20) {
+        t = _add32(_add32(t, (b & c) | (~b & d)), 0x5A827999);
+      } else if (i < 40) {
+        t = _add32(_add32(t, (b ^ c ^ d)), 0x6ED9EBA1);
+      } else if (i < 60) {
+        t = _add32(_add32(t, (b & c) | (b & d) | (c & d)), 0x8F1BBCDC);
+      } else {
+        t = _add32(_add32(t, b ^ c ^ d), 0xCA62C1D6);
+      }
+
+      e = d;
+      d = c;
+      c = _rotl32(b, 30);
+      b = a;
+      a = t & _MASK_32;
+    }
+
+    _h[0] = _add32(a, _h[0]);
+    _h[1] = _add32(b, _h[1]);
+    _h[2] = _add32(c, _h[2]);
+    _h[3] = _add32(d, _h[3]);
+    _h[4] = _add32(e, _h[4]);
+  }
+
+  List<int> _w;
+}
diff --git a/sdk_nnbd/lib/_http/http.dart b/sdk_nnbd/lib/_http/http.dart
new file mode 100644
index 0000000..2fc751f
--- /dev/null
+++ b/sdk_nnbd/lib/_http/http.dart
@@ -0,0 +1,2196 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library dart._http;
+
+import 'dart:async';
+import 'dart:collection'
+    show
+        HashMap,
+        HashSet,
+        Queue,
+        ListQueue,
+        LinkedList,
+        LinkedListEntry,
+        UnmodifiableMapView;
+import 'dart:convert';
+import 'dart:developer' hide log;
+import 'dart:_internal' show Since, HttpStatus;
+import 'dart:math';
+import 'dart:io';
+import 'dart:typed_data';
+
+part 'crypto.dart';
+part 'http_date.dart';
+part 'http_headers.dart';
+part 'http_impl.dart';
+part 'http_parser.dart';
+part 'http_session.dart';
+part 'overrides.dart';
+part 'websocket.dart';
+part 'websocket_impl.dart';
+
+/**
+ * A server that delivers content, such as web pages, using the HTTP protocol.
+ *
+ * The HttpServer is a [Stream] that provides [HttpRequest] objects. Each
+ * HttpRequest has an associated [HttpResponse] object.
+ * The server responds to a request by writing to that HttpResponse object.
+ * The following example shows how to bind an HttpServer to an IPv6
+ * [InternetAddress] on port 80 (the standard port for HTTP servers)
+ * and how to listen for requests.
+ * Port 80 is the default HTTP port. However, on most systems accessing
+ * this requires super-user privileges. For local testing consider
+ * using a non-reserved port (1024 and above).
+ *
+ *     import 'dart:io';
+ *
+ *     main() {
+ *       HttpServer
+ *           .bind(InternetAddress.anyIPv6, 80)
+ *           .then((server) {
+ *             server.listen((HttpRequest request) {
+ *               request.response.write('Hello, world!');
+ *               request.response.close();
+ *             });
+ *           });
+ *     }
+ *
+ * Incomplete requests, in which all or part of the header is missing, are
+ * ignored, and no exceptions or HttpRequest objects are generated for them.
+ * Likewise, when writing to an HttpResponse, any [Socket] exceptions are
+ * ignored and any future writes are ignored.
+ *
+ * The HttpRequest exposes the request headers and provides the request body,
+ * if it exists, as a Stream of data. If the body is unread, it is drained
+ * when the server writes to the HttpResponse or closes it.
+ *
+ * ## Bind with a secure HTTPS connection
+ *
+ * Use [bindSecure] to create an HTTPS server.
+ *
+ * The server presents a certificate to the client. The certificate
+ * chain and the private key are set in the [SecurityContext]
+ * object that is passed to [bindSecure].
+ *
+ *     import 'dart:io';
+ *     import "dart:isolate";
+ *
+ *     main() {
+ *       SecurityContext context = new SecurityContext();
+ *       var chain =
+ *           Platform.script.resolve('certificates/server_chain.pem')
+ *           .toFilePath();
+ *       var key =
+ *           Platform.script.resolve('certificates/server_key.pem')
+ *           .toFilePath();
+ *       context.useCertificateChain(chain);
+ *       context.usePrivateKey(key, password: 'dartdart');
+ *
+ *       HttpServer
+ *           .bindSecure(InternetAddress.anyIPv6,
+ *                       443,
+ *                       context)
+ *           .then((server) {
+ *             server.listen((HttpRequest request) {
+ *               request.response.write('Hello, world!');
+ *               request.response.close();
+ *             });
+ *           });
+ *     }
+ *
+ *  The certificates and keys are PEM files, which can be created and
+ *  managed with the tools in OpenSSL.
+ *
+ * ## Connect to a server socket
+ *
+ * You can use the [listenOn] constructor to attach an HTTP server to
+ * a [ServerSocket].
+ *
+ *     import 'dart:io';
+ *
+ *     main() {
+ *       ServerSocket.bind(InternetAddress.anyIPv6, 80)
+ *         .then((serverSocket) {
+ *           HttpServer httpserver = new HttpServer.listenOn(serverSocket);
+ *           serverSocket.listen((Socket socket) {
+ *             socket.write('Hello, client.');
+ *           });
+ *         });
+ *     }
+ *
+ * ## Other resources
+ *
+ * * HttpServer is a Stream. Refer to the [Stream] class for information
+ * about the streaming qualities of an HttpServer.
+ * Pausing the subscription of the stream, pauses at the OS level.
+ *
+ * * The [shelf](https://pub.dartlang.org/packages/shelf)
+ * package on pub.dartlang.org contains a set of high-level classes that,
+ * together with this class, makes it easy to provide content through HTTP
+ * servers.
+ */
+abstract class HttpServer implements Stream<HttpRequest> {
+  /**
+   * Gets and sets the default value of the `Server` header for all responses
+   * generated by this [HttpServer].
+   *
+   * If [serverHeader] is `null`, no `Server` header will be added to each
+   * response.
+   *
+   * The default value is `null`.
+   */
+  String serverHeader;
+
+  /**
+   * Default set of headers added to all response objects.
+   *
+   * By default the following headers are in this set:
+   *
+   *     Content-Type: text/plain; charset=utf-8
+   *     X-Frame-Options: SAMEORIGIN
+   *     X-Content-Type-Options: nosniff
+   *     X-XSS-Protection: 1; mode=block
+   *
+   * If the `Server` header is added here and the `serverHeader` is set as
+   * well then the value of `serverHeader` takes precedence.
+   */
+  HttpHeaders get defaultResponseHeaders;
+
+  /**
+   * Whether the [HttpServer] should compress the content, if possible.
+   *
+   * The content can only be compressed when the response is using
+   * chunked Transfer-Encoding and the incoming request has `gzip`
+   * as an accepted encoding in the Accept-Encoding header.
+   *
+   * The default value is `false` (compression disabled).
+   * To enable, set `autoCompress` to `true`.
+   */
+  bool autoCompress;
+
+  /**
+   * Gets or sets the timeout used for idle keep-alive connections. If no
+   * further request is seen within [idleTimeout] after the previous request was
+   * completed, the connection is dropped.
+   *
+   * Default is 120 seconds.
+   *
+   * Note that it may take up to `2 * idleTimeout` before a idle connection is
+   * aborted.
+   *
+   * To disable, set [idleTimeout] to `null`.
+   */
+  Duration idleTimeout;
+
+  /**
+   * Starts listening for HTTP requests on the specified [address] and
+   * [port].
+   *
+   * The [address] can either be a [String] or an
+   * [InternetAddress]. If [address] is a [String], [bind] will
+   * perform a [InternetAddress.lookup] and use the first value in the
+   * list. To listen on the loopback adapter, which will allow only
+   * incoming connections from the local host, use the value
+   * [InternetAddress.loopbackIPv4] or
+   * [InternetAddress.loopbackIPv6]. To allow for incoming
+   * connection from the network use either one of the values
+   * [InternetAddress.anyIPv4] or [InternetAddress.anyIPv6] to
+   * bind to all interfaces or the IP address of a specific interface.
+   *
+   * If an IP version 6 (IPv6) address is used, both IP version 6
+   * (IPv6) and version 4 (IPv4) connections will be accepted. To
+   * restrict this to version 6 (IPv6) only, use [v6Only] to set
+   * version 6 only. However, if the address is
+   * [InternetAddress.loopbackIPv6], only IP version 6 (IPv6) connections
+   * will be accepted.
+   *
+   * If [port] has the value [:0:] an ephemeral port will be chosen by
+   * the system. The actual port used can be retrieved using the
+   * [port] getter.
+   *
+   * The optional argument [backlog] can be used to specify the listen
+   * backlog for the underlying OS listen setup. If [backlog] has the
+   * value of [:0:] (the default) a reasonable value will be chosen by
+   * the system.
+   *
+   * The optional argument [shared] specifies whether additional HttpServer
+   * objects can bind to the same combination of `address`, `port` and `v6Only`.
+   * If `shared` is `true` and more `HttpServer`s from this isolate or other
+   * isolates are bound to the port, then the incoming connections will be
+   * distributed among all the bound `HttpServer`s. Connections can be
+   * distributed over multiple isolates this way.
+   */
+  static Future<HttpServer> bind(address, int port,
+          {int backlog: 0, bool v6Only: false, bool shared: false}) =>
+      _HttpServer.bind(address, port, backlog, v6Only, shared);
+
+  /**
+   * The [address] can either be a [String] or an
+   * [InternetAddress]. If [address] is a [String], [bind] will
+   * perform a [InternetAddress.lookup] and use the first value in the
+   * list. To listen on the loopback adapter, which will allow only
+   * incoming connections from the local host, use the value
+   * [InternetAddress.loopbackIPv4] or
+   * [InternetAddress.loopbackIPv6]. To allow for incoming
+   * connection from the network use either one of the values
+   * [InternetAddress.anyIPv4] or [InternetAddress.anyIPv6] to
+   * bind to all interfaces or the IP address of a specific interface.
+   *
+   * If an IP version 6 (IPv6) address is used, both IP version 6
+   * (IPv6) and version 4 (IPv4) connections will be accepted. To
+   * restrict this to version 6 (IPv6) only, use [v6Only] to set
+   * version 6 only.
+   *
+   * If [port] has the value [:0:] an ephemeral port will be chosen by
+   * the system. The actual port used can be retrieved using the
+   * [port] getter.
+   *
+   * The optional argument [backlog] can be used to specify the listen
+   * backlog for the underlying OS listen setup. If [backlog] has the
+   * value of [:0:] (the default) a reasonable value will be chosen by
+   * the system.
+   *
+   * If [requestClientCertificate] is true, the server will
+   * request clients to authenticate with a client certificate.
+   * The server will advertise the names of trusted issuers of client
+   * certificates, getting them from a [SecurityContext], where they have been
+   * set using [SecurityContext.setClientAuthorities].
+   *
+   * The optional argument [shared] specifies whether additional HttpServer
+   * objects can bind to the same combination of `address`, `port` and `v6Only`.
+   * If `shared` is `true` and more `HttpServer`s from this isolate or other
+   * isolates are bound to the port, then the incoming connections will be
+   * distributed among all the bound `HttpServer`s. Connections can be
+   * distributed over multiple isolates this way.
+   */
+
+  static Future<HttpServer> bindSecure(
+          address, int port, SecurityContext context,
+          {int backlog: 0,
+          bool v6Only: false,
+          bool requestClientCertificate: false,
+          bool shared: false}) =>
+      _HttpServer.bindSecure(address, port, context, backlog, v6Only,
+          requestClientCertificate, shared);
+
+  /**
+   * Attaches the HTTP server to an existing [ServerSocket]. When the
+   * [HttpServer] is closed, the [HttpServer] will just detach itself,
+   * closing current connections but not closing [serverSocket].
+   */
+  factory HttpServer.listenOn(ServerSocket serverSocket) =>
+      new _HttpServer.listenOn(serverSocket);
+
+  /**
+   * Permanently stops this [HttpServer] from listening for new
+   * connections.  This closes the [Stream] of [HttpRequest]s with a
+   * done event. The returned future completes when the server is
+   * stopped. For a server started using [bind] or [bindSecure] this
+   * means that the port listened on no longer in use.
+   *
+   * If [force] is `true`, active connections will be closed immediately.
+   */
+  Future close({bool force: false});
+
+  /**
+   * Returns the port that the server is listening on. This can be
+   * used to get the actual port used when a value of 0 for [:port:] is
+   * specified in the [bind] or [bindSecure] call.
+   */
+  int get port;
+
+  /**
+   * Returns the address that the server is listening on. This can be
+   * used to get the actual address used, when the address is fetched by
+   * a lookup from a hostname.
+   */
+  InternetAddress get address;
+
+  /**
+   * Sets the timeout, in seconds, for sessions of this [HttpServer].
+   * The default timeout is 20 minutes.
+   */
+  set sessionTimeout(int timeout);
+
+  /**
+   * Returns an [HttpConnectionsInfo] object summarizing the number of
+   * current connections handled by the server.
+   */
+  HttpConnectionsInfo connectionsInfo();
+}
+
+/**
+ * Summary statistics about an [HttpServer]s current socket connections.
+ */
+class HttpConnectionsInfo {
+  /**
+   * Total number of socket connections.
+   */
+  int total = 0;
+
+  /**
+   * Number of active connections where actual request/response
+   * processing is active.
+   */
+  int active = 0;
+
+  /**
+   * Number of idle connections held by clients as persistent connections.
+   */
+  int idle = 0;
+
+  /**
+   * Number of connections which are preparing to close. Note: These
+   * connections are also part of the [:active:] count as they might
+   * still be sending data to the client before finally closing.
+   */
+  int closing = 0;
+}
+
+/**
+ * Headers for HTTP requests and responses.
+ *
+ * In some situations, headers are immutable:
+ *
+ * * HttpRequest and HttpClientResponse always have immutable headers.
+ *
+ * * HttpResponse and HttpClientRequest have immutable headers
+ *   from the moment the body is written to.
+ *
+ * In these situations, the mutating methods throw exceptions.
+ *
+ * For all operations on HTTP headers the header name is
+ * case-insensitive.
+ *
+ * To set the value of a header use the `set()` method:
+ *
+ *     request.headers.set(HttpHeaders.cacheControlHeader,
+ *                         'max-age=3600, must-revalidate');
+ *
+ * To retrieve the value of a header use the `value()` method:
+ *
+ *     print(request.headers.value(HttpHeaders.userAgentHeader));
+ *
+ * An HttpHeaders object holds a list of values for each name
+ * as the standard allows. In most cases a name holds only a single value,
+ * The most common mode of operation is to use `set()` for setting a value,
+ * and `value()` for retrieving a value.
+ */
+abstract class HttpHeaders {
+  static const acceptHeader = "accept";
+  static const acceptCharsetHeader = "accept-charset";
+  static const acceptEncodingHeader = "accept-encoding";
+  static const acceptLanguageHeader = "accept-language";
+  static const acceptRangesHeader = "accept-ranges";
+  static const ageHeader = "age";
+  static const allowHeader = "allow";
+  static const authorizationHeader = "authorization";
+  static const cacheControlHeader = "cache-control";
+  static const connectionHeader = "connection";
+  static const contentEncodingHeader = "content-encoding";
+  static const contentLanguageHeader = "content-language";
+  static const contentLengthHeader = "content-length";
+  static const contentLocationHeader = "content-location";
+  static const contentMD5Header = "content-md5";
+  static const contentRangeHeader = "content-range";
+  static const contentTypeHeader = "content-type";
+  static const dateHeader = "date";
+  static const etagHeader = "etag";
+  static const expectHeader = "expect";
+  static const expiresHeader = "expires";
+  static const fromHeader = "from";
+  static const hostHeader = "host";
+  static const ifMatchHeader = "if-match";
+  static const ifModifiedSinceHeader = "if-modified-since";
+  static const ifNoneMatchHeader = "if-none-match";
+  static const ifRangeHeader = "if-range";
+  static const ifUnmodifiedSinceHeader = "if-unmodified-since";
+  static const lastModifiedHeader = "last-modified";
+  static const locationHeader = "location";
+  static const maxForwardsHeader = "max-forwards";
+  static const pragmaHeader = "pragma";
+  static const proxyAuthenticateHeader = "proxy-authenticate";
+  static const proxyAuthorizationHeader = "proxy-authorization";
+  static const rangeHeader = "range";
+  static const refererHeader = "referer";
+  static const retryAfterHeader = "retry-after";
+  static const serverHeader = "server";
+  static const teHeader = "te";
+  static const trailerHeader = "trailer";
+  static const transferEncodingHeader = "transfer-encoding";
+  static const upgradeHeader = "upgrade";
+  static const userAgentHeader = "user-agent";
+  static const varyHeader = "vary";
+  static const viaHeader = "via";
+  static const warningHeader = "warning";
+  static const wwwAuthenticateHeader = "www-authenticate";
+
+  @Deprecated("Use acceptHeader instead")
+  static const ACCEPT = acceptHeader;
+  @Deprecated("Use acceptCharsetHeader instead")
+  static const ACCEPT_CHARSET = acceptCharsetHeader;
+  @Deprecated("Use acceptEncodingHeader instead")
+  static const ACCEPT_ENCODING = acceptEncodingHeader;
+  @Deprecated("Use acceptLanguageHeader instead")
+  static const ACCEPT_LANGUAGE = acceptLanguageHeader;
+  @Deprecated("Use acceptRangesHeader instead")
+  static const ACCEPT_RANGES = acceptRangesHeader;
+  @Deprecated("Use ageHeader instead")
+  static const AGE = ageHeader;
+  @Deprecated("Use allowHeader instead")
+  static const ALLOW = allowHeader;
+  @Deprecated("Use authorizationHeader instead")
+  static const AUTHORIZATION = authorizationHeader;
+  @Deprecated("Use cacheControlHeader instead")
+  static const CACHE_CONTROL = cacheControlHeader;
+  @Deprecated("Use connectionHeader instead")
+  static const CONNECTION = connectionHeader;
+  @Deprecated("Use contentEncodingHeader instead")
+  static const CONTENT_ENCODING = contentEncodingHeader;
+  @Deprecated("Use contentLanguageHeader instead")
+  static const CONTENT_LANGUAGE = contentLanguageHeader;
+  @Deprecated("Use contentLengthHeader instead")
+  static const CONTENT_LENGTH = contentLengthHeader;
+  @Deprecated("Use contentLocationHeader instead")
+  static const CONTENT_LOCATION = contentLocationHeader;
+  @Deprecated("Use contentMD5Header instead")
+  static const CONTENT_MD5 = contentMD5Header;
+  @Deprecated("Use contentRangeHeader instead")
+  static const CONTENT_RANGE = contentRangeHeader;
+  @Deprecated("Use contentTypeHeader instead")
+  static const CONTENT_TYPE = contentTypeHeader;
+  @Deprecated("Use dateHeader instead")
+  static const DATE = dateHeader;
+  @Deprecated("Use etagHeader instead")
+  static const ETAG = etagHeader;
+  @Deprecated("Use expectHeader instead")
+  static const EXPECT = expectHeader;
+  @Deprecated("Use expiresHeader instead")
+  static const EXPIRES = expiresHeader;
+  @Deprecated("Use fromHeader instead")
+  static const FROM = fromHeader;
+  @Deprecated("Use hostHeader instead")
+  static const HOST = hostHeader;
+  @Deprecated("Use ifMatchHeader instead")
+  static const IF_MATCH = ifMatchHeader;
+  @Deprecated("Use ifModifiedSinceHeader instead")
+  static const IF_MODIFIED_SINCE = ifModifiedSinceHeader;
+  @Deprecated("Use ifNoneMatchHeader instead")
+  static const IF_NONE_MATCH = ifNoneMatchHeader;
+  @Deprecated("Use ifRangeHeader instead")
+  static const IF_RANGE = ifRangeHeader;
+  @Deprecated("Use ifUnmodifiedSinceHeader instead")
+  static const IF_UNMODIFIED_SINCE = ifUnmodifiedSinceHeader;
+  @Deprecated("Use lastModifiedHeader instead")
+  static const LAST_MODIFIED = lastModifiedHeader;
+  @Deprecated("Use locationHeader instead")
+  static const LOCATION = locationHeader;
+  @Deprecated("Use maxForwardsHeader instead")
+  static const MAX_FORWARDS = maxForwardsHeader;
+  @Deprecated("Use pragmaHeader instead")
+  static const PRAGMA = pragmaHeader;
+  @Deprecated("Use proxyAuthenticateHeader instead")
+  static const PROXY_AUTHENTICATE = proxyAuthenticateHeader;
+  @Deprecated("Use proxyAuthorizationHeader instead")
+  static const PROXY_AUTHORIZATION = proxyAuthorizationHeader;
+  @Deprecated("Use rangeHeader instead")
+  static const RANGE = rangeHeader;
+  @Deprecated("Use refererHeader instead")
+  static const REFERER = refererHeader;
+  @Deprecated("Use retryAfterHeader instead")
+  static const RETRY_AFTER = retryAfterHeader;
+  @Deprecated("Use serverHeader instead")
+  static const SERVER = serverHeader;
+  @Deprecated("Use teHeader instead")
+  static const TE = teHeader;
+  @Deprecated("Use trailerHeader instead")
+  static const TRAILER = trailerHeader;
+  @Deprecated("Use transferEncodingHeader instead")
+  static const TRANSFER_ENCODING = transferEncodingHeader;
+  @Deprecated("Use upgradeHeader instead")
+  static const UPGRADE = upgradeHeader;
+  @Deprecated("Use userAgentHeader instead")
+  static const USER_AGENT = userAgentHeader;
+  @Deprecated("Use varyHeader instead")
+  static const VARY = varyHeader;
+  @Deprecated("Use viaHeader instead")
+  static const VIA = viaHeader;
+  @Deprecated("Use warningHeader instead")
+  static const WARNING = warningHeader;
+  @Deprecated("Use wwwAuthenticateHeader instead")
+  static const WWW_AUTHENTICATE = wwwAuthenticateHeader;
+
+  // Cookie headers from RFC 6265.
+  static const cookieHeader = "cookie";
+  static const setCookieHeader = "set-cookie";
+
+  @Deprecated("Use cookieHeader instead")
+  static const COOKIE = cookieHeader;
+  @Deprecated("Use setCookieHeader instead")
+  static const SET_COOKIE = setCookieHeader;
+
+  static const generalHeaders = const [
+    cacheControlHeader,
+    connectionHeader,
+    dateHeader,
+    pragmaHeader,
+    trailerHeader,
+    transferEncodingHeader,
+    upgradeHeader,
+    viaHeader,
+    warningHeader
+  ];
+
+  @Deprecated("Use generalHeaders instead")
+  static const GENERAL_HEADERS = generalHeaders;
+
+  static const entityHeaders = const [
+    allowHeader,
+    contentEncodingHeader,
+    contentLanguageHeader,
+    contentLengthHeader,
+    contentLocationHeader,
+    contentMD5Header,
+    contentRangeHeader,
+    contentTypeHeader,
+    expiresHeader,
+    lastModifiedHeader
+  ];
+
+  @Deprecated("Use entityHeaders instead")
+  static const ENTITY_HEADERS = entityHeaders;
+
+  static const responseHeaders = const [
+    acceptRangesHeader,
+    ageHeader,
+    etagHeader,
+    locationHeader,
+    proxyAuthenticateHeader,
+    retryAfterHeader,
+    serverHeader,
+    varyHeader,
+    wwwAuthenticateHeader
+  ];
+
+  @Deprecated("Use responseHeaders instead")
+  static const RESPONSE_HEADERS = responseHeaders;
+
+  static const requestHeaders = const [
+    acceptHeader,
+    acceptCharsetHeader,
+    acceptEncodingHeader,
+    acceptLanguageHeader,
+    authorizationHeader,
+    expectHeader,
+    fromHeader,
+    hostHeader,
+    ifMatchHeader,
+    ifModifiedSinceHeader,
+    ifNoneMatchHeader,
+    ifRangeHeader,
+    ifUnmodifiedSinceHeader,
+    maxForwardsHeader,
+    proxyAuthorizationHeader,
+    rangeHeader,
+    refererHeader,
+    teHeader,
+    userAgentHeader
+  ];
+
+  @Deprecated("Use requestHeaders instead")
+  static const REQUEST_HEADERS = requestHeaders;
+
+  /**
+   * Gets and sets the date. The value of this property will
+   * reflect the 'date' header.
+   */
+  DateTime date;
+
+  /**
+   * Gets and sets the expiry date. The value of this property will
+   * reflect the 'expires' header.
+   */
+  DateTime expires;
+
+  /**
+   * Gets and sets the "if-modified-since" date. The value of this property will
+   * reflect the "if-modified-since" header.
+   */
+  DateTime ifModifiedSince;
+
+  /**
+   * Gets and sets the host part of the 'host' header for the
+   * connection.
+   */
+  String host;
+
+  /**
+   * Gets and sets the port part of the 'host' header for the
+   * connection.
+   */
+  int port;
+
+  /**
+   * Gets and sets the content type. Note that the content type in the
+   * header will only be updated if this field is set
+   * directly. Mutating the returned current value will have no
+   * effect.
+   */
+  ContentType contentType;
+
+  /**
+   * Gets and sets the content length header value.
+   */
+  int contentLength;
+
+  /**
+   * Gets and sets the persistent connection header value.
+   */
+  bool persistentConnection;
+
+  /**
+   * Gets and sets the chunked transfer encoding header value.
+   */
+  bool chunkedTransferEncoding;
+
+  /**
+   * Returns the list of values for the header named [name]. If there
+   * is no header with the provided name, [:null:] will be returned.
+   */
+  List<String> operator [](String name);
+
+  /**
+   * Convenience method for the value for a single valued header. If
+   * there is no header with the provided name, [:null:] will be
+   * returned. If the header has more than one value an exception is
+   * thrown.
+   */
+  String value(String name);
+
+  /**
+   * Adds a header value. The header named [name] will have the value
+   * [value] added to its list of values. Some headers are single
+   * valued, and for these adding a value will replace the previous
+   * value. If the value is of type DateTime a HTTP date format will be
+   * applied. If the value is a [:List:] each element of the list will
+   * be added separately. For all other types the default [:toString:]
+   * method will be used.
+   */
+  void add(String name, Object value);
+
+  /**
+   * Sets a header. The header named [name] will have all its values
+   * cleared before the value [value] is added as its value.
+   */
+  void set(String name, Object value);
+
+  /**
+   * Removes a specific value for a header name. Some headers have
+   * system supplied values and for these the system supplied values
+   * will still be added to the collection of values for the header.
+   */
+  void remove(String name, Object value);
+
+  /**
+   * Removes all values for the specified header name. Some headers
+   * have system supplied values and for these the system supplied
+   * values will still be added to the collection of values for the
+   * header.
+   */
+  void removeAll(String name);
+
+  /**
+   * Enumerates the headers, applying the function [f] to each
+   * header. The header name passed in [:name:] will be all lower
+   * case.
+   */
+  void forEach(void f(String name, List<String> values));
+
+  /**
+   * Disables folding for the header named [name] when sending the HTTP
+   * header. By default, multiple header values are folded into a
+   * single header line by separating the values with commas. The
+   * 'set-cookie' header has folding disabled by default.
+   */
+  void noFolding(String name);
+
+  /**
+   * Remove all headers. Some headers have system supplied values and
+   * for these the system supplied values will still be added to the
+   * collection of values for the header.
+   */
+  void clear();
+}
+
+/**
+ * Representation of a header value in the form:
+ *
+ *   [:value; parameter1=value1; parameter2=value2:]
+ *
+ * [HeaderValue] can be used to conveniently build and parse header
+ * values on this form.
+ *
+ * To build an [:accepts:] header with the value
+ *
+ *     text/plain; q=0.3, text/html
+ *
+ * use code like this:
+ *
+ *     HttpClientRequest request = ...;
+ *     var v = new HeaderValue("text/plain", {"q": "0.3"});
+ *     request.headers.add(HttpHeaders.acceptHeader, v);
+ *     request.headers.add(HttpHeaders.acceptHeader, "text/html");
+ *
+ * To parse the header values use the [:parse:] static method.
+ *
+ *     HttpRequest request = ...;
+ *     List<String> values = request.headers[HttpHeaders.acceptHeader];
+ *     values.forEach((value) {
+ *       HeaderValue v = HeaderValue.parse(value);
+ *       // Use v.value and v.parameters
+ *     });
+ *
+ * An instance of [HeaderValue] is immutable.
+ */
+abstract class HeaderValue {
+  /**
+   * Creates a new header value object setting the value and parameters.
+   */
+  factory HeaderValue([String value = "", Map<String, String> parameters]) {
+    return new _HeaderValue(value, parameters);
+  }
+
+  /**
+   * Creates a new header value object from parsing a header value
+   * string with both value and optional parameters.
+   */
+  static HeaderValue parse(String value,
+      {String parameterSeparator: ";",
+      String valueSeparator: null,
+      bool preserveBackslash: false}) {
+    return _HeaderValue.parse(value,
+        parameterSeparator: parameterSeparator,
+        valueSeparator: valueSeparator,
+        preserveBackslash: preserveBackslash);
+  }
+
+  /**
+   * Gets the header value.
+   */
+  String get value;
+
+  /**
+   * Gets the map of parameters.
+   *
+   * This map cannot be modified. Invoking any operation which would
+   * modify the map will throw [UnsupportedError].
+   */
+  Map<String, String> get parameters;
+
+  /**
+   * Returns the formatted string representation in the form:
+   *
+   *     value; parameter1=value1; parameter2=value2
+   */
+  String toString();
+}
+
+abstract class HttpSession implements Map {
+  /**
+   * Gets the id for the current session.
+   */
+  String get id;
+
+  /**
+   * Destroys the session. This will terminate the session and any further
+   * connections with this id will be given a new id and session.
+   */
+  void destroy();
+
+  /**
+   * Sets a callback that will be called when the session is timed out.
+   */
+  void set onTimeout(void callback());
+
+  /**
+   * Is true if the session has not been sent to the client yet.
+   */
+  bool get isNew;
+}
+
+/**
+ * Representation of a content type. An instance of [ContentType] is
+ * immutable.
+ */
+abstract class ContentType implements HeaderValue {
+  /**
+   * Content type for plain text using UTF-8 encoding.
+   *
+   *     text/plain; charset=utf-8
+   */
+  static final text = new ContentType("text", "plain", charset: "utf-8");
+  @Deprecated("Use text instead")
+  static final TEXT = text;
+
+  /**
+   *  Content type for HTML using UTF-8 encoding.
+   *
+   *     text/html; charset=utf-8
+   */
+  static final html = new ContentType("text", "html", charset: "utf-8");
+  @Deprecated("Use html instead")
+  static final HTML = html;
+
+  /**
+   *  Content type for JSON using UTF-8 encoding.
+   *
+   *     application/json; charset=utf-8
+   */
+  static final json = new ContentType("application", "json", charset: "utf-8");
+  @Deprecated("Use json instead")
+  static final JSON = json;
+
+  /**
+   *  Content type for binary data.
+   *
+   *     application/octet-stream
+   */
+  static final binary = new ContentType("application", "octet-stream");
+  @Deprecated("Use binary instead")
+  static final BINARY = binary;
+
+  /**
+   * Creates a new content type object setting the primary type and
+   * sub type. The charset and additional parameters can also be set
+   * using [charset] and [parameters]. If charset is passed and
+   * [parameters] contains charset as well the passed [charset] will
+   * override the value in parameters. Keys passed in parameters will be
+   * converted to lower case. The `charset` entry, whether passed as `charset`
+   * or in `parameters`, will have its value converted to lower-case.
+   */
+  factory ContentType(String primaryType, String subType,
+      {String charset, Map<String, String> parameters}) {
+    return new _ContentType(primaryType, subType, charset, parameters);
+  }
+
+  /**
+   * Creates a new content type object from parsing a Content-Type
+   * header value. As primary type, sub type and parameter names and
+   * values are not case sensitive all these values will be converted
+   * to lower case. Parsing this string
+   *
+   *     text/html; charset=utf-8
+   *
+   * will create a content type object with primary type [:text:], sub
+   * type [:html:] and parameter [:charset:] with value [:utf-8:].
+   */
+  static ContentType parse(String value) {
+    return _ContentType.parse(value);
+  }
+
+  /**
+   * Gets the mime-type, without any parameters.
+   */
+  String get mimeType;
+
+  /**
+   * Gets the primary type.
+   */
+  String get primaryType;
+
+  /**
+   * Gets the sub type.
+   */
+  String get subType;
+
+  /**
+   * Gets the character set.
+   */
+  String get charset;
+}
+
+/**
+ * Representation of a cookie. For cookies received by the server as Cookie
+ * header values only [name] and [value] properties will be set. When building a
+ * cookie for the 'set-cookie' header in the server and when receiving cookies
+ * in the client as 'set-cookie' headers all fields can be used.
+ */
+abstract class Cookie {
+  /**
+   * The name of the cookie.
+   *
+   * Must be a `token` as specified in RFC 6265.
+   *
+   * The allowed characters in a `token` are the visible ASCII characters,
+   * U+0021 (`!`) through U+007E (`~`), except the separator characters:
+   * `(`, `)`, `<`, `>`, `@`, `,`, `;`, `:`, `\`, `"`, `/`, `[`, `]`, `?`, `=`,
+   * `{`, and `}`.
+   */
+  String name;
+
+  /**
+   * The value of the cookie.
+   *
+   * Must be a `cookie-value` as specified in RFC 6265.
+   *
+   * The allowed characters in a cookie value are the visible ASCII characters,
+   * U+0021 (`!`) through U+007E (`~`) except the characters:
+   * `"`, `,`, `;` and `\`.
+   * Cookie values may be wrapped in a single pair of double quotes
+   * (U+0022, `"`).
+   */
+  String value;
+
+  /**
+   * The time at which the cookie expires.
+   */
+  DateTime expires;
+
+  /**
+   * The number of seconds until the cookie expires. A zero or negative value
+   * means the cookie has expired.
+   */
+  int maxAge;
+
+  /**
+   * The domain the cookie applies to.
+   */
+  String domain;
+
+  /**
+   * The path within the [domain] the cookie applies to.
+   */
+  String path;
+
+  /**
+   * Whether to only send this cookie on secure connections.
+   */
+  bool secure;
+
+  /**
+   * Whether the cookie is only sent in the HTTP request and is not made
+   * available to client side scripts.
+   */
+  bool httpOnly;
+
+  /**
+   * Creates a new cookie setting the name and value.
+   *
+   * [name] and [value] must be composed of valid characters according to RFC
+   * 6265.
+   *
+   * By default the value of `httpOnly` will be set to `true`.
+   */
+  factory Cookie(String name, String value) => new _Cookie(name, value);
+
+  /**
+   * Creates a new cookie by parsing a header value from a 'set-cookie'
+   * header.
+   */
+  factory Cookie.fromSetCookieValue(String value) {
+    return new _Cookie.fromSetCookieValue(value);
+  }
+
+  /**
+   * Returns the formatted string representation of the cookie. The
+   * string representation can be used for for setting the Cookie or
+   * 'set-cookie' headers
+   */
+  String toString();
+}
+
+/**
+ * A server-side object
+ * that contains the content of and information about an HTTP request.
+ *
+ * __Note__: Check out the
+ * [http_server](https://pub.dartlang.org/packages/http_server)
+ * package, which makes working with the low-level
+ * dart:io HTTP server subsystem easier.
+ *
+ * `HttpRequest` objects are generated by an [HttpServer],
+ * which listens for HTTP requests on a specific host and port.
+ * For each request received, the HttpServer, which is a [Stream],
+ * generates an `HttpRequest` object and adds it to the stream.
+ *
+ * An `HttpRequest` object delivers the body content of the request
+ * as a stream of byte lists.
+ * The object also contains information about the request,
+ * such as the method, URI, and headers.
+ *
+ * In the following code, an HttpServer listens
+ * for HTTP requests. When the server receives a request,
+ * it uses the HttpRequest object's `method` property to dispatch requests.
+ *
+ *     final HOST = InternetAddress.loopbackIPv4;
+ *     final PORT = 80;
+ *
+ *     HttpServer.bind(HOST, PORT).then((_server) {
+ *       _server.listen((HttpRequest request) {
+ *         switch (request.method) {
+ *           case 'GET':
+ *             handleGetRequest(request);
+ *             break;
+ *           case 'POST':
+ *             ...
+ *         }
+ *       },
+ *       onError: handleError);    // listen() failed.
+ *     }).catchError(handleError);
+ *
+ * An HttpRequest object provides access to the associated [HttpResponse]
+ * object through the response property.
+ * The server writes its response to the body of the HttpResponse object.
+ * For example, here's a function that responds to a request:
+ *
+ *     void handleGetRequest(HttpRequest req) {
+ *       HttpResponse res = req.response;
+ *       res.write('Received request ${req.method}: ${req.uri.path}');
+ *       res.close();
+ *     }
+ */
+abstract class HttpRequest implements Stream<Uint8List> {
+  /**
+   * The content length of the request body.
+   *
+   * If the size of the request body is not known in advance,
+   * this value is -1.
+   */
+  int get contentLength;
+
+  /**
+   * The method, such as 'GET' or 'POST', for the request.
+   */
+  String get method;
+
+  /**
+   * The URI for the request.
+   *
+   * This provides access to the
+   * path and query string for the request.
+   */
+  Uri get uri;
+
+  /**
+   * The requested URI for the request.
+   *
+   * The returned URI is reconstructed by using http-header fields, to access
+   * otherwise lost information, e.g. host and scheme.
+   *
+   * To reconstruct the scheme, first 'X-Forwarded-Proto' is checked, and then
+   * falling back to server type.
+   *
+   * To reconstruct the host, first 'X-Forwarded-Host' is checked, then 'Host'
+   * and finally calling back to server.
+   */
+  Uri get requestedUri;
+
+  /**
+   * The request headers.
+   *
+   * The returned [HttpHeaders] are immutable.
+   */
+  HttpHeaders get headers;
+
+  /**
+   * The cookies in the request, from the Cookie headers.
+   */
+  List<Cookie> get cookies;
+
+  /**
+   * The persistent connection state signaled by the client.
+   */
+  bool get persistentConnection;
+
+  /**
+   * The client certificate of the client making the request.
+   *
+   * This value is null if the connection is not a secure TLS or SSL connection,
+   * or if the server does not request a client certificate, or if the client
+   * does not provide one.
+   */
+  X509Certificate get certificate;
+
+  /**
+   * The session for the given request.
+   *
+   * If the session is
+   * being initialized by this call, [:isNew:] is true for the returned
+   * session.
+   * See [HttpServer.sessionTimeout] on how to change default timeout.
+   */
+  HttpSession get session;
+
+  /**
+   * The HTTP protocol version used in the request,
+   * either "1.0" or "1.1".
+   */
+  String get protocolVersion;
+
+  /**
+   * Information about the client connection.
+   *
+   * Returns [:null:] if the socket is not available.
+   */
+  HttpConnectionInfo get connectionInfo;
+
+  /**
+   * The [HttpResponse] object, used for sending back the response to the
+   * client.
+   *
+   * If the [contentLength] of the body isn't 0, and the body isn't being read,
+   * any write calls on the [HttpResponse] automatically drain the request
+   * body.
+   */
+  HttpResponse get response;
+}
+
+/**
+ * An HTTP response, which returns the headers and data
+ * from the server to the client in response to an HTTP request.
+ *
+ * Every HttpRequest object provides access to the associated [HttpResponse]
+ * object through the `response` property.
+ * The server sends its response to the client by writing to the
+ * HttpResponse object.
+ *
+ * ## Writing the response
+ *
+ * This class implements [IOSink].
+ * After the header has been set up, the methods
+ * from IOSink, such as `writeln()`, can be used to write
+ * the body of the HTTP response.
+ * Use the `close()` method to close the response and send it to the client.
+ *
+ *     server.listen((HttpRequest request) {
+ *       request.response.write('Hello, world!');
+ *       request.response.close();
+ *     });
+ *
+ * When one of the IOSink methods is used for the
+ * first time, the request header is sent. Calling any methods that
+ * change the header after it is sent throws an exception.
+ *
+ * ## Setting the headers
+ *
+ * The HttpResponse object has a number of properties for setting up
+ * the HTTP headers of the response.
+ * When writing string data through the IOSink, the encoding used
+ * is determined from the "charset" parameter of the
+ * "Content-Type" header.
+ *
+ *     HttpResponse response = ...
+ *     response.headers.contentType
+ *         = new ContentType("application", "json", charset: "utf-8");
+ *     response.write(...);  // Strings written will be UTF-8 encoded.
+ *
+ * If no charset is provided the default of ISO-8859-1 (Latin 1) will
+ * be used.
+ *
+ *     HttpResponse response = ...
+ *     response.headers.add(HttpHeaders.contentTypeHeader, "text/plain");
+ *     response.write(...);  // Strings written will be ISO-8859-1 encoded.
+ *
+ * An exception is thrown if you use the `write()` method
+ * while an unsupported content-type is set.
+ */
+abstract class HttpResponse implements IOSink {
+  // TODO(ajohnsen): Add documentation of how to pipe a file to the response.
+  /**
+   * Gets and sets the content length of the response. If the size of
+   * the response is not known in advance set the content length to
+   * -1, which is also the default if not set.
+   */
+  int contentLength;
+
+  /**
+   * Gets and sets the status code. Any integer value is accepted. For
+   * the official HTTP status codes use the fields from
+   * [HttpStatus]. If no status code is explicitly set the default
+   * value [HttpStatus.ok] is used.
+   *
+   * The status code must be set before the body is written
+   * to. Setting the status code after writing to the response body or
+   * closing the response will throw a `StateError`.
+   */
+  int statusCode;
+
+  /**
+   * Gets and sets the reason phrase. If no reason phrase is explicitly
+   * set a default reason phrase is provided.
+   *
+   * The reason phrase must be set before the body is written
+   * to. Setting the reason phrase after writing to the response body
+   * or closing the response will throw a `StateError`.
+   */
+  String reasonPhrase;
+
+  /**
+   * Gets and sets the persistent connection state. The initial value
+   * of this property is the persistent connection state from the
+   * request.
+   */
+  bool persistentConnection;
+
+  /**
+   * Set and get the [deadline] for the response. The deadline is timed from the
+   * time it's set. Setting a new deadline will override any previous deadline.
+   * When a deadline is exceeded, the response will be closed and any further
+   * data ignored.
+   *
+   * To disable a deadline, set the [deadline] to `null`.
+   *
+   * The [deadline] is `null` by default.
+   */
+  Duration deadline;
+
+  /**
+   * Gets or sets if the [HttpResponse] should buffer output.
+   *
+   * Default value is `true`.
+   *
+   * __Note__: Disabling buffering of the output can result in very poor
+   * performance, when writing many small chunks.
+   */
+  bool bufferOutput;
+
+  /**
+   * Returns the response headers.
+   *
+   * The response headers can be modified until the response body is
+   * written to or closed. After that they become immutable.
+   */
+  HttpHeaders get headers;
+
+  /**
+   * Cookies to set in the client (in the 'set-cookie' header).
+   */
+  List<Cookie> get cookies;
+
+  /**
+   * Respond with a redirect to [location].
+   *
+   * The URI in [location] should be absolute, but there are no checks
+   * to enforce that.
+   *
+   * By default the HTTP status code `HttpStatus.movedTemporarily`
+   * (`302`) is used for the redirect, but an alternative one can be
+   * specified using the [status] argument.
+   *
+   * This method will also call `close`, and the returned future is
+   * the future returned by `close`.
+   */
+  Future redirect(Uri location, {int status: HttpStatus.movedTemporarily});
+
+  /**
+   * Detaches the underlying socket from the HTTP server. When the
+   * socket is detached the HTTP server will no longer perform any
+   * operations on it.
+   *
+   * This is normally used when a HTTP upgrade request is received
+   * and the communication should continue with a different protocol.
+   *
+   * If [writeHeaders] is `true`, the status line and [headers] will be written
+   * to the socket before it's detached. If `false`, the socket is detached
+   * immediately, without any data written to the socket. Default is `true`.
+   */
+  Future<Socket> detachSocket({bool writeHeaders: true});
+
+  /**
+   * Gets information about the client connection. Returns [:null:] if the
+   * socket is not available.
+   */
+  HttpConnectionInfo get connectionInfo;
+}
+
+/**
+ * A client that receives content, such as web pages, from
+ * a server using the HTTP protocol.
+ *
+ * HttpClient contains a number of methods to send an [HttpClientRequest]
+ * to an Http server and receive an [HttpClientResponse] back.
+ * For example, you can use the [get], [getUrl], [post], and [postUrl] methods
+ * for GET and POST requests, respectively.
+ *
+ * ## Making a simple GET request: an example
+ *
+ * A `getUrl` request is a two-step process, triggered by two [Future]s.
+ * When the first future completes with a [HttpClientRequest], the underlying
+ * network connection has been established, but no data has been sent.
+ * In the callback function for the first future, the HTTP headers and body
+ * can be set on the request. Either the first write to the request object
+ * or a call to [close] sends the request to the server.
+ *
+ * When the HTTP response is received from the server,
+ * the second future, which is returned by close,
+ * completes with an [HttpClientResponse] object.
+ * This object provides access to the headers and body of the response.
+ * The body is available as a stream implemented by HttpClientResponse.
+ * If a body is present, it must be read. Otherwise, it leads to resource
+ * leaks. Consider using [HttpClientResponse.drain] if the body is unused.
+ *
+ *     HttpClient client = new HttpClient();
+ *     client.getUrl(Uri.parse("http://www.example.com/"))
+ *         .then((HttpClientRequest request) {
+ *           // Optionally set up headers...
+ *           // Optionally write to the request object...
+ *           // Then call close.
+ *           ...
+ *           return request.close();
+ *         })
+ *         .then((HttpClientResponse response) {
+ *           // Process the response.
+ *           ...
+ *         });
+ *
+ * The future for [HttpClientRequest] is created by methods such as
+ * [getUrl] and [open].
+ *
+ * ## HTTPS connections
+ *
+ * An HttpClient can make HTTPS requests, connecting to a server using
+ * the TLS (SSL) secure networking protocol. Calling [getUrl] with an
+ * https: scheme will work automatically, if the server's certificate is
+ * signed by a root CA (certificate authority) on the default list of
+ * well-known trusted CAs, compiled by Mozilla.
+ *
+ * To add a custom trusted certificate authority, or to send a client
+ * certificate to servers that request one, pass a [SecurityContext] object
+ * as the optional `context` argument to the `HttpClient` constructor.
+ * The desired security options can be set on the [SecurityContext] object.
+ *
+ * ## Headers
+ *
+ * All HttpClient requests set the following header by default:
+ *
+ *     Accept-Encoding: gzip
+ *
+ * This allows the HTTP server to use gzip compression for the body if
+ * possible. If this behavior is not desired set the
+ * `Accept-Encoding` header to something else.
+ * To turn off gzip compression of the response, clear this header:
+ *
+ *      request.headers.removeAll(HttpHeaders.acceptEncodingHeader)
+ *
+ * ## Closing the HttpClient
+ *
+ * The HttpClient supports persistent connections and caches network
+ * connections to reuse them for multiple requests whenever
+ * possible. This means that network connections can be kept open for
+ * some time after a request has completed. Use HttpClient.close
+ * to force the HttpClient object to shut down and to close the idle
+ * network connections.
+ *
+ * ## Turning proxies on and off
+ *
+ * By default the HttpClient uses the proxy configuration available
+ * from the environment, see [findProxyFromEnvironment]. To turn off
+ * the use of proxies set the [findProxy] property to
+ * [:null:].
+ *
+ *     HttpClient client = new HttpClient();
+ *     client.findProxy = null;
+ */
+abstract class HttpClient {
+  static const int defaultHttpPort = 80;
+  @Deprecated("Use defaultHttpPort instead")
+  static const int DEFAULT_HTTP_PORT = defaultHttpPort;
+
+  static const int defaultHttpsPort = 443;
+  @Deprecated("Use defaultHttpsPort instead")
+  static const int DEFAULT_HTTPS_PORT = defaultHttpsPort;
+
+  /// Gets and sets the idle timeout of non-active persistent (keep-alive)
+  /// connections.
+  ///
+  /// The default value is 15 seconds.
+  Duration idleTimeout;
+
+  /// Gets and sets the connection timeout.
+  ///
+  /// When connecting to a new host exceeds this timeout, a [SocketException]
+  /// is thrown. The timeout applies only to connections initiated after the
+  /// timeout is set.
+  ///
+  /// When this is `null`, the OS default timeout is used. The default is
+  /// `null`.
+  Duration connectionTimeout;
+
+  /**
+   * Gets and sets the maximum number of live connections, to a single host.
+   *
+   * Increasing this number may lower performance and take up unwanted
+   * system resources.
+   *
+   * To disable, set to `null`.
+   *
+   * Default is `null`.
+   */
+  int maxConnectionsPerHost;
+
+  /**
+   * Gets and sets whether the body of a response will be automatically
+   * uncompressed.
+   *
+   * The body of an HTTP response can be compressed. In most
+   * situations providing the un-compressed body is most
+   * convenient. Therefore the default behavior is to un-compress the
+   * body. However in some situations (e.g. implementing a transparent
+   * proxy) keeping the uncompressed stream is required.
+   *
+   * NOTE: Headers in the response are never modified. This means
+   * that when automatic un-compression is turned on the value of the
+   * header `Content-Length` will reflect the length of the original
+   * compressed body. Likewise the header `Content-Encoding` will also
+   * have the original value indicating compression.
+   *
+   * NOTE: Automatic un-compression is only performed if the
+   * `Content-Encoding` header value is `gzip`.
+   *
+   * This value affects all responses produced by this client after the
+   * value is changed.
+   *
+   * To disable, set to `false`.
+   *
+   * Default is `true`.
+   */
+  bool autoUncompress;
+
+  /// Gets and sets the default value of the `User-Agent` header for all requests
+  /// generated by this [HttpClient].
+  ///
+  /// The default value is `Dart/<version> (dart:io)`.
+  ///
+  /// If the userAgent is set to `null`, no default `User-Agent` header will be
+  /// added to each request.
+  String userAgent;
+
+  factory HttpClient({SecurityContext context}) {
+    HttpOverrides overrides = HttpOverrides.current;
+    if (overrides == null) {
+      return new _HttpClient(context);
+    }
+    return overrides.createHttpClient(context);
+  }
+
+  /**
+   * Opens a HTTP connection.
+   *
+   * The HTTP method to use is specified in [method], the server is
+   * specified using [host] and [port], and the path (including
+   * a possible query) is specified using [path].
+   * The path may also contain a URI fragment, which will be ignored.
+   *
+   * The `Host` header for the request will be set to the value [host]:[port]
+   * (if [host] is an IP address, it will still be used in the `Host` header).
+   * This can be overridden through the [HttpClientRequest] interface before
+   * the request is sent.
+   *
+   * For additional information on the sequence of events during an
+   * HTTP transaction, and the objects returned by the futures, see
+   * the overall documentation for the class [HttpClient].
+   */
+  Future<HttpClientRequest> open(
+      String method, String host, int port, String path);
+
+  /**
+   * Opens a HTTP connection.
+   *
+   * The HTTP method is specified in [method] and the URL to use in
+   * [url].
+   *
+   * The `Host` header for the request will be set to the value
+   * [Uri.host]:[Uri.port] from [url] (if [url.host] is an IP address, it will
+   * still be used in the `Host` header). This can be overridden through the
+   * [HttpClientRequest] interface before the request is sent.
+   *
+   * For additional information on the sequence of events during an
+   * HTTP transaction, and the objects returned by the futures, see
+   * the overall documentation for the class [HttpClient].
+   */
+  Future<HttpClientRequest> openUrl(String method, Uri url);
+
+  /**
+   * Opens a HTTP connection using the GET method.
+   *
+   * The server is specified using [host] and [port], and the path
+   * (including a possible query) is specified using
+   * [path].
+   *
+   * See [open] for details.
+   */
+  Future<HttpClientRequest> get(String host, int port, String path);
+
+  /**
+   * Opens a HTTP connection using the GET method.
+   *
+   * The URL to use is specified in [url].
+   *
+   * See [openUrl] for details.
+   */
+  Future<HttpClientRequest> getUrl(Uri url);
+
+  /**
+   * Opens a HTTP connection using the POST method.
+   *
+   * The server is specified using [host] and [port], and the path
+   * (including a possible query) is specified using
+   * [path].
+   *
+   * See [open] for details.
+   */
+  Future<HttpClientRequest> post(String host, int port, String path);
+
+  /**
+   * Opens a HTTP connection using the POST method.
+   *
+   * The URL to use is specified in [url].
+   *
+   * See [openUrl] for details.
+   */
+  Future<HttpClientRequest> postUrl(Uri url);
+
+  /**
+   * Opens a HTTP connection using the PUT method.
+   *
+   * The server is specified using [host] and [port], and the path
+   * (including a possible query) is specified using [path].
+   *
+   * See [open] for details.
+   */
+  Future<HttpClientRequest> put(String host, int port, String path);
+
+  /**
+   * Opens a HTTP connection using the PUT method.
+   *
+   * The URL to use is specified in [url].
+   *
+   * See [openUrl] for details.
+   */
+  Future<HttpClientRequest> putUrl(Uri url);
+
+  /**
+   * Opens a HTTP connection using the DELETE method.
+   *
+   * The server is specified using [host] and [port], and the path
+   * (including a possible query) is specified using [path].
+   *
+   * See [open] for details.
+   */
+  Future<HttpClientRequest> delete(String host, int port, String path);
+
+  /**
+   * Opens a HTTP connection using the DELETE method.
+   *
+   * The URL to use is specified in [url].
+   *
+   * See [openUrl] for details.
+   */
+  Future<HttpClientRequest> deleteUrl(Uri url);
+
+  /**
+   * Opens a HTTP connection using the PATCH method.
+   *
+   * The server is specified using [host] and [port], and the path
+   * (including a possible query) is specified using [path].
+   *
+   * See [open] for details.
+   */
+  Future<HttpClientRequest> patch(String host, int port, String path);
+
+  /**
+   * Opens a HTTP connection using the PATCH method.
+   *
+   * The URL to use is specified in [url].
+   *
+   * See [openUrl] for details.
+   */
+  Future<HttpClientRequest> patchUrl(Uri url);
+
+  /**
+   * Opens a HTTP connection using the HEAD method.
+   *
+   * The server is specified using [host] and [port], and the path
+   * (including a possible query) is specified using [path].
+   *
+   * See [open] for details.
+   */
+  Future<HttpClientRequest> head(String host, int port, String path);
+
+  /**
+   * Opens a HTTP connection using the HEAD method.
+   *
+   * The URL to use is specified in [url].
+   *
+   * See [openUrl] for details.
+   */
+  Future<HttpClientRequest> headUrl(Uri url);
+
+  /**
+   * Sets the function to be called when a site is requesting
+   * authentication. The URL requested and the security realm from the
+   * server are passed in the arguments [url] and [realm].
+   *
+   * The function returns a [Future] which should complete when the
+   * authentication has been resolved. If credentials cannot be
+   * provided the [Future] should complete with [:false:]. If
+   * credentials are available the function should add these using
+   * [addCredentials] before completing the [Future] with the value
+   * [:true:].
+   *
+   * If the [Future] completes with [:true:] the request will be retried
+   * using the updated credentials, however, the retried request will not
+   * carry the original request payload. Otherwise response processing will
+   * continue normally.
+   *
+   * If it is known that the remote server requires authentication for all
+   * requests, it is advisable to use [addCredentials] directly, or manually
+   * set the `'authorization'` header on the request to avoid the overhead
+   * of a failed request, or issues due to missing request payload on retried
+   * request.
+   */
+  set authenticate(Future<bool> f(Uri url, String scheme, String realm));
+
+  /**
+   * Add credentials to be used for authorizing HTTP requests.
+   */
+  void addCredentials(Uri url, String realm, HttpClientCredentials credentials);
+
+  /**
+   * Sets the function used to resolve the proxy server to be used for
+   * opening a HTTP connection to the specified [url]. If this
+   * function is not set, direct connections will always be used.
+   *
+   * The string returned by [f] must be in the format used by browser
+   * PAC (proxy auto-config) scripts. That is either
+   *
+   *     "DIRECT"
+   *
+   * for using a direct connection or
+   *
+   *     "PROXY host:port"
+   *
+   * for using the proxy server [:host:] on port [:port:].
+   *
+   * A configuration can contain several configuration elements
+   * separated by semicolons, e.g.
+   *
+   *     "PROXY host:port; PROXY host2:port2; DIRECT"
+   *
+   * The static function [findProxyFromEnvironment] on this class can
+   * be used to implement proxy server resolving based on environment
+   * variables.
+   */
+  set findProxy(String f(Uri url));
+
+  /**
+   * Function for resolving the proxy server to be used for a HTTP
+   * connection from the proxy configuration specified through
+   * environment variables.
+   *
+   * The following environment variables are taken into account:
+   *
+   *     http_proxy
+   *     https_proxy
+   *     no_proxy
+   *     HTTP_PROXY
+   *     HTTPS_PROXY
+   *     NO_PROXY
+   *
+   * [:http_proxy:] and [:HTTP_PROXY:] specify the proxy server to use for
+   * http:// urls. Use the format [:hostname:port:]. If no port is used a
+   * default of 1080 will be used. If both are set the lower case one takes
+   * precedence.
+   *
+   * [:https_proxy:] and [:HTTPS_PROXY:] specify the proxy server to use for
+   * https:// urls. Use the format [:hostname:port:]. If no port is used a
+   * default of 1080 will be used. If both are set the lower case one takes
+   * precedence.
+   *
+   * [:no_proxy:] and [:NO_PROXY:] specify a comma separated list of
+   * postfixes of hostnames for which not to use the proxy
+   * server. E.g. the value "localhost,127.0.0.1" will make requests
+   * to both "localhost" and "127.0.0.1" not use a proxy. If both are set
+   * the lower case one takes precedence.
+   *
+   * To activate this way of resolving proxies assign this function to
+   * the [findProxy] property on the [HttpClient].
+   *
+   *     HttpClient client = new HttpClient();
+   *     client.findProxy = HttpClient.findProxyFromEnvironment;
+   *
+   * If you don't want to use the system environment you can use a
+   * different one by wrapping the function.
+   *
+   *     HttpClient client = new HttpClient();
+   *     client.findProxy = (url) {
+   *       return HttpClient.findProxyFromEnvironment(
+   *           url, environment: {"http_proxy": ..., "no_proxy": ...});
+   *     }
+   *
+   * If a proxy requires authentication it is possible to configure
+   * the username and password as well. Use the format
+   * [:username:password@hostname:port:] to include the username and
+   * password. Alternatively the API [addProxyCredentials] can be used
+   * to set credentials for proxies which require authentication.
+   */
+  static String findProxyFromEnvironment(Uri url,
+      {Map<String, String> environment}) {
+    HttpOverrides overrides = HttpOverrides.current;
+    if (overrides == null) {
+      return _HttpClient._findProxyFromEnvironment(url, environment);
+    }
+    return overrides.findProxyFromEnvironment(url, environment);
+  }
+
+  /**
+   * Sets the function to be called when a proxy is requesting
+   * authentication. Information on the proxy in use and the security
+   * realm for the authentication are passed in the arguments [host],
+   * [port] and [realm].
+   *
+   * The function returns a [Future] which should complete when the
+   * authentication has been resolved. If credentials cannot be
+   * provided the [Future] should complete with [:false:]. If
+   * credentials are available the function should add these using
+   * [addProxyCredentials] before completing the [Future] with the value
+   * [:true:].
+   *
+   * If the [Future] completes with [:true:] the request will be retried
+   * using the updated credentials. Otherwise response processing will
+   * continue normally.
+   */
+  set authenticateProxy(
+      Future<bool> f(String host, int port, String scheme, String realm));
+
+  /**
+   * Add credentials to be used for authorizing HTTP proxies.
+   */
+  void addProxyCredentials(
+      String host, int port, String realm, HttpClientCredentials credentials);
+
+  /**
+   * Sets a callback that will decide whether to accept a secure connection
+   * with a server certificate that cannot be authenticated by any of our
+   * trusted root certificates.
+   *
+   * When an secure HTTP request if made, using this HttpClient, and the
+   * server returns a server certificate that cannot be authenticated, the
+   * callback is called asynchronously with the [X509Certificate] object and
+   * the server's hostname and port.  If the value of [badCertificateCallback]
+   * is [:null:], the bad certificate is rejected, as if the callback
+   * returned [:false:]
+   *
+   * If the callback returns true, the secure connection is accepted and the
+   * [:Future<HttpClientRequest>:] that was returned from the call making the
+   * request completes with a valid HttpRequest object. If the callback returns
+   * false, the [:Future<HttpClientRequest>:] completes with an exception.
+   *
+   * If a bad certificate is received on a connection attempt, the library calls
+   * the function that was the value of badCertificateCallback at the time
+   * the request is made, even if the value of badCertificateCallback
+   * has changed since then.
+   */
+  set badCertificateCallback(
+      bool callback(X509Certificate cert, String host, int port));
+
+  /// Shuts down the HTTP client.
+  ///
+  /// If [force] is `false` (the default) the [HttpClient] will be kept alive
+  /// until all active connections are done. If [force] is `true` any active
+  /// connections will be closed to immediately release all resources. These
+  /// closed connections will receive an error event to indicate that the client
+  /// was shut down. In both cases trying to establish a new connection after
+  /// calling [close] will throw an exception.
+  void close({bool force: false});
+}
+
+/**
+ * HTTP request for a client connection.
+ *
+ * To set up a request, set the headers using the headers property
+ * provided in this class and write the data to the body of the request.
+ * HttpClientRequest is an [IOSink]. Use the methods from IOSink,
+ * such as writeCharCode(), to write the body of the HTTP
+ * request. When one of the IOSink methods is used for the first
+ * time, the request header is sent. Calling any methods that
+ * change the header after it is sent throws an exception.
+ *
+ * When writing string data through the [IOSink] the
+ * encoding used is determined from the "charset" parameter of
+ * the "Content-Type" header.
+ *
+ *     HttpClientRequest request = ...
+ *     request.headers.contentType
+ *         = new ContentType("application", "json", charset: "utf-8");
+ *     request.write(...);  // Strings written will be UTF-8 encoded.
+ *
+ * If no charset is provided the default of ISO-8859-1 (Latin 1) is
+ * be used.
+ *
+ *     HttpClientRequest request = ...
+ *     request.headers.add(HttpHeaders.contentTypeHeader, "text/plain");
+ *     request.write(...);  // Strings written will be ISO-8859-1 encoded.
+ *
+ * An exception is thrown if you use an unsupported encoding and the
+ * `write()` method being used takes a string parameter.
+ */
+abstract class HttpClientRequest implements IOSink {
+  /**
+   * Gets and sets the requested persistent connection state.
+   *
+   * The default value is [:true:].
+   */
+  bool persistentConnection;
+
+  /**
+   * Set this property to [:true:] if this request should
+   * automatically follow redirects. The default is [:true:].
+   *
+   * Automatic redirect will only happen for "GET" and "HEAD" requests
+   * and only for the status codes [:HttpStatus.movedPermanently:]
+   * (301), [:HttpStatus.found:] (302),
+   * [:HttpStatus.movedTemporarily:] (302, alias for
+   * [:HttpStatus.found:]), [:HttpStatus.seeOther:] (303) and
+   * [:HttpStatus.temporaryRedirect:] (307). For
+   * [:HttpStatus.seeOther:] (303) automatic redirect will also happen
+   * for "POST" requests with the method changed to "GET" when
+   * following the redirect.
+   *
+   * All headers added to the request will be added to the redirection
+   * request(s). However, any body send with the request will not be
+   * part of the redirection request(s).
+   */
+  bool followRedirects;
+
+  /**
+   * Set this property to the maximum number of redirects to follow
+   * when [followRedirects] is `true`. If this number is exceeded
+   * an error event will be added with a [RedirectException].
+   *
+   * The default value is 5.
+   */
+  int maxRedirects;
+
+  /**
+   * The method of the request.
+   */
+  String get method;
+
+  /**
+   * The uri of the request.
+   */
+  Uri get uri;
+
+  /// Gets and sets the content length of the request.
+  ///
+  /// If the size of the request is not known in advance set content length to
+  /// -1, which is also the default.
+  int contentLength;
+
+  /**
+   * Gets or sets if the [HttpClientRequest] should buffer output.
+   *
+   * Default value is `true`.
+   *
+   * __Note__: Disabling buffering of the output can result in very poor
+   * performance, when writing many small chunks.
+   */
+  bool bufferOutput;
+
+  /**
+   * Returns the client request headers.
+   *
+   * The client request headers can be modified until the client
+   * request body is written to or closed. After that they become
+   * immutable.
+   */
+  HttpHeaders get headers;
+
+  /**
+   * Cookies to present to the server (in the 'cookie' header).
+   */
+  List<Cookie> get cookies;
+
+  /// A [HttpClientResponse] future that will complete once the response is
+  /// available.
+  ///
+  /// If an error occurs before the response is available, this future will
+  /// complete with an error.
+  Future<HttpClientResponse> get done;
+
+  /**
+   * Close the request for input. Returns the value of [done].
+   */
+  Future<HttpClientResponse> close();
+
+  /// Gets information about the client connection.
+  ///
+  /// Returns [:null:] if the socket is not available.
+  HttpConnectionInfo get connectionInfo;
+}
+
+/**
+ * HTTP response for a client connection.
+ *
+ * The body of a [HttpClientResponse] object is a
+ * [Stream] of data from the server. Listen to the body to handle
+ * the data and be notified when the entire body is received.
+ *
+ *     new HttpClient().get('localhost', 80, '/file.txt')
+ *          .then((HttpClientRequest request) => request.close())
+ *          .then((HttpClientResponse response) {
+ *            response.transform(utf8.decoder).listen((contents) {
+ *              // handle data
+ *            });
+ *          });
+ */
+abstract class HttpClientResponse implements Stream<List<int>> {
+  /**
+   * Returns the status code.
+   *
+   * The status code must be set before the body is written
+   * to. Setting the status code after writing to the body will throw
+   * a `StateError`.
+   */
+  int get statusCode;
+
+  /**
+   * Returns the reason phrase associated with the status code.
+   *
+   * The reason phrase must be set before the body is written
+   * to. Setting the reason phrase after writing to the body will throw
+   * a `StateError`.
+   */
+  String get reasonPhrase;
+
+  /**
+   * Returns the content length of the response body. Returns -1 if the size of
+   * the response body is not known in advance.
+   *
+   * If the content length needs to be set, it must be set before the
+   * body is written to. Setting the content length after writing to the body
+   * will throw a `StateError`.
+   */
+  int get contentLength;
+
+  /// The compression state of the response.
+  ///
+  /// This specifies whether the response bytes were compressed when they were
+  /// received across the wire and whether callers will receive compressed
+  /// or uncompressed bytes when they listed to this response's byte stream.
+  @Since("2.4")
+  HttpClientResponseCompressionState get compressionState;
+
+  /**
+   * Gets the persistent connection state returned by the server.
+   *
+   * If the persistent connection state needs to be set, it must be
+   * set before the body is written to. Setting the persistent connection state
+   * after writing to the body will throw a `StateError`.
+   */
+  bool get persistentConnection;
+
+  /**
+   * Returns whether the status code is one of the normal redirect
+   * codes [HttpStatus.movedPermanently], [HttpStatus.found],
+   * [HttpStatus.movedTemporarily], [HttpStatus.seeOther] and
+   * [HttpStatus.temporaryRedirect].
+   */
+  bool get isRedirect;
+
+  /**
+   * Returns the series of redirects this connection has been through. The
+   * list will be empty if no redirects were followed. [redirects] will be
+   * updated both in the case of an automatic and a manual redirect.
+   */
+  List<RedirectInfo> get redirects;
+
+  /**
+   * Redirects this connection to a new URL. The default value for
+   * [method] is the method for the current request. The default value
+   * for [url] is the value of the [HttpHeaders.locationHeader] header of
+   * the current response. All body data must have been read from the
+   * current response before calling [redirect].
+   *
+   * All headers added to the request will be added to the redirection
+   * request. However, any body sent with the request will not be
+   * part of the redirection request.
+   *
+   * If [followLoops] is set to [:true:], redirect will follow the redirect,
+   * even if the URL was already visited. The default value is [:false:].
+   *
+   * The method will ignore [HttpClientRequest.maxRedirects]
+   * and will always perform the redirect.
+   */
+  Future<HttpClientResponse> redirect(
+      [String method, Uri url, bool followLoops]);
+
+  /**
+   * Returns the client response headers.
+   *
+   * The client response headers are immutable.
+   */
+  HttpHeaders get headers;
+
+  /**
+   * Detach the underlying socket from the HTTP client. When the
+   * socket is detached the HTTP client will no longer perform any
+   * operations on it.
+   *
+   * This is normally used when a HTTP upgrade is negotiated and the
+   * communication should continue with a different protocol.
+   */
+  Future<Socket> detachSocket();
+
+  /**
+   * Cookies set by the server (from the 'set-cookie' header).
+   */
+  List<Cookie> get cookies;
+
+  /**
+   * Returns the certificate of the HTTPS server providing the response.
+   * Returns null if the connection is not a secure TLS or SSL connection.
+   */
+  X509Certificate get certificate;
+
+  /**
+   * Gets information about the client connection. Returns [:null:] if the socket
+   * is not available.
+   */
+  HttpConnectionInfo get connectionInfo;
+}
+
+/// Enum that specifies the compression state of the byte stream of an
+/// [HttpClientResponse].
+///
+/// The values herein allow callers to answer the following questions as they
+/// pertain to an [HttpClientResponse]:
+///
+///  * Can the value of the response's `Content-Length` HTTP header be trusted?
+///  * Does the caller need to manually decompress the response's byte stream?
+///
+/// This enum is accessed via the [HttpClientResponse.compressionState] value.
+@Since("2.4")
+enum HttpClientResponseCompressionState {
+  /// The body of the HTTP response was received and remains in an uncompressed
+  /// state.
+  ///
+  /// In this state, the value of the `Content-Length` HTTP header, if
+  /// specified (non-negative), should match the number of bytes produced by
+  /// the response's byte stream.
+  notCompressed,
+
+  /// The body of the HTTP response was originally compressed, but by virtue of
+  /// the [HttpClient.autoUncompress] configuration option, it has been
+  /// automatically uncompressed.
+  ///
+  /// HTTP headers are not modified, so when a response has been uncompressed
+  /// in this way, the value of the `Content-Length` HTTP header cannot be
+  /// trusted, as it will contain the compressed content length, whereas the
+  /// stream of bytes produced by the response will contain uncompressed bytes.
+  decompressed,
+
+  /// The body of the HTTP response contains compressed bytes.
+  ///
+  /// In this state, the value of the `Content-Length` HTTP header, if
+  /// specified (non-negative), should match the number of bytes produced by
+  /// the response's byte stream.
+  ///
+  /// If the caller wishes to manually uncompress the body of the response,
+  /// it should consult the value of the `Content-Encoding` HTTP header to see
+  /// what type of compression has been applied. See
+  /// <https://tools.ietf.org/html/rfc2616#section-14.11> for more information.
+  compressed,
+}
+
+abstract class HttpClientCredentials {}
+
+/**
+ * Represents credentials for basic authentication.
+ */
+abstract class HttpClientBasicCredentials extends HttpClientCredentials {
+  factory HttpClientBasicCredentials(String username, String password) =>
+      new _HttpClientBasicCredentials(username, password);
+}
+
+/**
+ * Represents credentials for digest authentication. Digest
+ * authentication is only supported for servers using the MD5
+ * algorithm and quality of protection (qop) of either "none" or
+ * "auth".
+ */
+abstract class HttpClientDigestCredentials extends HttpClientCredentials {
+  factory HttpClientDigestCredentials(String username, String password) =>
+      new _HttpClientDigestCredentials(username, password);
+}
+
+/**
+ * Information about an [HttpRequest], [HttpResponse], [HttpClientRequest], or
+ * [HttpClientResponse] connection.
+ */
+abstract class HttpConnectionInfo {
+  InternetAddress get remoteAddress;
+  int get remotePort;
+  int get localPort;
+}
+
+/**
+ * Redirect information.
+ */
+abstract class RedirectInfo {
+  /**
+   * Returns the status code used for the redirect.
+   */
+  int get statusCode;
+
+  /**
+   * Returns the method used for the redirect.
+   */
+  String get method;
+
+  /**
+   * Returns the location for the redirect.
+   */
+  Uri get location;
+}
+
+/**
+ * When detaching a socket from either the [:HttpServer:] or the
+ * [:HttpClient:] due to a HTTP connection upgrade there might be
+ * unparsed data already read from the socket. This unparsed data
+ * together with the detached socket is returned in an instance of
+ * this class.
+ */
+abstract class DetachedSocket {
+  Socket get socket;
+  List<int> get unparsedData;
+}
+
+class HttpException implements IOException {
+  final String message;
+  final Uri uri;
+
+  const HttpException(this.message, {this.uri});
+
+  String toString() {
+    var b = new StringBuffer()..write('HttpException: ')..write(message);
+    if (uri != null) {
+      b.write(', uri = $uri');
+    }
+    return b.toString();
+  }
+}
+
+class RedirectException implements HttpException {
+  final String message;
+  final List<RedirectInfo> redirects;
+
+  const RedirectException(this.message, this.redirects);
+
+  String toString() => "RedirectException: $message";
+
+  Uri get uri => redirects.last.location;
+}
diff --git a/sdk_nnbd/lib/_http/http_date.dart b/sdk_nnbd/lib/_http/http_date.dart
new file mode 100644
index 0000000..d9301b4
--- /dev/null
+++ b/sdk_nnbd/lib/_http/http_date.dart
@@ -0,0 +1,388 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart._http;
+
+/**
+ * Utility functions for working with dates with HTTP specific date
+ * formats.
+ */
+class HttpDate {
+  // From RFC-2616 section "3.3.1 Full Date",
+  // http://tools.ietf.org/html/rfc2616#section-3.3.1
+  //
+  // HTTP-date    = rfc1123-date | rfc850-date | asctime-date
+  // rfc1123-date = wkday "," SP date1 SP time SP "GMT"
+  // rfc850-date  = weekday "," SP date2 SP time SP "GMT"
+  // asctime-date = wkday SP date3 SP time SP 4DIGIT
+  // date1        = 2DIGIT SP month SP 4DIGIT
+  //                ; day month year (e.g., 02 Jun 1982)
+  // date2        = 2DIGIT "-" month "-" 2DIGIT
+  //                ; day-month-year (e.g., 02-Jun-82)
+  // date3        = month SP ( 2DIGIT | ( SP 1DIGIT ))
+  //                ; month day (e.g., Jun  2)
+  // time         = 2DIGIT ":" 2DIGIT ":" 2DIGIT
+  //                ; 00:00:00 - 23:59:59
+  // wkday        = "Mon" | "Tue" | "Wed"
+  //              | "Thu" | "Fri" | "Sat" | "Sun"
+  // weekday      = "Monday" | "Tuesday" | "Wednesday"
+  //              | "Thursday" | "Friday" | "Saturday" | "Sunday"
+  // month        = "Jan" | "Feb" | "Mar" | "Apr"
+  //              | "May" | "Jun" | "Jul" | "Aug"
+  //              | "Sep" | "Oct" | "Nov" | "Dec"
+
+  /**
+   * Format a date according to
+   * [RFC-1123](http://tools.ietf.org/html/rfc1123 "RFC-1123"),
+   * e.g. `Thu, 1 Jan 1970 00:00:00 GMT`.
+   */
+  static String format(DateTime date) {
+    const List wkday = const ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"];
+    const List month = const [
+      "Jan",
+      "Feb",
+      "Mar",
+      "Apr",
+      "May",
+      "Jun",
+      "Jul",
+      "Aug",
+      "Sep",
+      "Oct",
+      "Nov",
+      "Dec"
+    ];
+
+    DateTime d = date.toUtc();
+    StringBuffer sb = new StringBuffer()
+      ..write(wkday[d.weekday - 1])
+      ..write(", ")
+      ..write(d.day <= 9 ? "0" : "")
+      ..write(d.day.toString())
+      ..write(" ")
+      ..write(month[d.month - 1])
+      ..write(" ")
+      ..write(d.year.toString())
+      ..write(d.hour <= 9 ? " 0" : " ")
+      ..write(d.hour.toString())
+      ..write(d.minute <= 9 ? ":0" : ":")
+      ..write(d.minute.toString())
+      ..write(d.second <= 9 ? ":0" : ":")
+      ..write(d.second.toString())
+      ..write(" GMT");
+    return sb.toString();
+  }
+
+  /**
+   * Parse a date string in either of the formats
+   * [RFC-1123](http://tools.ietf.org/html/rfc1123 "RFC-1123"),
+   * [RFC-850](http://tools.ietf.org/html/rfc850 "RFC-850") or
+   * ANSI C's asctime() format. These formats are listed here.
+   *
+   *     Thu, 1 Jan 1970 00:00:00 GMT
+   *     Thursday, 1-Jan-1970 00:00:00 GMT
+   *     Thu Jan  1 00:00:00 1970
+   *
+   * For more information see [RFC-2616 section
+   * 3.1.1](http://tools.ietf.org/html/rfc2616#section-3.3.1
+   * "RFC-2616 section 3.1.1").
+   */
+  static DateTime parse(String date) {
+    final int SP = 32;
+    const List wkdays = const ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"];
+    const List weekdays = const [
+      "Monday",
+      "Tuesday",
+      "Wednesday",
+      "Thursday",
+      "Friday",
+      "Saturday",
+      "Sunday"
+    ];
+    const List months = const [
+      "Jan",
+      "Feb",
+      "Mar",
+      "Apr",
+      "May",
+      "Jun",
+      "Jul",
+      "Aug",
+      "Sep",
+      "Oct",
+      "Nov",
+      "Dec"
+    ];
+    const List wkdaysLowerCase = const [
+      "mon",
+      "tue",
+      "wed",
+      "thu",
+      "fri",
+      "sat",
+      "sun"
+    ];
+    const List weekdaysLowerCase = const [
+      "monday",
+      "tuesday",
+      "wednesday",
+      "thursday",
+      "friday",
+      "saturday",
+      "sunday"
+    ];
+    const List monthsLowerCase = const [
+      "jan",
+      "feb",
+      "mar",
+      "apr",
+      "may",
+      "jun",
+      "jul",
+      "aug",
+      "sep",
+      "oct",
+      "nov",
+      "dec"
+    ];
+
+    final int formatRfc1123 = 0;
+    final int formatRfc850 = 1;
+    final int formatAsctime = 2;
+
+    int index = 0;
+    String tmp;
+    int format;
+
+    void expect(String s) {
+      if (date.length - index < s.length) {
+        throw new HttpException("Invalid HTTP date $date");
+      }
+      String tmp = date.substring(index, index + s.length);
+      if (tmp != s) {
+        throw new HttpException("Invalid HTTP date $date");
+      }
+      index += s.length;
+    }
+
+    int expectWeekday() {
+      int weekday;
+      // The formatting of the weekday signals the format of the date string.
+      int pos = date.indexOf(",", index);
+      if (pos == -1) {
+        int pos = date.indexOf(" ", index);
+        if (pos == -1) throw new HttpException("Invalid HTTP date $date");
+        tmp = date.substring(index, pos);
+        index = pos + 1;
+        weekday = wkdays.indexOf(tmp);
+        if (weekday != -1) {
+          format = formatAsctime;
+          return weekday;
+        }
+      } else {
+        tmp = date.substring(index, pos);
+        index = pos + 1;
+        weekday = wkdays.indexOf(tmp);
+        if (weekday != -1) {
+          format = formatRfc1123;
+          return weekday;
+        }
+        weekday = weekdays.indexOf(tmp);
+        if (weekday != -1) {
+          format = formatRfc850;
+          return weekday;
+        }
+      }
+      throw new HttpException("Invalid HTTP date $date");
+    }
+
+    int expectMonth(String separator) {
+      int pos = date.indexOf(separator, index);
+      if (pos - index != 3) throw new HttpException("Invalid HTTP date $date");
+      tmp = date.substring(index, pos);
+      index = pos + 1;
+      int month = months.indexOf(tmp);
+      if (month != -1) return month;
+      throw new HttpException("Invalid HTTP date $date");
+    }
+
+    int expectNum(String separator) {
+      int pos;
+      if (separator.length > 0) {
+        pos = date.indexOf(separator, index);
+      } else {
+        pos = date.length;
+      }
+      String tmp = date.substring(index, pos);
+      index = pos + separator.length;
+      try {
+        int value = int.parse(tmp);
+        return value;
+      } on FormatException catch (e) {
+        throw new HttpException("Invalid HTTP date $date");
+      }
+    }
+
+    void expectEnd() {
+      if (index != date.length) {
+        throw new HttpException("Invalid HTTP date $date");
+      }
+    }
+
+    int weekday = expectWeekday();
+    int day;
+    int month;
+    int year;
+    int hours;
+    int minutes;
+    int seconds;
+    if (format == formatAsctime) {
+      month = expectMonth(" ");
+      if (date.codeUnitAt(index) == SP) index++;
+      day = expectNum(" ");
+      hours = expectNum(":");
+      minutes = expectNum(":");
+      seconds = expectNum(" ");
+      year = expectNum("");
+    } else {
+      expect(" ");
+      day = expectNum(format == formatRfc1123 ? " " : "-");
+      month = expectMonth(format == formatRfc1123 ? " " : "-");
+      year = expectNum(" ");
+      hours = expectNum(":");
+      minutes = expectNum(":");
+      seconds = expectNum(" ");
+      expect("GMT");
+    }
+    expectEnd();
+    return new DateTime.utc(year, month + 1, day, hours, minutes, seconds, 0);
+  }
+
+  // Parse a cookie date string.
+  static DateTime _parseCookieDate(String date) {
+    const List monthsLowerCase = const [
+      "jan",
+      "feb",
+      "mar",
+      "apr",
+      "may",
+      "jun",
+      "jul",
+      "aug",
+      "sep",
+      "oct",
+      "nov",
+      "dec"
+    ];
+
+    int position = 0;
+
+    void error() {
+      throw new HttpException("Invalid cookie date $date");
+    }
+
+    bool isEnd() => position == date.length;
+
+    bool isDelimiter(String s) {
+      int char = s.codeUnitAt(0);
+      if (char == 0x09) return true;
+      if (char >= 0x20 && char <= 0x2F) return true;
+      if (char >= 0x3B && char <= 0x40) return true;
+      if (char >= 0x5B && char <= 0x60) return true;
+      if (char >= 0x7B && char <= 0x7E) return true;
+      return false;
+    }
+
+    bool isNonDelimiter(String s) {
+      int char = s.codeUnitAt(0);
+      if (char >= 0x00 && char <= 0x08) return true;
+      if (char >= 0x0A && char <= 0x1F) return true;
+      if (char >= 0x30 && char <= 0x39) return true; // Digit
+      if (char == 0x3A) return true; // ':'
+      if (char >= 0x41 && char <= 0x5A) return true; // Alpha
+      if (char >= 0x61 && char <= 0x7A) return true; // Alpha
+      if (char >= 0x7F && char <= 0xFF) return true; // Alpha
+      return false;
+    }
+
+    bool isDigit(String s) {
+      int char = s.codeUnitAt(0);
+      if (char > 0x2F && char < 0x3A) return true;
+      return false;
+    }
+
+    int getMonth(String month) {
+      if (month.length < 3) return -1;
+      return monthsLowerCase.indexOf(month.substring(0, 3));
+    }
+
+    int toInt(String s) {
+      int index = 0;
+      for (; index < s.length && isDigit(s[index]); index++);
+      return int.parse(s.substring(0, index));
+    }
+
+    var tokens = [];
+    while (!isEnd()) {
+      while (!isEnd() && isDelimiter(date[position])) position++;
+      int start = position;
+      while (!isEnd() && isNonDelimiter(date[position])) position++;
+      tokens.add(date.substring(start, position).toLowerCase());
+      while (!isEnd() && isDelimiter(date[position])) position++;
+    }
+
+    String timeStr;
+    String dayOfMonthStr;
+    String monthStr;
+    String yearStr;
+
+    for (var token in tokens) {
+      if (token.length < 1) continue;
+      if (timeStr == null &&
+          token.length >= 5 &&
+          isDigit(token[0]) &&
+          (token[1] == ":" || (isDigit(token[1]) && token[2] == ":"))) {
+        timeStr = token;
+      } else if (dayOfMonthStr == null && isDigit(token[0])) {
+        dayOfMonthStr = token;
+      } else if (monthStr == null && getMonth(token) >= 0) {
+        monthStr = token;
+      } else if (yearStr == null &&
+          token.length >= 2 &&
+          isDigit(token[0]) &&
+          isDigit(token[1])) {
+        yearStr = token;
+      }
+    }
+
+    if (timeStr == null ||
+        dayOfMonthStr == null ||
+        monthStr == null ||
+        yearStr == null) {
+      error();
+    }
+
+    int year = toInt(yearStr);
+    if (year >= 70 && year <= 99)
+      year += 1900;
+    else if (year >= 0 && year <= 69) year += 2000;
+    if (year < 1601) error();
+
+    int dayOfMonth = toInt(dayOfMonthStr);
+    if (dayOfMonth < 1 || dayOfMonth > 31) error();
+
+    int month = getMonth(monthStr) + 1;
+
+    var timeList = timeStr.split(":");
+    if (timeList.length != 3) error();
+    int hour = toInt(timeList[0]);
+    int minute = toInt(timeList[1]);
+    int second = toInt(timeList[2]);
+    if (hour > 23) error();
+    if (minute > 59) error();
+    if (second > 59) error();
+
+    return new DateTime.utc(year, month, dayOfMonth, hour, minute, second, 0);
+  }
+}
diff --git a/sdk_nnbd/lib/_http/http_headers.dart b/sdk_nnbd/lib/_http/http_headers.dart
new file mode 100644
index 0000000..7601485
--- /dev/null
+++ b/sdk_nnbd/lib/_http/http_headers.dart
@@ -0,0 +1,1033 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart._http;
+
+class _HttpHeaders implements HttpHeaders {
+  final Map<String, List<String>> _headers;
+  final String protocolVersion;
+
+  bool _mutable = true; // Are the headers currently mutable?
+  List<String> _noFoldingHeaders;
+
+  int _contentLength = -1;
+  bool _persistentConnection = true;
+  bool _chunkedTransferEncoding = false;
+  String _host;
+  int _port;
+
+  final int _defaultPortForScheme;
+
+  _HttpHeaders(this.protocolVersion,
+      {int defaultPortForScheme: HttpClient.defaultHttpPort,
+      _HttpHeaders initialHeaders})
+      : _headers = new HashMap<String, List<String>>(),
+        _defaultPortForScheme = defaultPortForScheme {
+    if (initialHeaders != null) {
+      initialHeaders._headers.forEach((name, value) => _headers[name] = value);
+      _contentLength = initialHeaders._contentLength;
+      _persistentConnection = initialHeaders._persistentConnection;
+      _chunkedTransferEncoding = initialHeaders._chunkedTransferEncoding;
+      _host = initialHeaders._host;
+      _port = initialHeaders._port;
+    }
+    if (protocolVersion == "1.0") {
+      _persistentConnection = false;
+      _chunkedTransferEncoding = false;
+    }
+  }
+
+  List<String> operator [](String name) => _headers[name.toLowerCase()];
+
+  String value(String name) {
+    name = name.toLowerCase();
+    List<String> values = _headers[name];
+    if (values == null) return null;
+    if (values.length > 1) {
+      throw new HttpException("More than one value for header $name");
+    }
+    return values[0];
+  }
+
+  void add(String name, value) {
+    _checkMutable();
+    _addAll(_validateField(name), value);
+  }
+
+  void _addAll(String name, value) {
+    assert(name == _validateField(name));
+    if (value is Iterable) {
+      for (var v in value) {
+        _add(name, _validateValue(v));
+      }
+    } else {
+      _add(name, _validateValue(value));
+    }
+  }
+
+  void set(String name, Object value) {
+    _checkMutable();
+    name = _validateField(name);
+    _headers.remove(name);
+    if (name == HttpHeaders.transferEncodingHeader) {
+      _chunkedTransferEncoding = false;
+    }
+    _addAll(name, value);
+  }
+
+  void remove(String name, Object value) {
+    _checkMutable();
+    name = _validateField(name);
+    value = _validateValue(value);
+    List<String> values = _headers[name];
+    if (values != null) {
+      int index = values.indexOf(value);
+      if (index != -1) {
+        values.removeRange(index, index + 1);
+      }
+      if (values.length == 0) _headers.remove(name);
+    }
+    if (name == HttpHeaders.transferEncodingHeader && value == "chunked") {
+      _chunkedTransferEncoding = false;
+    }
+  }
+
+  void removeAll(String name) {
+    _checkMutable();
+    name = _validateField(name);
+    _headers.remove(name);
+  }
+
+  void forEach(void f(String name, List<String> values)) {
+    _headers.forEach(f);
+  }
+
+  void noFolding(String name) {
+    if (_noFoldingHeaders == null) _noFoldingHeaders = new List<String>();
+    _noFoldingHeaders.add(name);
+  }
+
+  bool get persistentConnection => _persistentConnection;
+
+  void set persistentConnection(bool persistentConnection) {
+    _checkMutable();
+    if (persistentConnection == _persistentConnection) return;
+    if (persistentConnection) {
+      if (protocolVersion == "1.1") {
+        remove(HttpHeaders.connectionHeader, "close");
+      } else {
+        if (_contentLength == -1) {
+          throw new HttpException(
+              "Trying to set 'Connection: Keep-Alive' on HTTP 1.0 headers with "
+              "no ContentLength");
+        }
+        add(HttpHeaders.connectionHeader, "keep-alive");
+      }
+    } else {
+      if (protocolVersion == "1.1") {
+        add(HttpHeaders.connectionHeader, "close");
+      } else {
+        remove(HttpHeaders.connectionHeader, "keep-alive");
+      }
+    }
+    _persistentConnection = persistentConnection;
+  }
+
+  int get contentLength => _contentLength;
+
+  void set contentLength(int contentLength) {
+    _checkMutable();
+    if (protocolVersion == "1.0" &&
+        persistentConnection &&
+        contentLength == -1) {
+      throw new HttpException(
+          "Trying to clear ContentLength on HTTP 1.0 headers with "
+          "'Connection: Keep-Alive' set");
+    }
+    if (_contentLength == contentLength) return;
+    _contentLength = contentLength;
+    if (_contentLength >= 0) {
+      if (chunkedTransferEncoding) chunkedTransferEncoding = false;
+      _set(HttpHeaders.contentLengthHeader, contentLength.toString());
+    } else {
+      removeAll(HttpHeaders.contentLengthHeader);
+      if (protocolVersion == "1.1") {
+        chunkedTransferEncoding = true;
+      }
+    }
+  }
+
+  bool get chunkedTransferEncoding => _chunkedTransferEncoding;
+
+  void set chunkedTransferEncoding(bool chunkedTransferEncoding) {
+    _checkMutable();
+    if (chunkedTransferEncoding && protocolVersion == "1.0") {
+      throw new HttpException(
+          "Trying to set 'Transfer-Encoding: Chunked' on HTTP 1.0 headers");
+    }
+    if (chunkedTransferEncoding == _chunkedTransferEncoding) return;
+    if (chunkedTransferEncoding) {
+      List<String> values = _headers[HttpHeaders.transferEncodingHeader];
+      if ((values == null || values.last != "chunked")) {
+        // Headers does not specify chunked encoding - add it if set.
+        _addValue(HttpHeaders.transferEncodingHeader, "chunked");
+      }
+      contentLength = -1;
+    } else {
+      // Headers does specify chunked encoding - remove it if not set.
+      remove(HttpHeaders.transferEncodingHeader, "chunked");
+    }
+    _chunkedTransferEncoding = chunkedTransferEncoding;
+  }
+
+  String get host => _host;
+
+  void set host(String host) {
+    _checkMutable();
+    _host = host;
+    _updateHostHeader();
+  }
+
+  int get port => _port;
+
+  void set port(int port) {
+    _checkMutable();
+    _port = port;
+    _updateHostHeader();
+  }
+
+  DateTime get ifModifiedSince {
+    List<String> values = _headers[HttpHeaders.ifModifiedSinceHeader];
+    if (values != null) {
+      try {
+        return HttpDate.parse(values[0]);
+      } on Exception catch (e) {
+        return null;
+      }
+    }
+    return null;
+  }
+
+  void set ifModifiedSince(DateTime ifModifiedSince) {
+    _checkMutable();
+    // Format "ifModifiedSince" header with date in Greenwich Mean Time (GMT).
+    String formatted = HttpDate.format(ifModifiedSince.toUtc());
+    _set(HttpHeaders.ifModifiedSinceHeader, formatted);
+  }
+
+  DateTime get date {
+    List<String> values = _headers[HttpHeaders.dateHeader];
+    if (values != null) {
+      try {
+        return HttpDate.parse(values[0]);
+      } on Exception catch (e) {
+        return null;
+      }
+    }
+    return null;
+  }
+
+  void set date(DateTime date) {
+    _checkMutable();
+    // Format "DateTime" header with date in Greenwich Mean Time (GMT).
+    String formatted = HttpDate.format(date.toUtc());
+    _set("date", formatted);
+  }
+
+  DateTime get expires {
+    List<String> values = _headers[HttpHeaders.expiresHeader];
+    if (values != null) {
+      try {
+        return HttpDate.parse(values[0]);
+      } on Exception catch (e) {
+        return null;
+      }
+    }
+    return null;
+  }
+
+  void set expires(DateTime expires) {
+    _checkMutable();
+    // Format "Expires" header with date in Greenwich Mean Time (GMT).
+    String formatted = HttpDate.format(expires.toUtc());
+    _set(HttpHeaders.expiresHeader, formatted);
+  }
+
+  ContentType get contentType {
+    var values = _headers["content-type"];
+    if (values != null) {
+      return ContentType.parse(values[0]);
+    } else {
+      return null;
+    }
+  }
+
+  void set contentType(ContentType contentType) {
+    _checkMutable();
+    _set(HttpHeaders.contentTypeHeader, contentType.toString());
+  }
+
+  void clear() {
+    _checkMutable();
+    _headers.clear();
+    _contentLength = -1;
+    _persistentConnection = true;
+    _chunkedTransferEncoding = false;
+    _host = null;
+    _port = null;
+  }
+
+  // [name] must be a lower-case version of the name.
+  void _add(String name, value) {
+    assert(name == _validateField(name));
+    // Use the length as index on what method to call. This is notable
+    // faster than computing hash and looking up in a hash-map.
+    switch (name.length) {
+      case 4:
+        if (HttpHeaders.dateHeader == name) {
+          _addDate(name, value);
+          return;
+        }
+        if (HttpHeaders.hostHeader == name) {
+          _addHost(name, value);
+          return;
+        }
+        break;
+      case 7:
+        if (HttpHeaders.expiresHeader == name) {
+          _addExpires(name, value);
+          return;
+        }
+        break;
+      case 10:
+        if (HttpHeaders.connectionHeader == name) {
+          _addConnection(name, value);
+          return;
+        }
+        break;
+      case 12:
+        if (HttpHeaders.contentTypeHeader == name) {
+          _addContentType(name, value);
+          return;
+        }
+        break;
+      case 14:
+        if (HttpHeaders.contentLengthHeader == name) {
+          _addContentLength(name, value);
+          return;
+        }
+        break;
+      case 17:
+        if (HttpHeaders.transferEncodingHeader == name) {
+          _addTransferEncoding(name, value);
+          return;
+        }
+        if (HttpHeaders.ifModifiedSinceHeader == name) {
+          _addIfModifiedSince(name, value);
+          return;
+        }
+    }
+    _addValue(name, value);
+  }
+
+  void _addContentLength(String name, value) {
+    if (value is int) {
+      contentLength = value;
+    } else if (value is String) {
+      contentLength = int.parse(value);
+    } else {
+      throw new HttpException("Unexpected type for header named $name");
+    }
+  }
+
+  void _addTransferEncoding(String name, value) {
+    if (value == "chunked") {
+      chunkedTransferEncoding = true;
+    } else {
+      _addValue(HttpHeaders.transferEncodingHeader, value);
+    }
+  }
+
+  void _addDate(String name, value) {
+    if (value is DateTime) {
+      date = value;
+    } else if (value is String) {
+      _set(HttpHeaders.dateHeader, value);
+    } else {
+      throw new HttpException("Unexpected type for header named $name");
+    }
+  }
+
+  void _addExpires(String name, value) {
+    if (value is DateTime) {
+      expires = value;
+    } else if (value is String) {
+      _set(HttpHeaders.expiresHeader, value);
+    } else {
+      throw new HttpException("Unexpected type for header named $name");
+    }
+  }
+
+  void _addIfModifiedSince(String name, value) {
+    if (value is DateTime) {
+      ifModifiedSince = value;
+    } else if (value is String) {
+      _set(HttpHeaders.ifModifiedSinceHeader, value);
+    } else {
+      throw new HttpException("Unexpected type for header named $name");
+    }
+  }
+
+  void _addHost(String name, value) {
+    if (value is String) {
+      int pos = value.indexOf(":");
+      if (pos == -1) {
+        _host = value;
+        _port = HttpClient.defaultHttpPort;
+      } else {
+        if (pos > 0) {
+          _host = value.substring(0, pos);
+        } else {
+          _host = null;
+        }
+        if (pos + 1 == value.length) {
+          _port = HttpClient.defaultHttpPort;
+        } else {
+          try {
+            _port = int.parse(value.substring(pos + 1));
+          } on FormatException catch (e) {
+            _port = null;
+          }
+        }
+      }
+      _set(HttpHeaders.hostHeader, value);
+    } else {
+      throw new HttpException("Unexpected type for header named $name");
+    }
+  }
+
+  void _addConnection(String name, value) {
+    var lowerCaseValue = value.toLowerCase();
+    if (lowerCaseValue == 'close') {
+      _persistentConnection = false;
+    } else if (lowerCaseValue == 'keep-alive') {
+      _persistentConnection = true;
+    }
+    _addValue(name, value);
+  }
+
+  void _addContentType(String name, value) {
+    _set(HttpHeaders.contentTypeHeader, value);
+  }
+
+  void _addValue(String name, Object value) {
+    List<String> values = _headers[name];
+    if (values == null) {
+      values = new List<String>();
+      _headers[name] = values;
+    }
+    if (value is DateTime) {
+      values.add(HttpDate.format(value));
+    } else if (value is String) {
+      values.add(value);
+    } else {
+      values.add(_validateValue(value.toString()));
+    }
+  }
+
+  void _set(String name, String value) {
+    assert(name == _validateField(name));
+    List<String> values = new List<String>();
+    _headers[name] = values;
+    values.add(value);
+  }
+
+  _checkMutable() {
+    if (!_mutable) throw new HttpException("HTTP headers are not mutable");
+  }
+
+  _updateHostHeader() {
+    bool defaultPort = _port == null || _port == _defaultPortForScheme;
+    _set("host", defaultPort ? host : "$host:$_port");
+  }
+
+  _foldHeader(String name) {
+    if (name == HttpHeaders.setCookieHeader ||
+        (_noFoldingHeaders != null && _noFoldingHeaders.indexOf(name) != -1)) {
+      return false;
+    }
+    return true;
+  }
+
+  void _finalize() {
+    _mutable = false;
+  }
+
+  void _build(BytesBuilder builder) {
+    for (String name in _headers.keys) {
+      List<String> values = _headers[name];
+      bool fold = _foldHeader(name);
+      var nameData = name.codeUnits;
+      builder.add(nameData);
+      builder.addByte(_CharCode.COLON);
+      builder.addByte(_CharCode.SP);
+      for (int i = 0; i < values.length; i++) {
+        if (i > 0) {
+          if (fold) {
+            builder.addByte(_CharCode.COMMA);
+            builder.addByte(_CharCode.SP);
+          } else {
+            builder.addByte(_CharCode.CR);
+            builder.addByte(_CharCode.LF);
+            builder.add(nameData);
+            builder.addByte(_CharCode.COLON);
+            builder.addByte(_CharCode.SP);
+          }
+        }
+        builder.add(values[i].codeUnits);
+      }
+      builder.addByte(_CharCode.CR);
+      builder.addByte(_CharCode.LF);
+    }
+  }
+
+  String toString() {
+    StringBuffer sb = new StringBuffer();
+    _headers.forEach((String name, List<String> values) {
+      sb..write(name)..write(": ");
+      bool fold = _foldHeader(name);
+      for (int i = 0; i < values.length; i++) {
+        if (i > 0) {
+          if (fold) {
+            sb.write(", ");
+          } else {
+            sb..write("\n")..write(name)..write(": ");
+          }
+        }
+        sb.write(values[i]);
+      }
+      sb.write("\n");
+    });
+    return sb.toString();
+  }
+
+  List<Cookie> _parseCookies() {
+    // Parse a Cookie header value according to the rules in RFC 6265.
+    var cookies = new List<Cookie>();
+    void parseCookieString(String s) {
+      int index = 0;
+
+      bool done() => index == -1 || index == s.length;
+
+      void skipWS() {
+        while (!done()) {
+          if (s[index] != " " && s[index] != "\t") return;
+          index++;
+        }
+      }
+
+      String parseName() {
+        int start = index;
+        while (!done()) {
+          if (s[index] == " " || s[index] == "\t" || s[index] == "=") break;
+          index++;
+        }
+        return s.substring(start, index);
+      }
+
+      String parseValue() {
+        int start = index;
+        while (!done()) {
+          if (s[index] == " " || s[index] == "\t" || s[index] == ";") break;
+          index++;
+        }
+        return s.substring(start, index);
+      }
+
+      bool expect(String expected) {
+        if (done()) return false;
+        if (s[index] != expected) return false;
+        index++;
+        return true;
+      }
+
+      while (!done()) {
+        skipWS();
+        if (done()) return;
+        String name = parseName();
+        skipWS();
+        if (!expect("=")) {
+          index = s.indexOf(';', index);
+          continue;
+        }
+        skipWS();
+        String value = parseValue();
+        try {
+          cookies.add(new _Cookie(name, value));
+        } catch (_) {
+          // Skip it, invalid cookie data.
+        }
+        skipWS();
+        if (done()) return;
+        if (!expect(";")) {
+          index = s.indexOf(';', index);
+          continue;
+        }
+      }
+    }
+
+    List<String> values = _headers[HttpHeaders.cookieHeader];
+    if (values != null) {
+      values.forEach((headerValue) => parseCookieString(headerValue));
+    }
+    return cookies;
+  }
+
+  static String _validateField(String field) {
+    for (var i = 0; i < field.length; i++) {
+      if (!_HttpParser._isTokenChar(field.codeUnitAt(i))) {
+        throw new FormatException(
+            "Invalid HTTP header field name: ${json.encode(field)}");
+      }
+    }
+    return field.toLowerCase();
+  }
+
+  static _validateValue(value) {
+    if (value is! String) return value;
+    for (var i = 0; i < value.length; i++) {
+      if (!_HttpParser._isValueChar(value.codeUnitAt(i))) {
+        throw new FormatException(
+            "Invalid HTTP header field value: ${json.encode(value)}");
+      }
+    }
+    return value;
+  }
+}
+
+class _HeaderValue implements HeaderValue {
+  String _value;
+  Map<String, String> _parameters;
+  Map<String, String> _unmodifiableParameters;
+
+  _HeaderValue([this._value = "", Map<String, String> parameters]) {
+    if (parameters != null) {
+      _parameters = new HashMap<String, String>.from(parameters);
+    }
+  }
+
+  static _HeaderValue parse(String value,
+      {parameterSeparator: ";",
+      valueSeparator: null,
+      preserveBackslash: false}) {
+    // Parse the string.
+    var result = new _HeaderValue();
+    result._parse(value, parameterSeparator, valueSeparator, preserveBackslash);
+    return result;
+  }
+
+  String get value => _value;
+
+  void _ensureParameters() {
+    if (_parameters == null) {
+      _parameters = new HashMap<String, String>();
+    }
+  }
+
+  Map<String, String> get parameters {
+    _ensureParameters();
+    if (_unmodifiableParameters == null) {
+      _unmodifiableParameters = new UnmodifiableMapView(_parameters);
+    }
+    return _unmodifiableParameters;
+  }
+
+  String toString() {
+    StringBuffer sb = new StringBuffer();
+    sb.write(_value);
+    if (parameters != null && parameters.length > 0) {
+      _parameters.forEach((String name, String value) {
+        sb..write("; ")..write(name)..write("=")..write(value);
+      });
+    }
+    return sb.toString();
+  }
+
+  void _parse(String s, String parameterSeparator, String valueSeparator,
+      bool preserveBackslash) {
+    int index = 0;
+
+    bool done() => index == s.length;
+
+    void skipWS() {
+      while (!done()) {
+        if (s[index] != " " && s[index] != "\t") return;
+        index++;
+      }
+    }
+
+    String parseValue() {
+      int start = index;
+      while (!done()) {
+        if (s[index] == " " ||
+            s[index] == "\t" ||
+            s[index] == valueSeparator ||
+            s[index] == parameterSeparator) break;
+        index++;
+      }
+      return s.substring(start, index);
+    }
+
+    void expect(String expected) {
+      if (done() || s[index] != expected) {
+        throw new HttpException("Failed to parse header value");
+      }
+      index++;
+    }
+
+    void maybeExpect(String expected) {
+      if (s[index] == expected) index++;
+    }
+
+    void parseParameters() {
+      var parameters = new HashMap<String, String>();
+      _parameters = new UnmodifiableMapView(parameters);
+
+      String parseParameterName() {
+        int start = index;
+        while (!done()) {
+          if (s[index] == " " ||
+              s[index] == "\t" ||
+              s[index] == "=" ||
+              s[index] == parameterSeparator ||
+              s[index] == valueSeparator) break;
+          index++;
+        }
+        return s.substring(start, index).toLowerCase();
+      }
+
+      String parseParameterValue() {
+        if (!done() && s[index] == "\"") {
+          // Parse quoted value.
+          StringBuffer sb = new StringBuffer();
+          index++;
+          while (!done()) {
+            if (s[index] == "\\") {
+              if (index + 1 == s.length) {
+                throw new HttpException("Failed to parse header value");
+              }
+              if (preserveBackslash && s[index + 1] != "\"") {
+                sb.write(s[index]);
+              }
+              index++;
+            } else if (s[index] == "\"") {
+              index++;
+              break;
+            }
+            sb.write(s[index]);
+            index++;
+          }
+          return sb.toString();
+        } else {
+          // Parse non-quoted value.
+          var val = parseValue();
+          return val == "" ? null : val;
+        }
+      }
+
+      while (!done()) {
+        skipWS();
+        if (done()) return;
+        String name = parseParameterName();
+        skipWS();
+        if (done()) {
+          parameters[name] = null;
+          return;
+        }
+        maybeExpect("=");
+        skipWS();
+        if (done()) {
+          parameters[name] = null;
+          return;
+        }
+        String value = parseParameterValue();
+        if (name == 'charset' && this is _ContentType && value != null) {
+          // Charset parameter of ContentTypes are always lower-case.
+          value = value.toLowerCase();
+        }
+        parameters[name] = value;
+        skipWS();
+        if (done()) return;
+        // TODO: Implement support for multi-valued parameters.
+        if (s[index] == valueSeparator) return;
+        expect(parameterSeparator);
+      }
+    }
+
+    skipWS();
+    _value = parseValue();
+    skipWS();
+    if (done()) return;
+    maybeExpect(parameterSeparator);
+    parseParameters();
+  }
+}
+
+class _ContentType extends _HeaderValue implements ContentType {
+  String _primaryType = "";
+  String _subType = "";
+
+  _ContentType(String primaryType, String subType, String charset,
+      Map<String, String> parameters)
+      : _primaryType = primaryType,
+        _subType = subType,
+        super("") {
+    if (_primaryType == null) _primaryType = "";
+    if (_subType == null) _subType = "";
+    _value = "$_primaryType/$_subType";
+    if (parameters != null) {
+      _ensureParameters();
+      parameters.forEach((String key, String value) {
+        String lowerCaseKey = key.toLowerCase();
+        if (lowerCaseKey == "charset") {
+          value = value.toLowerCase();
+        }
+        this._parameters[lowerCaseKey] = value;
+      });
+    }
+    if (charset != null) {
+      _ensureParameters();
+      this._parameters["charset"] = charset.toLowerCase();
+    }
+  }
+
+  _ContentType._();
+
+  static _ContentType parse(String value) {
+    var result = new _ContentType._();
+    result._parse(value, ";", null, false);
+    int index = result._value.indexOf("/");
+    if (index == -1 || index == (result._value.length - 1)) {
+      result._primaryType = result._value.trim().toLowerCase();
+      result._subType = "";
+    } else {
+      result._primaryType =
+          result._value.substring(0, index).trim().toLowerCase();
+      result._subType = result._value.substring(index + 1).trim().toLowerCase();
+    }
+    return result;
+  }
+
+  String get mimeType => '$primaryType/$subType';
+
+  String get primaryType => _primaryType;
+
+  String get subType => _subType;
+
+  String get charset => parameters["charset"];
+}
+
+class _Cookie implements Cookie {
+  String _name;
+  String _value;
+  DateTime expires;
+  int maxAge;
+  String domain;
+  String path;
+  bool httpOnly = false;
+  bool secure = false;
+
+  _Cookie(String name, String value)
+      : _name = _validateName(name),
+        _value = _validateValue(value),
+        httpOnly = true;
+
+  String get name => _name;
+  String get value => _value;
+
+  set name(String newName) {
+    _validateName(newName);
+    _name = newName;
+  }
+
+  set value(String newValue) {
+    _validateValue(newValue);
+    _value = newValue;
+  }
+
+  _Cookie.fromSetCookieValue(String value) {
+    // Parse the 'set-cookie' header value.
+    _parseSetCookieValue(value);
+  }
+
+  // Parse a 'set-cookie' header value according to the rules in RFC 6265.
+  void _parseSetCookieValue(String s) {
+    int index = 0;
+
+    bool done() => index == s.length;
+
+    String parseName() {
+      int start = index;
+      while (!done()) {
+        if (s[index] == "=") break;
+        index++;
+      }
+      return s.substring(start, index).trim();
+    }
+
+    String parseValue() {
+      int start = index;
+      while (!done()) {
+        if (s[index] == ";") break;
+        index++;
+      }
+      return s.substring(start, index).trim();
+    }
+
+    void expect(String expected) {
+      if (done()) throw new HttpException("Failed to parse header value [$s]");
+      if (s[index] != expected) {
+        throw new HttpException("Failed to parse header value [$s]");
+      }
+      index++;
+    }
+
+    void parseAttributes() {
+      String parseAttributeName() {
+        int start = index;
+        while (!done()) {
+          if (s[index] == "=" || s[index] == ";") break;
+          index++;
+        }
+        return s.substring(start, index).trim().toLowerCase();
+      }
+
+      String parseAttributeValue() {
+        int start = index;
+        while (!done()) {
+          if (s[index] == ";") break;
+          index++;
+        }
+        return s.substring(start, index).trim().toLowerCase();
+      }
+
+      while (!done()) {
+        String name = parseAttributeName();
+        String value = "";
+        if (!done() && s[index] == "=") {
+          index++; // Skip the = character.
+          value = parseAttributeValue();
+        }
+        if (name == "expires") {
+          expires = HttpDate._parseCookieDate(value);
+        } else if (name == "max-age") {
+          maxAge = int.parse(value);
+        } else if (name == "domain") {
+          domain = value;
+        } else if (name == "path") {
+          path = value;
+        } else if (name == "httponly") {
+          httpOnly = true;
+        } else if (name == "secure") {
+          secure = true;
+        }
+        if (!done()) index++; // Skip the ; character
+      }
+    }
+
+    _name = _validateName(parseName());
+    if (done() || _name.length == 0) {
+      throw new HttpException("Failed to parse header value [$s]");
+    }
+    index++; // Skip the = character.
+    _value = _validateValue(parseValue());
+    if (done()) return;
+    index++; // Skip the ; character.
+    parseAttributes();
+  }
+
+  String toString() {
+    StringBuffer sb = new StringBuffer();
+    sb..write(_name)..write("=")..write(_value);
+    if (expires != null) {
+      sb..write("; Expires=")..write(HttpDate.format(expires));
+    }
+    if (maxAge != null) {
+      sb..write("; Max-Age=")..write(maxAge);
+    }
+    if (domain != null) {
+      sb..write("; Domain=")..write(domain);
+    }
+    if (path != null) {
+      sb..write("; Path=")..write(path);
+    }
+    if (secure) sb.write("; Secure");
+    if (httpOnly) sb.write("; HttpOnly");
+    return sb.toString();
+  }
+
+  static String _validateName(String newName) {
+    const separators = const [
+      "(",
+      ")",
+      "<",
+      ">",
+      "@",
+      ",",
+      ";",
+      ":",
+      "\\",
+      '"',
+      "/",
+      "[",
+      "]",
+      "?",
+      "=",
+      "{",
+      "}"
+    ];
+    if (newName == null) throw new ArgumentError.notNull("name");
+    for (int i = 0; i < newName.length; i++) {
+      int codeUnit = newName.codeUnits[i];
+      if (codeUnit <= 32 ||
+          codeUnit >= 127 ||
+          separators.indexOf(newName[i]) >= 0) {
+        throw new FormatException(
+            "Invalid character in cookie name, code unit: '$codeUnit'",
+            newName,
+            i);
+      }
+    }
+    return newName;
+  }
+
+  static String _validateValue(String newValue) {
+    if (newValue == null) throw new ArgumentError.notNull("value");
+    // Per RFC 6265, consider surrounding "" as part of the value, but otherwise
+    // double quotes are not allowed.
+    int start = 0;
+    int end = newValue.length;
+    if (2 <= newValue.length &&
+        newValue.codeUnits[start] == 0x22 &&
+        newValue.codeUnits[end - 1] == 0x22) {
+      start++;
+      end--;
+    }
+
+    for (int i = start; i < end; i++) {
+      int codeUnit = newValue.codeUnits[i];
+      if (!(codeUnit == 0x21 ||
+          (codeUnit >= 0x23 && codeUnit <= 0x2B) ||
+          (codeUnit >= 0x2D && codeUnit <= 0x3A) ||
+          (codeUnit >= 0x3C && codeUnit <= 0x5B) ||
+          (codeUnit >= 0x5D && codeUnit <= 0x7E))) {
+        throw new FormatException(
+            "Invalid character in cookie value, code unit: '$codeUnit'",
+            newValue,
+            i);
+      }
+    }
+    return newValue;
+  }
+}
diff --git a/sdk_nnbd/lib/_http/http_impl.dart b/sdk_nnbd/lib/_http/http_impl.dart
new file mode 100644
index 0000000..cdf2412
--- /dev/null
+++ b/sdk_nnbd/lib/_http/http_impl.dart
@@ -0,0 +1,3237 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart._http;
+
+int _nextServiceId = 1;
+
+// TODO(ajohnsen): Use other way of getting a unique id.
+abstract class _ServiceObject {
+  int __serviceId = 0;
+  int get _serviceId {
+    if (__serviceId == 0) __serviceId = _nextServiceId++;
+    return __serviceId;
+  }
+
+  Map _toJSON(bool ref);
+
+  String get _servicePath => "$_serviceTypePath/$_serviceId";
+
+  String get _serviceTypePath;
+
+  String get _serviceTypeName;
+
+  String _serviceType(bool ref) {
+    if (ref) return "@$_serviceTypeName";
+    return _serviceTypeName;
+  }
+}
+
+class _CopyingBytesBuilder implements BytesBuilder {
+  // Start with 1024 bytes.
+  static const int _INIT_SIZE = 1024;
+
+  static final _emptyList = new Uint8List(0);
+
+  int _length = 0;
+  Uint8List _buffer;
+
+  _CopyingBytesBuilder([int initialCapacity = 0])
+      : _buffer = (initialCapacity <= 0)
+            ? _emptyList
+            : new Uint8List(_pow2roundup(initialCapacity));
+
+  void add(List<int> bytes) {
+    int bytesLength = bytes.length;
+    if (bytesLength == 0) return;
+    int required = _length + bytesLength;
+    if (_buffer.length < required) {
+      _grow(required);
+    }
+    assert(_buffer.length >= required);
+    if (bytes is Uint8List) {
+      _buffer.setRange(_length, required, bytes);
+    } else {
+      for (int i = 0; i < bytesLength; i++) {
+        _buffer[_length + i] = bytes[i];
+      }
+    }
+    _length = required;
+  }
+
+  void addByte(int byte) {
+    if (_buffer.length == _length) {
+      // The grow algorithm always at least doubles.
+      // If we added one to _length it would quadruple unnecessarily.
+      _grow(_length);
+    }
+    assert(_buffer.length > _length);
+    _buffer[_length] = byte;
+    _length++;
+  }
+
+  void _grow(int required) {
+    // We will create a list in the range of 2-4 times larger than
+    // required.
+    int newSize = required * 2;
+    if (newSize < _INIT_SIZE) {
+      newSize = _INIT_SIZE;
+    } else {
+      newSize = _pow2roundup(newSize);
+    }
+    var newBuffer = new Uint8List(newSize);
+    newBuffer.setRange(0, _buffer.length, _buffer);
+    _buffer = newBuffer;
+  }
+
+  Uint8List takeBytes() {
+    if (_length == 0) return _emptyList;
+    var buffer = new Uint8List.view(_buffer.buffer, 0, _length);
+    clear();
+    return buffer;
+  }
+
+  Uint8List toBytes() {
+    if (_length == 0) return _emptyList;
+    return new Uint8List.fromList(
+        new Uint8List.view(_buffer.buffer, 0, _length));
+  }
+
+  int get length => _length;
+
+  bool get isEmpty => _length == 0;
+
+  bool get isNotEmpty => _length != 0;
+
+  void clear() {
+    _length = 0;
+    _buffer = _emptyList;
+  }
+
+  static int _pow2roundup(int x) {
+    assert(x > 0);
+    --x;
+    x |= x >> 1;
+    x |= x >> 2;
+    x |= x >> 4;
+    x |= x >> 8;
+    x |= x >> 16;
+    return x + 1;
+  }
+}
+
+const int _OUTGOING_BUFFER_SIZE = 8 * 1024;
+
+typedef void _BytesConsumer(List<int> bytes);
+
+class _HttpIncoming extends Stream<Uint8List> {
+  final int _transferLength;
+  final Completer _dataCompleter = new Completer();
+  Stream<Uint8List> _stream;
+
+  bool fullBodyRead = false;
+
+  // Common properties.
+  final _HttpHeaders headers;
+  bool upgraded = false;
+
+  // ClientResponse properties.
+  int statusCode;
+  String reasonPhrase;
+
+  // Request properties.
+  String method;
+  Uri uri;
+
+  bool hasSubscriber = false;
+
+  // The transfer length if the length of the message body as it
+  // appears in the message (RFC 2616 section 4.4). This can be -1 if
+  // the length of the massage body is not known due to transfer
+  // codings.
+  int get transferLength => _transferLength;
+
+  _HttpIncoming(this.headers, this._transferLength, this._stream);
+
+  StreamSubscription<Uint8List> listen(void onData(Uint8List event),
+      {Function onError, void onDone(), bool cancelOnError}) {
+    hasSubscriber = true;
+    return _stream.handleError((error) {
+      throw new HttpException(error.message, uri: uri);
+    }).listen(onData,
+        onError: onError, onDone: onDone, cancelOnError: cancelOnError);
+  }
+
+  // Is completed once all data have been received.
+  Future get dataDone => _dataCompleter.future;
+
+  void close(bool closing) {
+    fullBodyRead = true;
+    hasSubscriber = true;
+    _dataCompleter.complete(closing);
+  }
+}
+
+abstract class _HttpInboundMessageListInt extends Stream<List<int>> {
+  final _HttpIncoming _incoming;
+  List<Cookie> _cookies;
+
+  _HttpInboundMessageListInt(this._incoming);
+
+  List<Cookie> get cookies {
+    if (_cookies != null) return _cookies;
+    return _cookies = headers._parseCookies();
+  }
+
+  _HttpHeaders get headers => _incoming.headers;
+  String get protocolVersion => headers.protocolVersion;
+  int get contentLength => headers.contentLength;
+  bool get persistentConnection => headers.persistentConnection;
+}
+
+abstract class _HttpInboundMessage extends Stream<Uint8List> {
+  final _HttpIncoming _incoming;
+  List<Cookie> _cookies;
+
+  _HttpInboundMessage(this._incoming);
+
+  List<Cookie> get cookies {
+    if (_cookies != null) return _cookies;
+    return _cookies = headers._parseCookies();
+  }
+
+  _HttpHeaders get headers => _incoming.headers;
+  String get protocolVersion => headers.protocolVersion;
+  int get contentLength => headers.contentLength;
+  bool get persistentConnection => headers.persistentConnection;
+}
+
+class _HttpRequest extends _HttpInboundMessage implements HttpRequest {
+  final HttpResponse response;
+
+  final _HttpServer _httpServer;
+
+  final _HttpConnection _httpConnection;
+
+  _HttpSession _session;
+
+  Uri _requestedUri;
+
+  _HttpRequest(this.response, _HttpIncoming _incoming, this._httpServer,
+      this._httpConnection)
+      : super(_incoming) {
+    if (headers.protocolVersion == "1.1") {
+      response.headers
+        ..chunkedTransferEncoding = true
+        ..persistentConnection = headers.persistentConnection;
+    }
+
+    if (_httpServer._sessionManagerInstance != null) {
+      // Map to session if exists.
+      var sessionIds = cookies
+          .where((cookie) => cookie.name.toUpperCase() == _DART_SESSION_ID)
+          .map((cookie) => cookie.value);
+      for (var sessionId in sessionIds) {
+        _session = _httpServer._sessionManager.getSession(sessionId);
+        if (_session != null) {
+          _session._markSeen();
+          break;
+        }
+      }
+    }
+  }
+
+  StreamSubscription<Uint8List> listen(void onData(Uint8List event),
+      {Function onError, void onDone(), bool cancelOnError}) {
+    return _incoming.listen(onData,
+        onError: onError, onDone: onDone, cancelOnError: cancelOnError);
+  }
+
+  Uri get uri => _incoming.uri;
+
+  Uri get requestedUri {
+    if (_requestedUri == null) {
+      var proto = headers['x-forwarded-proto'];
+      var scheme = proto != null
+          ? proto.first
+          : _httpConnection._socket is SecureSocket ? "https" : "http";
+      var hostList = headers['x-forwarded-host'];
+      String host;
+      if (hostList != null) {
+        host = hostList.first;
+      } else {
+        hostList = headers['host'];
+        if (hostList != null) {
+          host = hostList.first;
+        } else {
+          host = "${_httpServer.address.host}:${_httpServer.port}";
+        }
+      }
+      _requestedUri = Uri.parse("$scheme://$host$uri");
+    }
+    return _requestedUri;
+  }
+
+  String get method => _incoming.method;
+
+  HttpSession get session {
+    if (_session != null) {
+      if (_session._destroyed) {
+        // It's destroyed, clear it.
+        _session = null;
+        // Create new session object by calling recursive.
+        return session;
+      }
+      // It's already mapped, use it.
+      return _session;
+    }
+    // Create session, store it in connection, and return.
+    return _session = _httpServer._sessionManager.createSession();
+  }
+
+  HttpConnectionInfo get connectionInfo => _httpConnection.connectionInfo;
+
+  X509Certificate get certificate {
+    var socket = _httpConnection._socket;
+    if (socket is SecureSocket) return socket.peerCertificate;
+    return null;
+  }
+}
+
+class _HttpClientResponse extends _HttpInboundMessageListInt
+    implements HttpClientResponse {
+  List<RedirectInfo> get redirects => _httpRequest._responseRedirects;
+
+  // The HttpClient this response belongs to.
+  final _HttpClient _httpClient;
+
+  // The HttpClientRequest of this response.
+  final _HttpClientRequest _httpRequest;
+
+  // The compression state of this response.
+  final HttpClientResponseCompressionState compressionState;
+
+  _HttpClientResponse(
+      _HttpIncoming _incoming, this._httpRequest, this._httpClient)
+      : compressionState = _getCompressionState(_httpClient, _incoming.headers),
+        super(_incoming) {
+    // Set uri for potential exceptions.
+    _incoming.uri = _httpRequest.uri;
+  }
+
+  static HttpClientResponseCompressionState _getCompressionState(
+      _HttpClient httpClient, _HttpHeaders headers) {
+    if (headers.value(HttpHeaders.contentEncodingHeader) == "gzip") {
+      return httpClient.autoUncompress
+          ? HttpClientResponseCompressionState.decompressed
+          : HttpClientResponseCompressionState.compressed;
+    } else {
+      return HttpClientResponseCompressionState.notCompressed;
+    }
+  }
+
+  int get statusCode => _incoming.statusCode;
+  String get reasonPhrase => _incoming.reasonPhrase;
+
+  X509Certificate get certificate {
+    var socket = _httpRequest._httpClientConnection._socket;
+    if (socket is SecureSocket) return socket.peerCertificate;
+    return null;
+  }
+
+  List<Cookie> get cookies {
+    if (_cookies != null) return _cookies;
+    _cookies = new List<Cookie>();
+    List<String> values = headers[HttpHeaders.setCookieHeader];
+    if (values != null) {
+      values.forEach((value) {
+        _cookies.add(new Cookie.fromSetCookieValue(value));
+      });
+    }
+    return _cookies;
+  }
+
+  bool get isRedirect {
+    if (_httpRequest.method == "GET" || _httpRequest.method == "HEAD") {
+      return statusCode == HttpStatus.movedPermanently ||
+          statusCode == HttpStatus.found ||
+          statusCode == HttpStatus.seeOther ||
+          statusCode == HttpStatus.temporaryRedirect;
+    } else if (_httpRequest.method == "POST") {
+      return statusCode == HttpStatus.seeOther;
+    }
+    return false;
+  }
+
+  Future<HttpClientResponse> redirect(
+      [String method, Uri url, bool followLoops]) {
+    if (method == null) {
+      // Set method as defined by RFC 2616 section 10.3.4.
+      if (statusCode == HttpStatus.seeOther && _httpRequest.method == "POST") {
+        method = "GET";
+      } else {
+        method = _httpRequest.method;
+      }
+    }
+    if (url == null) {
+      String location = headers.value(HttpHeaders.locationHeader);
+      if (location == null) {
+        throw new StateError("Response has no Location header for redirect");
+      }
+      url = Uri.parse(location);
+    }
+    if (followLoops != true) {
+      for (var redirect in redirects) {
+        if (redirect.location == url) {
+          return new Future.error(
+              new RedirectException("Redirect loop detected", redirects));
+        }
+      }
+    }
+    return _httpClient
+        ._openUrlFromRequest(method, url, _httpRequest)
+        .then((request) {
+      request._responseRedirects
+        ..addAll(this.redirects)
+        ..add(new _RedirectInfo(statusCode, method, url));
+      return request.close();
+    });
+  }
+
+  StreamSubscription<Uint8List> listen(void onData(Uint8List event),
+      {Function onError, void onDone(), bool cancelOnError}) {
+    if (_incoming.upgraded) {
+      // If upgraded, the connection is already 'removed' form the client.
+      // Since listening to upgraded data is 'bogus', simply close and
+      // return empty stream subscription.
+      _httpRequest._httpClientConnection.destroy();
+      return new Stream<Uint8List>.empty().listen(null, onDone: onDone);
+    }
+    Stream<Uint8List> stream = _incoming;
+    if (compressionState == HttpClientResponseCompressionState.decompressed) {
+      stream = stream
+          .cast<List<int>>()
+          .transform(gzip.decoder)
+          .transform(const _ToUint8List());
+    }
+    return stream.listen(onData,
+        onError: onError, onDone: onDone, cancelOnError: cancelOnError);
+  }
+
+  Future<Socket> detachSocket() {
+    _httpClient._connectionClosed(_httpRequest._httpClientConnection);
+    return _httpRequest._httpClientConnection.detachSocket();
+  }
+
+  HttpConnectionInfo get connectionInfo => _httpRequest.connectionInfo;
+
+  bool get _shouldAuthenticateProxy {
+    // Only try to authenticate if there is a challenge in the response.
+    List<String> challenge = headers[HttpHeaders.proxyAuthenticateHeader];
+    return statusCode == HttpStatus.proxyAuthenticationRequired &&
+        challenge != null &&
+        challenge.length == 1;
+  }
+
+  bool get _shouldAuthenticate {
+    // Only try to authenticate if there is a challenge in the response.
+    List<String> challenge = headers[HttpHeaders.wwwAuthenticateHeader];
+    return statusCode == HttpStatus.unauthorized &&
+        challenge != null &&
+        challenge.length == 1;
+  }
+
+  Future<HttpClientResponse> _authenticate(bool proxyAuth) {
+    Future<HttpClientResponse> retry() {
+      // Drain body and retry.
+      return drain().then((_) {
+        return _httpClient
+            ._openUrlFromRequest(
+                _httpRequest.method, _httpRequest.uri, _httpRequest)
+            .then((request) => request.close());
+      });
+    }
+
+    List<String> authChallenge() {
+      return proxyAuth
+          ? headers[HttpHeaders.proxyAuthenticateHeader]
+          : headers[HttpHeaders.wwwAuthenticateHeader];
+    }
+
+    _Credentials findCredentials(_AuthenticationScheme scheme) {
+      return proxyAuth
+          ? _httpClient._findProxyCredentials(_httpRequest._proxy, scheme)
+          : _httpClient._findCredentials(_httpRequest.uri, scheme);
+    }
+
+    void removeCredentials(_Credentials cr) {
+      if (proxyAuth) {
+        _httpClient._removeProxyCredentials(cr);
+      } else {
+        _httpClient._removeCredentials(cr);
+      }
+    }
+
+    Future requestAuthentication(_AuthenticationScheme scheme, String realm) {
+      if (proxyAuth) {
+        if (_httpClient._authenticateProxy == null) {
+          return new Future.value(false);
+        }
+        var proxy = _httpRequest._proxy;
+        return _httpClient._authenticateProxy(
+            proxy.host, proxy.port, scheme.toString(), realm);
+      } else {
+        if (_httpClient._authenticate == null) {
+          return new Future.value(false);
+        }
+        return _httpClient._authenticate(
+            _httpRequest.uri, scheme.toString(), realm);
+      }
+    }
+
+    List<String> challenge = authChallenge();
+    assert(challenge != null || challenge.length == 1);
+    _HeaderValue header =
+        _HeaderValue.parse(challenge[0], parameterSeparator: ",");
+    _AuthenticationScheme scheme =
+        new _AuthenticationScheme.fromString(header.value);
+    String realm = header.parameters["realm"];
+
+    // See if any matching credentials are available.
+    _Credentials cr = findCredentials(scheme);
+    if (cr != null) {
+      // For basic authentication don't retry already used credentials
+      // as they must have already been added to the request causing
+      // this authenticate response.
+      if (cr.scheme == _AuthenticationScheme.BASIC && !cr.used) {
+        // Credentials where found, prepare for retrying the request.
+        return retry();
+      }
+
+      // Digest authentication only supports the MD5 algorithm.
+      if (cr.scheme == _AuthenticationScheme.DIGEST &&
+          (header.parameters["algorithm"] == null ||
+              header.parameters["algorithm"].toLowerCase() == "md5")) {
+        if (cr.nonce == null || cr.nonce == header.parameters["nonce"]) {
+          // If the nonce is not set then this is the first authenticate
+          // response for these credentials. Set up authentication state.
+          if (cr.nonce == null) {
+            cr
+              ..nonce = header.parameters["nonce"]
+              ..algorithm = "MD5"
+              ..qop = header.parameters["qop"]
+              ..nonceCount = 0;
+          }
+          // Credentials where found, prepare for retrying the request.
+          return retry();
+        } else if (header.parameters["stale"] != null &&
+            header.parameters["stale"].toLowerCase() == "true") {
+          // If stale is true retry with new nonce.
+          cr.nonce = header.parameters["nonce"];
+          // Credentials where found, prepare for retrying the request.
+          return retry();
+        }
+      }
+    }
+
+    // Ask for more credentials if none found or the one found has
+    // already been used. If it has already been used it must now be
+    // invalid and is removed.
+    if (cr != null) {
+      removeCredentials(cr);
+      cr = null;
+    }
+    return requestAuthentication(scheme, realm).then((credsAvailable) {
+      if (credsAvailable) {
+        cr = _httpClient._findCredentials(_httpRequest.uri, scheme);
+        return retry();
+      } else {
+        // No credentials available, complete with original response.
+        return this;
+      }
+    });
+  }
+}
+
+class _ToUint8List extends Converter<List<int>, Uint8List> {
+  const _ToUint8List();
+
+  Uint8List convert(List<int> input) => Uint8List.fromList(input);
+
+  Sink<List<int>> startChunkedConversion(Sink<Uint8List> sink) {
+    return _Uint8ListConversionSink(sink);
+  }
+}
+
+class _Uint8ListConversionSink implements Sink<List<int>> {
+  const _Uint8ListConversionSink(this._target);
+
+  final Sink<Uint8List> _target;
+
+  void add(List<int> data) {
+    _target.add(Uint8List.fromList(data));
+  }
+
+  void close() {
+    _target.close();
+  }
+}
+
+class _StreamSinkImpl<T> implements StreamSink<T> {
+  final StreamConsumer<T> _target;
+  final Completer _doneCompleter = new Completer();
+  StreamController<T> _controllerInstance;
+  Completer _controllerCompleter;
+  bool _isClosed = false;
+  bool _isBound = false;
+  bool _hasError = false;
+
+  _StreamSinkImpl(this._target);
+
+  void add(T data) {
+    if (_isClosed) {
+      throw StateError("StreamSink is closed");
+    }
+    _controller.add(data);
+  }
+
+  void addError(error, [StackTrace stackTrace]) {
+    if (_isClosed) {
+      throw StateError("StreamSink is closed");
+    }
+    _controller.addError(error, stackTrace);
+  }
+
+  Future addStream(Stream<T> stream) {
+    if (_isBound) {
+      throw new StateError("StreamSink is already bound to a stream");
+    }
+    _isBound = true;
+    if (_hasError) return done;
+    // Wait for any sync operations to complete.
+    Future targetAddStream() {
+      return _target.addStream(stream).whenComplete(() {
+        _isBound = false;
+      });
+    }
+
+    if (_controllerInstance == null) return targetAddStream();
+    var future = _controllerCompleter.future;
+    _controllerInstance.close();
+    return future.then((_) => targetAddStream());
+  }
+
+  Future flush() {
+    if (_isBound) {
+      throw new StateError("StreamSink is bound to a stream");
+    }
+    if (_controllerInstance == null) return new Future.value(this);
+    // Adding an empty stream-controller will return a future that will complete
+    // when all data is done.
+    _isBound = true;
+    var future = _controllerCompleter.future;
+    _controllerInstance.close();
+    return future.whenComplete(() {
+      _isBound = false;
+    });
+  }
+
+  Future close() {
+    if (_isBound) {
+      throw new StateError("StreamSink is bound to a stream");
+    }
+    if (!_isClosed) {
+      _isClosed = true;
+      if (_controllerInstance != null) {
+        _controllerInstance.close();
+      } else {
+        _closeTarget();
+      }
+    }
+    return done;
+  }
+
+  void _closeTarget() {
+    _target.close().then(_completeDoneValue, onError: _completeDoneError);
+  }
+
+  Future get done => _doneCompleter.future;
+
+  void _completeDoneValue(value) {
+    if (!_doneCompleter.isCompleted) {
+      _doneCompleter.complete(value);
+    }
+  }
+
+  void _completeDoneError(error, StackTrace stackTrace) {
+    if (!_doneCompleter.isCompleted) {
+      _hasError = true;
+      _doneCompleter.completeError(error, stackTrace);
+    }
+  }
+
+  StreamController<T> get _controller {
+    if (_isBound) {
+      throw new StateError("StreamSink is bound to a stream");
+    }
+    if (_isClosed) {
+      throw new StateError("StreamSink is closed");
+    }
+    if (_controllerInstance == null) {
+      _controllerInstance = new StreamController<T>(sync: true);
+      _controllerCompleter = new Completer();
+      _target.addStream(_controller.stream).then((_) {
+        if (_isBound) {
+          // A new stream takes over - forward values to that stream.
+          _controllerCompleter.complete(this);
+          _controllerCompleter = null;
+          _controllerInstance = null;
+        } else {
+          // No new stream, .close was called. Close _target.
+          _closeTarget();
+        }
+      }, onError: (error, stackTrace) {
+        if (_isBound) {
+          // A new stream takes over - forward errors to that stream.
+          _controllerCompleter.completeError(error, stackTrace);
+          _controllerCompleter = null;
+          _controllerInstance = null;
+        } else {
+          // No new stream. No need to close target, as it has already
+          // failed.
+          _completeDoneError(error, stackTrace);
+        }
+      });
+    }
+    return _controllerInstance;
+  }
+}
+
+class _IOSinkImpl extends _StreamSinkImpl<List<int>> implements IOSink {
+  Encoding _encoding;
+  bool _encodingMutable = true;
+
+  _IOSinkImpl(StreamConsumer<List<int>> target, this._encoding) : super(target);
+
+  Encoding get encoding => _encoding;
+
+  void set encoding(Encoding value) {
+    if (!_encodingMutable) {
+      throw new StateError("IOSink encoding is not mutable");
+    }
+    _encoding = value;
+  }
+
+  void write(Object obj) {
+    String string = '$obj';
+    if (string.isEmpty) return;
+    add(_encoding.encode(string));
+  }
+
+  void writeAll(Iterable objects, [String separator = ""]) {
+    Iterator iterator = objects.iterator;
+    if (!iterator.moveNext()) return;
+    if (separator.isEmpty) {
+      do {
+        write(iterator.current);
+      } while (iterator.moveNext());
+    } else {
+      write(iterator.current);
+      while (iterator.moveNext()) {
+        write(separator);
+        write(iterator.current);
+      }
+    }
+  }
+
+  void writeln([Object object = ""]) {
+    write(object);
+    write("\n");
+  }
+
+  void writeCharCode(int charCode) {
+    write(new String.fromCharCode(charCode));
+  }
+}
+
+abstract class _HttpOutboundMessage<T> extends _IOSinkImpl {
+  // Used to mark when the body should be written. This is used for HEAD
+  // requests and in error handling.
+  bool _encodingSet = false;
+
+  bool _bufferOutput = true;
+
+  final Uri _uri;
+  final _HttpOutgoing _outgoing;
+
+  final _HttpHeaders headers;
+
+  _HttpOutboundMessage(Uri uri, String protocolVersion, _HttpOutgoing outgoing,
+      {_HttpHeaders initialHeaders})
+      : _uri = uri,
+        headers = new _HttpHeaders(protocolVersion,
+            defaultPortForScheme: uri.scheme == 'https'
+                ? HttpClient.defaultHttpsPort
+                : HttpClient.defaultHttpPort,
+            initialHeaders: initialHeaders),
+        _outgoing = outgoing,
+        super(outgoing, null) {
+    _outgoing.outbound = this;
+    _encodingMutable = false;
+  }
+
+  int get contentLength => headers.contentLength;
+  void set contentLength(int contentLength) {
+    headers.contentLength = contentLength;
+  }
+
+  bool get persistentConnection => headers.persistentConnection;
+  void set persistentConnection(bool p) {
+    headers.persistentConnection = p;
+  }
+
+  bool get bufferOutput => _bufferOutput;
+  void set bufferOutput(bool bufferOutput) {
+    if (_outgoing.headersWritten) throw new StateError("Header already sent");
+    _bufferOutput = bufferOutput;
+  }
+
+  Encoding get encoding {
+    if (_encodingSet && _outgoing.headersWritten) {
+      return _encoding;
+    }
+    var charset;
+    if (headers.contentType != null && headers.contentType.charset != null) {
+      charset = headers.contentType.charset;
+    } else {
+      charset = "iso-8859-1";
+    }
+    return Encoding.getByName(charset);
+  }
+
+  void add(List<int> data) {
+    if (data.length == 0) return;
+    super.add(data);
+  }
+
+  void write(Object obj) {
+    if (!_encodingSet) {
+      _encoding = encoding;
+      _encodingSet = true;
+    }
+    super.write(obj);
+  }
+
+  void _writeHeader();
+
+  bool get _isConnectionClosed => false;
+}
+
+class _HttpResponse extends _HttpOutboundMessage<HttpResponse>
+    implements HttpResponse {
+  int _statusCode = 200;
+  String _reasonPhrase;
+  List<Cookie> _cookies;
+  _HttpRequest _httpRequest;
+  Duration _deadline;
+  Timer _deadlineTimer;
+
+  _HttpResponse(Uri uri, String protocolVersion, _HttpOutgoing outgoing,
+      HttpHeaders defaultHeaders, String serverHeader)
+      : super(uri, protocolVersion, outgoing, initialHeaders: defaultHeaders) {
+    if (serverHeader != null) headers.set('server', serverHeader);
+  }
+
+  bool get _isConnectionClosed => _httpRequest._httpConnection._isClosing;
+
+  List<Cookie> get cookies {
+    if (_cookies == null) _cookies = new List<Cookie>();
+    return _cookies;
+  }
+
+  int get statusCode => _statusCode;
+  void set statusCode(int statusCode) {
+    if (_outgoing.headersWritten) throw new StateError("Header already sent");
+    _statusCode = statusCode;
+  }
+
+  String get reasonPhrase => _findReasonPhrase(statusCode);
+  void set reasonPhrase(String reasonPhrase) {
+    if (_outgoing.headersWritten) throw new StateError("Header already sent");
+    _reasonPhrase = reasonPhrase;
+  }
+
+  Future redirect(Uri location, {int status: HttpStatus.movedTemporarily}) {
+    if (_outgoing.headersWritten) throw new StateError("Header already sent");
+    statusCode = status;
+    headers.set("location", location.toString());
+    return close();
+  }
+
+  Future<Socket> detachSocket({bool writeHeaders: true}) {
+    if (_outgoing.headersWritten) throw new StateError("Headers already sent");
+    deadline = null; // Be sure to stop any deadline.
+    var future = _httpRequest._httpConnection.detachSocket();
+    if (writeHeaders) {
+      var headersFuture =
+          _outgoing.writeHeaders(drainRequest: false, setOutgoing: false);
+      assert(headersFuture == null);
+    } else {
+      // Imitate having written the headers.
+      _outgoing.headersWritten = true;
+    }
+    // Close connection so the socket is 'free'.
+    close();
+    done.catchError((_) {
+      // Catch any error on done, as they automatically will be
+      // propagated to the websocket.
+    });
+    return future;
+  }
+
+  HttpConnectionInfo get connectionInfo => _httpRequest.connectionInfo;
+
+  Duration get deadline => _deadline;
+
+  void set deadline(Duration d) {
+    if (_deadlineTimer != null) _deadlineTimer.cancel();
+    _deadline = d;
+
+    if (_deadline == null) return;
+    _deadlineTimer = new Timer(_deadline, () {
+      _httpRequest._httpConnection.destroy();
+    });
+  }
+
+  void _writeHeader() {
+    BytesBuilder buffer = new _CopyingBytesBuilder(_OUTGOING_BUFFER_SIZE);
+
+    // Write status line.
+    if (headers.protocolVersion == "1.1") {
+      buffer.add(_Const.HTTP11);
+    } else {
+      buffer.add(_Const.HTTP10);
+    }
+    buffer.addByte(_CharCode.SP);
+    buffer.add(statusCode.toString().codeUnits);
+    buffer.addByte(_CharCode.SP);
+    buffer.add(reasonPhrase.codeUnits);
+    buffer.addByte(_CharCode.CR);
+    buffer.addByte(_CharCode.LF);
+
+    var session = _httpRequest._session;
+    if (session != null && !session._destroyed) {
+      // Mark as not new.
+      session._isNew = false;
+      // Make sure we only send the current session id.
+      bool found = false;
+      for (int i = 0; i < cookies.length; i++) {
+        if (cookies[i].name.toUpperCase() == _DART_SESSION_ID) {
+          cookies[i]
+            ..value = session.id
+            ..httpOnly = true
+            ..path = "/";
+          found = true;
+        }
+      }
+      if (!found) {
+        var cookie = new Cookie(_DART_SESSION_ID, session.id);
+        cookies.add(cookie
+          ..httpOnly = true
+          ..path = "/");
+      }
+    }
+    // Add all the cookies set to the headers.
+    if (_cookies != null) {
+      _cookies.forEach((cookie) {
+        headers.add(HttpHeaders.setCookieHeader, cookie);
+      });
+    }
+
+    headers._finalize();
+
+    // Write headers.
+    headers._build(buffer);
+    buffer.addByte(_CharCode.CR);
+    buffer.addByte(_CharCode.LF);
+    Uint8List headerBytes = buffer.takeBytes();
+    _outgoing.setHeader(headerBytes, headerBytes.length);
+  }
+
+  String _findReasonPhrase(int statusCode) {
+    if (_reasonPhrase != null) {
+      return _reasonPhrase;
+    }
+
+    switch (statusCode) {
+      case HttpStatus.continue_:
+        return "Continue";
+      case HttpStatus.switchingProtocols:
+        return "Switching Protocols";
+      case HttpStatus.ok:
+        return "OK";
+      case HttpStatus.created:
+        return "Created";
+      case HttpStatus.accepted:
+        return "Accepted";
+      case HttpStatus.nonAuthoritativeInformation:
+        return "Non-Authoritative Information";
+      case HttpStatus.noContent:
+        return "No Content";
+      case HttpStatus.resetContent:
+        return "Reset Content";
+      case HttpStatus.partialContent:
+        return "Partial Content";
+      case HttpStatus.multipleChoices:
+        return "Multiple Choices";
+      case HttpStatus.movedPermanently:
+        return "Moved Permanently";
+      case HttpStatus.found:
+        return "Found";
+      case HttpStatus.seeOther:
+        return "See Other";
+      case HttpStatus.notModified:
+        return "Not Modified";
+      case HttpStatus.useProxy:
+        return "Use Proxy";
+      case HttpStatus.temporaryRedirect:
+        return "Temporary Redirect";
+      case HttpStatus.badRequest:
+        return "Bad Request";
+      case HttpStatus.unauthorized:
+        return "Unauthorized";
+      case HttpStatus.paymentRequired:
+        return "Payment Required";
+      case HttpStatus.forbidden:
+        return "Forbidden";
+      case HttpStatus.notFound:
+        return "Not Found";
+      case HttpStatus.methodNotAllowed:
+        return "Method Not Allowed";
+      case HttpStatus.notAcceptable:
+        return "Not Acceptable";
+      case HttpStatus.proxyAuthenticationRequired:
+        return "Proxy Authentication Required";
+      case HttpStatus.requestTimeout:
+        return "Request Time-out";
+      case HttpStatus.conflict:
+        return "Conflict";
+      case HttpStatus.gone:
+        return "Gone";
+      case HttpStatus.lengthRequired:
+        return "Length Required";
+      case HttpStatus.preconditionFailed:
+        return "Precondition Failed";
+      case HttpStatus.requestEntityTooLarge:
+        return "Request Entity Too Large";
+      case HttpStatus.requestUriTooLong:
+        return "Request-URI Too Long";
+      case HttpStatus.unsupportedMediaType:
+        return "Unsupported Media Type";
+      case HttpStatus.requestedRangeNotSatisfiable:
+        return "Requested range not satisfiable";
+      case HttpStatus.expectationFailed:
+        return "Expectation Failed";
+      case HttpStatus.internalServerError:
+        return "Internal Server Error";
+      case HttpStatus.notImplemented:
+        return "Not Implemented";
+      case HttpStatus.badGateway:
+        return "Bad Gateway";
+      case HttpStatus.serviceUnavailable:
+        return "Service Unavailable";
+      case HttpStatus.gatewayTimeout:
+        return "Gateway Time-out";
+      case HttpStatus.httpVersionNotSupported:
+        return "Http Version not supported";
+      default:
+        return "Status $statusCode";
+    }
+  }
+}
+
+class _HttpClientRequest extends _HttpOutboundMessage<HttpClientResponse>
+    implements HttpClientRequest {
+  final String method;
+  final Uri uri;
+  final List<Cookie> cookies = new List<Cookie>();
+
+  // The HttpClient this request belongs to.
+  final _HttpClient _httpClient;
+  final _HttpClientConnection _httpClientConnection;
+
+  final Completer<HttpClientResponse> _responseCompleter =
+      new Completer<HttpClientResponse>();
+
+  final _Proxy _proxy;
+
+  Future<HttpClientResponse> _response;
+
+  // TODO(ajohnsen): Get default value from client?
+  bool _followRedirects = true;
+
+  int _maxRedirects = 5;
+
+  List<RedirectInfo> _responseRedirects = [];
+
+  _HttpClientRequest(_HttpOutgoing outgoing, Uri uri, this.method, this._proxy,
+      this._httpClient, this._httpClientConnection)
+      : uri = uri,
+        super(uri, "1.1", outgoing) {
+    // GET and HEAD have 'content-length: 0' by default.
+    if (method == "GET" || method == "HEAD") {
+      contentLength = 0;
+    } else {
+      headers.chunkedTransferEncoding = true;
+    }
+  }
+
+  Future<HttpClientResponse> get done {
+    if (_response == null) {
+      _response =
+          Future.wait([_responseCompleter.future, super.done], eagerError: true)
+              .then((list) => list[0]);
+    }
+    return _response;
+  }
+
+  Future<HttpClientResponse> close() {
+    super.close();
+    return done;
+  }
+
+  int get maxRedirects => _maxRedirects;
+  void set maxRedirects(int maxRedirects) {
+    if (_outgoing.headersWritten) throw new StateError("Request already sent");
+    _maxRedirects = maxRedirects;
+  }
+
+  bool get followRedirects => _followRedirects;
+  void set followRedirects(bool followRedirects) {
+    if (_outgoing.headersWritten) throw new StateError("Request already sent");
+    _followRedirects = followRedirects;
+  }
+
+  HttpConnectionInfo get connectionInfo => _httpClientConnection.connectionInfo;
+
+  void _onIncoming(_HttpIncoming incoming) {
+    var response = new _HttpClientResponse(incoming, this, _httpClient);
+    Future<HttpClientResponse> future;
+    if (followRedirects && response.isRedirect) {
+      if (response.redirects.length < maxRedirects) {
+        // Redirect and drain response.
+        future = response
+            .drain()
+            .then<HttpClientResponse>((_) => response.redirect());
+      } else {
+        // End with exception, too many redirects.
+        future = response.drain().then<HttpClientResponse>((_) {
+          return new Future<HttpClientResponse>.error(new RedirectException(
+              "Redirect limit exceeded", response.redirects));
+        });
+      }
+    } else if (response._shouldAuthenticateProxy) {
+      future = response._authenticate(true);
+    } else if (response._shouldAuthenticate) {
+      future = response._authenticate(false);
+    } else {
+      future = new Future<HttpClientResponse>.value(response);
+    }
+    future.then((v) => _responseCompleter.complete(v),
+        onError: _responseCompleter.completeError);
+  }
+
+  void _onError(error, StackTrace stackTrace) {
+    _responseCompleter.completeError(error, stackTrace);
+  }
+
+  // Generate the request URI based on the method and proxy.
+  String _requestUri() {
+    // Generate the request URI starting from the path component.
+    String uriStartingFromPath() {
+      String result = uri.path;
+      if (result.isEmpty) result = "/";
+      if (uri.hasQuery) {
+        result = "${result}?${uri.query}";
+      }
+      return result;
+    }
+
+    if (_proxy.isDirect) {
+      return uriStartingFromPath();
+    } else {
+      if (method == "CONNECT") {
+        // For the connect method the request URI is the host:port of
+        // the requested destination of the tunnel (see RFC 2817
+        // section 5.2)
+        return "${uri.host}:${uri.port}";
+      } else {
+        if (_httpClientConnection._proxyTunnel) {
+          return uriStartingFromPath();
+        } else {
+          return uri.removeFragment().toString();
+        }
+      }
+    }
+  }
+
+  void _writeHeader() {
+    BytesBuilder buffer = new _CopyingBytesBuilder(_OUTGOING_BUFFER_SIZE);
+
+    // Write the request method.
+    buffer.add(method.codeUnits);
+    buffer.addByte(_CharCode.SP);
+    // Write the request URI.
+    buffer.add(_requestUri().codeUnits);
+    buffer.addByte(_CharCode.SP);
+    // Write HTTP/1.1.
+    buffer.add(_Const.HTTP11);
+    buffer.addByte(_CharCode.CR);
+    buffer.addByte(_CharCode.LF);
+
+    // Add the cookies to the headers.
+    if (!cookies.isEmpty) {
+      StringBuffer sb = new StringBuffer();
+      for (int i = 0; i < cookies.length; i++) {
+        if (i > 0) sb.write("; ");
+        sb..write(cookies[i].name)..write("=")..write(cookies[i].value);
+      }
+      headers.add(HttpHeaders.cookieHeader, sb.toString());
+    }
+
+    headers._finalize();
+
+    // Write headers.
+    headers._build(buffer);
+    buffer.addByte(_CharCode.CR);
+    buffer.addByte(_CharCode.LF);
+    Uint8List headerBytes = buffer.takeBytes();
+    _outgoing.setHeader(headerBytes, headerBytes.length);
+  }
+}
+
+// Used by _HttpOutgoing as a target of a chunked converter for gzip
+// compression.
+class _HttpGZipSink extends ByteConversionSink {
+  final _BytesConsumer _consume;
+  _HttpGZipSink(this._consume);
+
+  void add(List<int> chunk) {
+    _consume(chunk);
+  }
+
+  void addSlice(List<int> chunk, int start, int end, bool isLast) {
+    if (chunk is Uint8List) {
+      _consume(new Uint8List.view(chunk.buffer, start, end - start));
+    } else {
+      _consume(chunk.sublist(start, end - start));
+    }
+  }
+
+  void close() {}
+}
+
+// The _HttpOutgoing handles all of the following:
+//  - Buffering
+//  - GZip compression
+//  - Content-Length validation.
+//  - Errors.
+//
+// Most notable is the GZip compression, that uses a double-buffering system,
+// one before gzip (_gzipBuffer) and one after (_buffer).
+class _HttpOutgoing implements StreamConsumer<List<int>> {
+  static const List<int> _footerAndChunk0Length = const [
+    _CharCode.CR,
+    _CharCode.LF,
+    0x30,
+    _CharCode.CR,
+    _CharCode.LF,
+    _CharCode.CR,
+    _CharCode.LF
+  ];
+
+  static const List<int> _chunk0Length = const [
+    0x30,
+    _CharCode.CR,
+    _CharCode.LF,
+    _CharCode.CR,
+    _CharCode.LF
+  ];
+
+  final Completer<Socket> _doneCompleter = new Completer<Socket>();
+  final Socket socket;
+
+  bool ignoreBody = false;
+  bool headersWritten = false;
+
+  Uint8List _buffer;
+  int _length = 0;
+
+  Future _closeFuture;
+
+  bool chunked = false;
+  int _pendingChunkedFooter = 0;
+
+  int contentLength;
+  int _bytesWritten = 0;
+
+  bool _gzip = false;
+  ByteConversionSink _gzipSink;
+  // _gzipAdd is set iff the sink is being added to. It's used to specify where
+  // gzipped data should be taken (sometimes a controller, sometimes a socket).
+  _BytesConsumer _gzipAdd;
+  Uint8List _gzipBuffer;
+  int _gzipBufferLength = 0;
+
+  bool _socketError = false;
+
+  _HttpOutboundMessage outbound;
+
+  _HttpOutgoing(this.socket);
+
+  // Returns either a future or 'null', if it was able to write headers
+  // immediately.
+  Future writeHeaders({bool drainRequest: true, bool setOutgoing: true}) {
+    if (headersWritten) return null;
+    headersWritten = true;
+    Future drainFuture;
+    bool gzip = false;
+    if (outbound is _HttpResponse) {
+      // Server side.
+      _HttpResponse response = outbound;
+      if (response._httpRequest._httpServer.autoCompress &&
+          outbound.bufferOutput &&
+          outbound.headers.chunkedTransferEncoding) {
+        List acceptEncodings =
+            response._httpRequest.headers[HttpHeaders.acceptEncodingHeader];
+        List contentEncoding =
+            outbound.headers[HttpHeaders.contentEncodingHeader];
+        if (acceptEncodings != null &&
+            acceptEncodings
+                .expand((list) => list.split(","))
+                .any((encoding) => encoding.trim().toLowerCase() == "gzip") &&
+            contentEncoding == null) {
+          outbound.headers.set(HttpHeaders.contentEncodingHeader, "gzip");
+          gzip = true;
+        }
+      }
+      if (drainRequest && !response._httpRequest._incoming.hasSubscriber) {
+        drainFuture = response._httpRequest.drain().catchError((_) {});
+      }
+    } else {
+      drainRequest = false;
+    }
+    if (!ignoreBody) {
+      if (setOutgoing) {
+        int contentLength = outbound.headers.contentLength;
+        if (outbound.headers.chunkedTransferEncoding) {
+          chunked = true;
+          if (gzip) this.gzip = true;
+        } else if (contentLength >= 0) {
+          this.contentLength = contentLength;
+        }
+      }
+      if (drainFuture != null) {
+        return drainFuture.then((_) => outbound._writeHeader());
+      }
+    }
+    outbound._writeHeader();
+    return null;
+  }
+
+  Future addStream(Stream<List<int>> stream) {
+    if (_socketError) {
+      stream.listen(null).cancel();
+      return new Future.value(outbound);
+    }
+    if (ignoreBody) {
+      stream.drain().catchError((_) {});
+      var future = writeHeaders();
+      if (future != null) {
+        return future.then((_) => close());
+      }
+      return close();
+    }
+    StreamSubscription<List<int>> sub;
+    // Use new stream so we are able to pause (see below listen). The
+    // alternative is to use stream.extand, but that won't give us a way of
+    // pausing.
+    var controller = new StreamController<List<int>>(
+        onPause: () => sub.pause(), onResume: () => sub.resume(), sync: true);
+
+    void onData(List<int> data) {
+      if (_socketError) return;
+      if (data.length == 0) return;
+      if (chunked) {
+        if (_gzip) {
+          _gzipAdd = controller.add;
+          _addGZipChunk(data, _gzipSink.add);
+          _gzipAdd = null;
+          return;
+        }
+        _addChunk(_chunkHeader(data.length), controller.add);
+        _pendingChunkedFooter = 2;
+      } else {
+        if (contentLength != null) {
+          _bytesWritten += data.length;
+          if (_bytesWritten > contentLength) {
+            controller.addError(new HttpException(
+                "Content size exceeds specified contentLength. "
+                "$_bytesWritten bytes written while expected "
+                "$contentLength. "
+                "[${new String.fromCharCodes(data)}]"));
+            return;
+          }
+        }
+      }
+      _addChunk(data, controller.add);
+    }
+
+    sub = stream.listen(onData,
+        onError: controller.addError,
+        onDone: controller.close,
+        cancelOnError: true);
+    // Write headers now that we are listening to the stream.
+    if (!headersWritten) {
+      var future = writeHeaders();
+      if (future != null) {
+        // While incoming is being drained, the pauseFuture is non-null. Pause
+        // output until it's drained.
+        sub.pause(future);
+      }
+    }
+    return socket.addStream(controller.stream).then((_) {
+      return outbound;
+    }, onError: (error, stackTrace) {
+      // Be sure to close it in case of an error.
+      if (_gzip) _gzipSink.close();
+      _socketError = true;
+      _doneCompleter.completeError(error, stackTrace);
+      if (_ignoreError(error)) {
+        return outbound;
+      } else {
+        throw error;
+      }
+    });
+  }
+
+  Future close() {
+    // If we are already closed, return that future.
+    if (_closeFuture != null) return _closeFuture;
+    // If we earlier saw an error, return immediate. The notification to
+    // _Http*Connection is already done.
+    if (_socketError) return new Future.value(outbound);
+    if (outbound._isConnectionClosed) return new Future.value(outbound);
+    if (!headersWritten && !ignoreBody) {
+      if (outbound.headers.contentLength == -1) {
+        // If no body was written, ignoreBody is false (it's not a HEAD
+        // request) and the content-length is unspecified, set contentLength to
+        // 0.
+        outbound.headers.chunkedTransferEncoding = false;
+        outbound.headers.contentLength = 0;
+      } else if (outbound.headers.contentLength > 0) {
+        var error = new HttpException(
+            "No content even though contentLength was specified to be "
+            "greater than 0: ${outbound.headers.contentLength}.",
+            uri: outbound._uri);
+        _doneCompleter.completeError(error);
+        return _closeFuture = new Future.error(error);
+      }
+    }
+    // If contentLength was specified, validate it.
+    if (contentLength != null) {
+      if (_bytesWritten < contentLength) {
+        var error = new HttpException(
+            "Content size below specified contentLength. "
+            " $_bytesWritten bytes written but expected "
+            "$contentLength.",
+            uri: outbound._uri);
+        _doneCompleter.completeError(error);
+        return _closeFuture = new Future.error(error);
+      }
+    }
+
+    Future finalize() {
+      // In case of chunked encoding (and gzip), handle remaining gzip data and
+      // append the 'footer' for chunked encoding.
+      if (chunked) {
+        if (_gzip) {
+          _gzipAdd = socket.add;
+          if (_gzipBufferLength > 0) {
+            _gzipSink.add(
+                new Uint8List.view(_gzipBuffer.buffer, 0, _gzipBufferLength));
+          }
+          _gzipBuffer = null;
+          _gzipSink.close();
+          _gzipAdd = null;
+        }
+        _addChunk(_chunkHeader(0), socket.add);
+      }
+      // Add any remaining data in the buffer.
+      if (_length > 0) {
+        socket.add(new Uint8List.view(_buffer.buffer, 0, _length));
+      }
+      // Clear references, for better GC.
+      _buffer = null;
+      // And finally flush it. As we support keep-alive, never close it from
+      // here. Once the socket is flushed, we'll be able to reuse it (signaled
+      // by the 'done' future).
+      return socket.flush().then((_) {
+        _doneCompleter.complete(socket);
+        return outbound;
+      }, onError: (error, stackTrace) {
+        _doneCompleter.completeError(error, stackTrace);
+        if (_ignoreError(error)) {
+          return outbound;
+        } else {
+          throw error;
+        }
+      });
+    }
+
+    var future = writeHeaders();
+    if (future != null) {
+      return _closeFuture = future.whenComplete(finalize);
+    }
+    return _closeFuture = finalize();
+  }
+
+  Future<Socket> get done => _doneCompleter.future;
+
+  void setHeader(List<int> data, int length) {
+    assert(_length == 0);
+    _buffer = data;
+    _length = length;
+  }
+
+  void set gzip(bool value) {
+    _gzip = value;
+    if (_gzip) {
+      _gzipBuffer = new Uint8List(_OUTGOING_BUFFER_SIZE);
+      assert(_gzipSink == null);
+      _gzipSink = new ZLibEncoder(gzip: true)
+          .startChunkedConversion(new _HttpGZipSink((data) {
+        // We are closing down prematurely, due to an error. Discard.
+        if (_gzipAdd == null) return;
+        _addChunk(_chunkHeader(data.length), _gzipAdd);
+        _pendingChunkedFooter = 2;
+        _addChunk(data, _gzipAdd);
+      }));
+    }
+  }
+
+  bool _ignoreError(error) =>
+      (error is SocketException || error is TlsException) &&
+      outbound is HttpResponse;
+
+  void _addGZipChunk(List<int> chunk, void add(List<int> data)) {
+    if (!outbound.bufferOutput) {
+      add(chunk);
+      return;
+    }
+    if (chunk.length > _gzipBuffer.length - _gzipBufferLength) {
+      add(new Uint8List.view(_gzipBuffer.buffer, 0, _gzipBufferLength));
+      _gzipBuffer = new Uint8List(_OUTGOING_BUFFER_SIZE);
+      _gzipBufferLength = 0;
+    }
+    if (chunk.length > _OUTGOING_BUFFER_SIZE) {
+      add(chunk);
+    } else {
+      _gzipBuffer.setRange(
+          _gzipBufferLength, _gzipBufferLength + chunk.length, chunk);
+      _gzipBufferLength += chunk.length;
+    }
+  }
+
+  void _addChunk(List<int> chunk, void add(List<int> data)) {
+    if (!outbound.bufferOutput) {
+      if (_buffer != null) {
+        // If _buffer is not null, we have not written the header yet. Write
+        // it now.
+        add(new Uint8List.view(_buffer.buffer, 0, _length));
+        _buffer = null;
+        _length = 0;
+      }
+      add(chunk);
+      return;
+    }
+    if (chunk.length > _buffer.length - _length) {
+      add(new Uint8List.view(_buffer.buffer, 0, _length));
+      _buffer = new Uint8List(_OUTGOING_BUFFER_SIZE);
+      _length = 0;
+    }
+    if (chunk.length > _OUTGOING_BUFFER_SIZE) {
+      add(chunk);
+    } else {
+      _buffer.setRange(_length, _length + chunk.length, chunk);
+      _length += chunk.length;
+    }
+  }
+
+  List<int> _chunkHeader(int length) {
+    const hexDigits = const [
+      0x30,
+      0x31,
+      0x32,
+      0x33,
+      0x34,
+      0x35,
+      0x36,
+      0x37,
+      0x38,
+      0x39,
+      0x41,
+      0x42,
+      0x43,
+      0x44,
+      0x45,
+      0x46
+    ];
+    if (length == 0) {
+      if (_pendingChunkedFooter == 2) return _footerAndChunk0Length;
+      return _chunk0Length;
+    }
+    int size = _pendingChunkedFooter;
+    int len = length;
+    // Compute a fast integer version of (log(length + 1) / log(16)).ceil().
+    while (len > 0) {
+      size++;
+      len >>= 4;
+    }
+    var footerAndHeader = new Uint8List(size + 2);
+    if (_pendingChunkedFooter == 2) {
+      footerAndHeader[0] = _CharCode.CR;
+      footerAndHeader[1] = _CharCode.LF;
+    }
+    int index = size;
+    while (index > _pendingChunkedFooter) {
+      footerAndHeader[--index] = hexDigits[length & 15];
+      length = length >> 4;
+    }
+    footerAndHeader[size + 0] = _CharCode.CR;
+    footerAndHeader[size + 1] = _CharCode.LF;
+    return footerAndHeader;
+  }
+}
+
+class _HttpClientConnection {
+  final String key;
+  final Socket _socket;
+  final bool _proxyTunnel;
+  final SecurityContext _context;
+  final _HttpParser _httpParser;
+  StreamSubscription _subscription;
+  final _HttpClient _httpClient;
+  bool _dispose = false;
+  Timer _idleTimer;
+  bool closed = false;
+  Uri _currentUri;
+
+  Completer<_HttpIncoming> _nextResponseCompleter;
+  Future<Socket> _streamFuture;
+
+  _HttpClientConnection(this.key, this._socket, this._httpClient,
+      [this._proxyTunnel = false, this._context])
+      : _httpParser = new _HttpParser.responseParser() {
+    _httpParser.listenToStream(_socket);
+
+    // Set up handlers on the parser here, so we are sure to get 'onDone' from
+    // the parser.
+    _subscription = _httpParser.listen((incoming) {
+      // Only handle one incoming response at the time. Keep the
+      // stream paused until the response have been processed.
+      _subscription.pause();
+      // We assume the response is not here, until we have send the request.
+      if (_nextResponseCompleter == null) {
+        throw new HttpException(
+            "Unexpected response (unsolicited response without request).",
+            uri: _currentUri);
+      }
+
+      // Check for status code '100 Continue'. In that case just
+      // consume that response as the final response will follow
+      // it. There is currently no API for the client to wait for
+      // the '100 Continue' response.
+      if (incoming.statusCode == 100) {
+        incoming.drain().then((_) {
+          _subscription.resume();
+        }).catchError((error, [StackTrace stackTrace]) {
+          _nextResponseCompleter.completeError(
+              new HttpException(error.message, uri: _currentUri), stackTrace);
+          _nextResponseCompleter = null;
+        });
+      } else {
+        _nextResponseCompleter.complete(incoming);
+        _nextResponseCompleter = null;
+      }
+    }, onError: (error, [StackTrace stackTrace]) {
+      if (_nextResponseCompleter != null) {
+        _nextResponseCompleter.completeError(
+            new HttpException(error.message, uri: _currentUri), stackTrace);
+        _nextResponseCompleter = null;
+      }
+    }, onDone: () {
+      if (_nextResponseCompleter != null) {
+        _nextResponseCompleter.completeError(new HttpException(
+            "Connection closed before response was received",
+            uri: _currentUri));
+        _nextResponseCompleter = null;
+      }
+      close();
+    });
+  }
+
+  _HttpClientRequest send(Uri uri, int port, String method, _Proxy proxy) {
+    if (closed) {
+      throw new HttpException("Socket closed before request was sent",
+          uri: uri);
+    }
+    _currentUri = uri;
+    // Start with pausing the parser.
+    _subscription.pause();
+    _ProxyCredentials proxyCreds; // Credentials used to authorize proxy.
+    _SiteCredentials creds; // Credentials used to authorize this request.
+    var outgoing = new _HttpOutgoing(_socket);
+    // Create new request object, wrapping the outgoing connection.
+    var request =
+        new _HttpClientRequest(outgoing, uri, method, proxy, _httpClient, this);
+    // For the Host header an IPv6 address must be enclosed in []'s.
+    var host = uri.host;
+    if (host.contains(':')) host = "[$host]";
+    request.headers
+      ..host = host
+      ..port = port
+      .._add(HttpHeaders.acceptEncodingHeader, "gzip");
+    if (_httpClient.userAgent != null) {
+      request.headers._add('user-agent', _httpClient.userAgent);
+    }
+    if (proxy.isAuthenticated) {
+      // If the proxy configuration contains user information use that
+      // for proxy basic authorization.
+      String auth = _CryptoUtils.bytesToBase64(
+          utf8.encode("${proxy.username}:${proxy.password}"));
+      request.headers.set(HttpHeaders.proxyAuthorizationHeader, "Basic $auth");
+    } else if (!proxy.isDirect && _httpClient._proxyCredentials.length > 0) {
+      proxyCreds = _httpClient._findProxyCredentials(proxy);
+      if (proxyCreds != null) {
+        proxyCreds.authorize(request);
+      }
+    }
+    if (uri.userInfo != null && !uri.userInfo.isEmpty) {
+      // If the URL contains user information use that for basic
+      // authorization.
+      String auth = _CryptoUtils.bytesToBase64(utf8.encode(uri.userInfo));
+      request.headers.set(HttpHeaders.authorizationHeader, "Basic $auth");
+    } else {
+      // Look for credentials.
+      creds = _httpClient._findCredentials(uri);
+      if (creds != null) {
+        creds.authorize(request);
+      }
+    }
+    // Start sending the request (lazy, delayed until the user provides
+    // data).
+    _httpParser.isHead = method == "HEAD";
+    _streamFuture = outgoing.done.then<Socket>((Socket s) {
+      // Request sent, set up response completer.
+      _nextResponseCompleter = new Completer<_HttpIncoming>();
+
+      // Listen for response.
+      _nextResponseCompleter.future.then((incoming) {
+        _currentUri = null;
+        incoming.dataDone.then((closing) {
+          if (incoming.upgraded) {
+            _httpClient._connectionClosed(this);
+            startTimer();
+            return;
+          }
+          if (closed) return;
+          if (!closing &&
+              !_dispose &&
+              incoming.headers.persistentConnection &&
+              request.persistentConnection) {
+            // Return connection, now we are done.
+            _httpClient._returnConnection(this);
+            _subscription.resume();
+          } else {
+            destroy();
+          }
+        });
+        // For digest authentication if proxy check if the proxy
+        // requests the client to start using a new nonce for proxy
+        // authentication.
+        if (proxyCreds != null &&
+            proxyCreds.scheme == _AuthenticationScheme.DIGEST) {
+          var authInfo = incoming.headers["proxy-authentication-info"];
+          if (authInfo != null && authInfo.length == 1) {
+            var header =
+                _HeaderValue.parse(authInfo[0], parameterSeparator: ',');
+            var nextnonce = header.parameters["nextnonce"];
+            if (nextnonce != null) proxyCreds.nonce = nextnonce;
+          }
+        }
+        // For digest authentication check if the server requests the
+        // client to start using a new nonce.
+        if (creds != null && creds.scheme == _AuthenticationScheme.DIGEST) {
+          var authInfo = incoming.headers["authentication-info"];
+          if (authInfo != null && authInfo.length == 1) {
+            var header =
+                _HeaderValue.parse(authInfo[0], parameterSeparator: ',');
+            var nextnonce = header.parameters["nextnonce"];
+            if (nextnonce != null) creds.nonce = nextnonce;
+          }
+        }
+        request._onIncoming(incoming);
+      })
+          // If we see a state error, we failed to get the 'first'
+          // element.
+          .catchError((error) {
+        throw new HttpException("Connection closed before data was received",
+            uri: uri);
+      }, test: (error) => error is StateError).catchError((error, stackTrace) {
+        // We are done with the socket.
+        destroy();
+        request._onError(error, stackTrace);
+      });
+
+      // Resume the parser now we have a handler.
+      _subscription.resume();
+      return s;
+    }, onError: (e) {
+      destroy();
+    });
+    return request;
+  }
+
+  Future<Socket> detachSocket() {
+    return _streamFuture.then(
+        (_) => new _DetachedSocket(_socket, _httpParser.detachIncoming()));
+  }
+
+  void destroy() {
+    closed = true;
+    _httpClient._connectionClosed(this);
+    _socket.destroy();
+  }
+
+  void close() {
+    closed = true;
+    _httpClient._connectionClosed(this);
+    _streamFuture
+        .timeout(_httpClient.idleTimeout)
+        .then((_) => _socket.destroy());
+  }
+
+  Future<_HttpClientConnection> createProxyTunnel(String host, int port,
+      _Proxy proxy, bool callback(X509Certificate certificate)) {
+    _HttpClientRequest request =
+        send(new Uri(host: host, port: port), port, "CONNECT", proxy);
+    if (proxy.isAuthenticated) {
+      // If the proxy configuration contains user information use that
+      // for proxy basic authorization.
+      String auth = _CryptoUtils.bytesToBase64(
+          utf8.encode("${proxy.username}:${proxy.password}"));
+      request.headers.set(HttpHeaders.proxyAuthorizationHeader, "Basic $auth");
+    }
+    return request.close().then((response) {
+      if (response.statusCode != HttpStatus.ok) {
+        throw new HttpException(
+            "Proxy failed to establish tunnel "
+            "(${response.statusCode} ${response.reasonPhrase})",
+            uri: request.uri);
+      }
+      var socket = (response as _HttpClientResponse)
+          ._httpRequest
+          ._httpClientConnection
+          ._socket;
+      return SecureSocket.secure(socket,
+          host: host, context: _context, onBadCertificate: callback);
+    }).then((secureSocket) {
+      String key = _HttpClientConnection.makeKey(true, host, port);
+      return new _HttpClientConnection(
+          key, secureSocket, request._httpClient, true);
+    });
+  }
+
+  HttpConnectionInfo get connectionInfo => _HttpConnectionInfo.create(_socket);
+
+  static makeKey(bool isSecure, String host, int port) {
+    return isSecure ? "ssh:$host:$port" : "$host:$port";
+  }
+
+  void stopTimer() {
+    if (_idleTimer != null) {
+      _idleTimer.cancel();
+      _idleTimer = null;
+    }
+  }
+
+  void startTimer() {
+    assert(_idleTimer == null);
+    _idleTimer = new Timer(_httpClient.idleTimeout, () {
+      _idleTimer = null;
+      close();
+    });
+  }
+}
+
+class _ConnectionInfo {
+  final _HttpClientConnection connection;
+  final _Proxy proxy;
+
+  _ConnectionInfo(this.connection, this.proxy);
+}
+
+class _ConnectionTarget {
+  // Unique key for this connection target.
+  final String key;
+  final String host;
+  final int port;
+  final bool isSecure;
+  final SecurityContext context;
+  final Set<_HttpClientConnection> _idle = new HashSet();
+  final Set<_HttpClientConnection> _active = new HashSet();
+  final Set<ConnectionTask> _socketTasks = new HashSet();
+  final Queue _pending = new ListQueue();
+  int _connecting = 0;
+
+  _ConnectionTarget(
+      this.key, this.host, this.port, this.isSecure, this.context);
+
+  bool get isEmpty => _idle.isEmpty && _active.isEmpty && _connecting == 0;
+
+  bool get hasIdle => _idle.isNotEmpty;
+
+  bool get hasActive => _active.isNotEmpty || _connecting > 0;
+
+  _HttpClientConnection takeIdle() {
+    assert(hasIdle);
+    _HttpClientConnection connection = _idle.first;
+    _idle.remove(connection);
+    connection.stopTimer();
+    _active.add(connection);
+    return connection;
+  }
+
+  _checkPending() {
+    if (_pending.isNotEmpty) {
+      _pending.removeFirst()();
+    }
+  }
+
+  void addNewActive(_HttpClientConnection connection) {
+    _active.add(connection);
+  }
+
+  void returnConnection(_HttpClientConnection connection) {
+    assert(_active.contains(connection));
+    _active.remove(connection);
+    _idle.add(connection);
+    connection.startTimer();
+    _checkPending();
+  }
+
+  void connectionClosed(_HttpClientConnection connection) {
+    assert(!_active.contains(connection) || !_idle.contains(connection));
+    _active.remove(connection);
+    _idle.remove(connection);
+    _checkPending();
+  }
+
+  void close(bool force) {
+    // Always cancel pending socket connections.
+    for (var t in _socketTasks.toList()) {
+      // Make sure the socket is destroyed if the ConnectionTask is cancelled.
+      t.socket.then((s) {
+        s.destroy();
+      }, onError: (e) {});
+      t.cancel();
+    }
+    if (force) {
+      for (var c in _idle.toList()) {
+        c.destroy();
+      }
+      for (var c in _active.toList()) {
+        c.destroy();
+      }
+    } else {
+      for (var c in _idle.toList()) {
+        c.close();
+      }
+    }
+  }
+
+  Future<_ConnectionInfo> connect(
+      String uriHost, int uriPort, _Proxy proxy, _HttpClient client) {
+    if (hasIdle) {
+      var connection = takeIdle();
+      client._connectionsChanged();
+      return new Future.value(new _ConnectionInfo(connection, proxy));
+    }
+    if (client.maxConnectionsPerHost != null &&
+        _active.length + _connecting >= client.maxConnectionsPerHost) {
+      var completer = new Completer<_ConnectionInfo>();
+      _pending.add(() {
+        completer.complete(connect(uriHost, uriPort, proxy, client));
+      });
+      return completer.future;
+    }
+    var currentBadCertificateCallback = client._badCertificateCallback;
+
+    bool callback(X509Certificate certificate) {
+      if (currentBadCertificateCallback == null) return false;
+      return currentBadCertificateCallback(certificate, uriHost, uriPort);
+    }
+
+    Future<ConnectionTask> connectionTask = (isSecure && proxy.isDirect
+        ? SecureSocket.startConnect(host, port,
+            context: context, onBadCertificate: callback)
+        : Socket.startConnect(host, port));
+    _connecting++;
+    return connectionTask.then((ConnectionTask task) {
+      _socketTasks.add(task);
+      Future socketFuture = task.socket;
+      final Duration connectionTimeout = client.connectionTimeout;
+      if (connectionTimeout != null) {
+        socketFuture = socketFuture.timeout(connectionTimeout, onTimeout: () {
+          _socketTasks.remove(task);
+          task.cancel();
+          return null;
+        });
+      }
+      return socketFuture.then((socket) {
+        // When there is a timeout, there is a race in which the connectionTask
+        // Future won't be completed with an error before the socketFuture here
+        // is completed with 'null' by the onTimeout callback above. In this
+        // case, propagate a SocketException as specified by the
+        // HttpClient.connectionTimeout docs.
+        if (socket == null) {
+          assert(connectionTimeout != null);
+          throw new SocketException(
+              "HTTP connection timed out after ${connectionTimeout}, "
+              "host: ${host}, port: ${port}");
+        }
+        _connecting--;
+        socket.setOption(SocketOption.tcpNoDelay, true);
+        var connection =
+            new _HttpClientConnection(key, socket, client, false, context);
+        if (isSecure && !proxy.isDirect) {
+          connection._dispose = true;
+          return connection
+              .createProxyTunnel(uriHost, uriPort, proxy, callback)
+              .then((tunnel) {
+            client
+                ._getConnectionTarget(uriHost, uriPort, true)
+                .addNewActive(tunnel);
+            _socketTasks.remove(task);
+            return new _ConnectionInfo(tunnel, proxy);
+          });
+        } else {
+          addNewActive(connection);
+          _socketTasks.remove(task);
+          return new _ConnectionInfo(connection, proxy);
+        }
+      }, onError: (error) {
+        _connecting--;
+        _socketTasks.remove(task);
+        _checkPending();
+        throw error;
+      });
+    });
+  }
+}
+
+typedef bool BadCertificateCallback(X509Certificate cr, String host, int port);
+
+class _HttpClient implements HttpClient {
+  bool _closing = false;
+  bool _closingForcefully = false;
+  final Map<String, _ConnectionTarget> _connectionTargets =
+      new HashMap<String, _ConnectionTarget>();
+  final List<_Credentials> _credentials = [];
+  final List<_ProxyCredentials> _proxyCredentials = [];
+  final SecurityContext _context;
+  Function _authenticate;
+  Function _authenticateProxy;
+  Function _findProxy = HttpClient.findProxyFromEnvironment;
+  Duration _idleTimeout = const Duration(seconds: 15);
+  BadCertificateCallback _badCertificateCallback;
+
+  Duration get idleTimeout => _idleTimeout;
+
+  Duration connectionTimeout;
+
+  int maxConnectionsPerHost;
+
+  bool autoUncompress = true;
+
+  String userAgent = _getHttpVersion();
+
+  _HttpClient(this._context);
+
+  void set idleTimeout(Duration timeout) {
+    _idleTimeout = timeout;
+    for (var c in _connectionTargets.values) {
+      for (var idle in c._idle) {
+        // Reset timer. This is fine, as it's not happening often.
+        idle.stopTimer();
+        idle.startTimer();
+      }
+    }
+  }
+
+  set badCertificateCallback(
+      bool callback(X509Certificate cert, String host, int port)) {
+    _badCertificateCallback = callback;
+  }
+
+  Future<HttpClientRequest> open(
+      String method, String host, int port, String path) {
+    const int hashMark = 0x23;
+    const int questionMark = 0x3f;
+    int fragmentStart = path.length;
+    int queryStart = path.length;
+    for (int i = path.length - 1; i >= 0; i--) {
+      var char = path.codeUnitAt(i);
+      if (char == hashMark) {
+        fragmentStart = i;
+        queryStart = i;
+      } else if (char == questionMark) {
+        queryStart = i;
+      }
+    }
+    String query = null;
+    if (queryStart < fragmentStart) {
+      query = path.substring(queryStart + 1, fragmentStart);
+      path = path.substring(0, queryStart);
+    }
+    Uri uri = new Uri(
+        scheme: "http", host: host, port: port, path: path, query: query);
+    return _openUrl(method, uri);
+  }
+
+  Future<HttpClientRequest> openUrl(String method, Uri url) =>
+      _openUrl(method, url);
+
+  Future<HttpClientRequest> get(String host, int port, String path) =>
+      open("get", host, port, path);
+
+  Future<HttpClientRequest> getUrl(Uri url) => _openUrl("get", url);
+
+  Future<HttpClientRequest> post(String host, int port, String path) =>
+      open("post", host, port, path);
+
+  Future<HttpClientRequest> postUrl(Uri url) => _openUrl("post", url);
+
+  Future<HttpClientRequest> put(String host, int port, String path) =>
+      open("put", host, port, path);
+
+  Future<HttpClientRequest> putUrl(Uri url) => _openUrl("put", url);
+
+  Future<HttpClientRequest> delete(String host, int port, String path) =>
+      open("delete", host, port, path);
+
+  Future<HttpClientRequest> deleteUrl(Uri url) => _openUrl("delete", url);
+
+  Future<HttpClientRequest> head(String host, int port, String path) =>
+      open("head", host, port, path);
+
+  Future<HttpClientRequest> headUrl(Uri url) => _openUrl("head", url);
+
+  Future<HttpClientRequest> patch(String host, int port, String path) =>
+      open("patch", host, port, path);
+
+  Future<HttpClientRequest> patchUrl(Uri url) => _openUrl("patch", url);
+
+  void close({bool force: false}) {
+    _closing = true;
+    _closingForcefully = force;
+    _closeConnections(_closingForcefully);
+    assert(!_connectionTargets.values.any((s) => s.hasIdle));
+    assert(
+        !force || !_connectionTargets.values.any((s) => s._active.isNotEmpty));
+  }
+
+  set authenticate(Future<bool> f(Uri url, String scheme, String realm)) {
+    _authenticate = f;
+  }
+
+  void addCredentials(Uri url, String realm, HttpClientCredentials cr) {
+    _credentials.add(new _SiteCredentials(url, realm, cr));
+  }
+
+  set authenticateProxy(
+      Future<bool> f(String host, int port, String scheme, String realm)) {
+    _authenticateProxy = f;
+  }
+
+  void addProxyCredentials(
+      String host, int port, String realm, HttpClientCredentials cr) {
+    _proxyCredentials.add(new _ProxyCredentials(host, port, realm, cr));
+  }
+
+  set findProxy(String f(Uri uri)) => _findProxy = f;
+
+  Future<_HttpClientRequest> _openUrl(String method, Uri uri) {
+    if (_closing) {
+      throw new StateError("Client is closed");
+    }
+
+    // Ignore any fragments on the request URI.
+    uri = uri.removeFragment();
+
+    if (method == null) {
+      throw new ArgumentError(method);
+    }
+    if (method != "CONNECT") {
+      if (uri.host.isEmpty) {
+        throw new ArgumentError("No host specified in URI $uri");
+      } else if (uri.scheme != "http" && uri.scheme != "https") {
+        throw new ArgumentError(
+            "Unsupported scheme '${uri.scheme}' in URI $uri");
+      }
+    }
+
+    bool isSecure = (uri.scheme == "https");
+    int port = uri.port;
+    if (port == 0) {
+      port =
+          isSecure ? HttpClient.defaultHttpsPort : HttpClient.defaultHttpPort;
+    }
+    // Check to see if a proxy server should be used for this connection.
+    var proxyConf = const _ProxyConfiguration.direct();
+    if (_findProxy != null) {
+      // TODO(sgjesse): Keep a map of these as normally only a few
+      // configuration strings will be used.
+      try {
+        proxyConf = new _ProxyConfiguration(_findProxy(uri));
+      } catch (error, stackTrace) {
+        return new Future.error(error, stackTrace);
+      }
+    }
+    return _getConnection(uri.host, port, proxyConf, isSecure)
+        .then((_ConnectionInfo info) {
+      _HttpClientRequest send(_ConnectionInfo info) {
+        return info.connection
+            .send(uri, port, method.toUpperCase(), info.proxy);
+      }
+
+      // If the connection was closed before the request was sent, create
+      // and use another connection.
+      if (info.connection.closed) {
+        return _getConnection(uri.host, port, proxyConf, isSecure).then(send);
+      }
+      return send(info);
+    });
+  }
+
+  Future<_HttpClientRequest> _openUrlFromRequest(
+      String method, Uri uri, _HttpClientRequest previous) {
+    // If the new URI is relative (to either '/' or some sub-path),
+    // construct a full URI from the previous one.
+    Uri resolved = previous.uri.resolveUri(uri);
+    return _openUrl(method, resolved).then((_HttpClientRequest request) {
+      request
+        // Only follow redirects if initial request did.
+        ..followRedirects = previous.followRedirects
+        // Allow same number of redirects.
+        ..maxRedirects = previous.maxRedirects;
+      // Copy headers.
+      for (var header in previous.headers._headers.keys) {
+        if (request.headers[header] == null) {
+          request.headers.set(header, previous.headers[header]);
+        }
+      }
+      return request
+        ..headers.chunkedTransferEncoding = false
+        ..contentLength = 0;
+    });
+  }
+
+  // Return a live connection to the idle pool.
+  void _returnConnection(_HttpClientConnection connection) {
+    _connectionTargets[connection.key].returnConnection(connection);
+    _connectionsChanged();
+  }
+
+  // Remove a closed connection from the active set.
+  void _connectionClosed(_HttpClientConnection connection) {
+    connection.stopTimer();
+    var connectionTarget = _connectionTargets[connection.key];
+    if (connectionTarget != null) {
+      connectionTarget.connectionClosed(connection);
+      if (connectionTarget.isEmpty) {
+        _connectionTargets.remove(connection.key);
+      }
+      _connectionsChanged();
+    }
+  }
+
+  void _connectionsChanged() {
+    if (_closing) {
+      _closeConnections(_closingForcefully);
+    }
+  }
+
+  void _closeConnections(bool force) {
+    for (var connectionTarget in _connectionTargets.values.toList()) {
+      connectionTarget.close(force);
+    }
+  }
+
+  _ConnectionTarget _getConnectionTarget(String host, int port, bool isSecure) {
+    String key = _HttpClientConnection.makeKey(isSecure, host, port);
+    return _connectionTargets.putIfAbsent(key, () {
+      return new _ConnectionTarget(key, host, port, isSecure, _context);
+    });
+  }
+
+  // Get a new _HttpClientConnection, from the matching _ConnectionTarget.
+  Future<_ConnectionInfo> _getConnection(String uriHost, int uriPort,
+      _ProxyConfiguration proxyConf, bool isSecure) {
+    Iterator<_Proxy> proxies = proxyConf.proxies.iterator;
+
+    Future<_ConnectionInfo> connect(error) {
+      if (!proxies.moveNext()) return new Future.error(error);
+      _Proxy proxy = proxies.current;
+      String host = proxy.isDirect ? uriHost : proxy.host;
+      int port = proxy.isDirect ? uriPort : proxy.port;
+      return _getConnectionTarget(host, port, isSecure)
+          .connect(uriHost, uriPort, proxy, this)
+          // On error, continue with next proxy.
+          .catchError(connect);
+    }
+
+    return connect(new HttpException("No proxies given"));
+  }
+
+  _SiteCredentials _findCredentials(Uri url, [_AuthenticationScheme scheme]) {
+    // Look for credentials.
+    _SiteCredentials cr =
+        _credentials.fold(null, (_SiteCredentials prev, value) {
+      var siteCredentials = value as _SiteCredentials;
+      if (siteCredentials.applies(url, scheme)) {
+        if (prev == null) return value;
+        return siteCredentials.uri.path.length > prev.uri.path.length
+            ? siteCredentials
+            : prev;
+      } else {
+        return prev;
+      }
+    });
+    return cr;
+  }
+
+  _ProxyCredentials _findProxyCredentials(_Proxy proxy,
+      [_AuthenticationScheme scheme]) {
+    // Look for credentials.
+    var it = _proxyCredentials.iterator;
+    while (it.moveNext()) {
+      if (it.current.applies(proxy, scheme)) {
+        return it.current;
+      }
+    }
+    return null;
+  }
+
+  void _removeCredentials(_Credentials cr) {
+    int index = _credentials.indexOf(cr);
+    if (index != -1) {
+      _credentials.removeAt(index);
+    }
+  }
+
+  void _removeProxyCredentials(_Credentials cr) {
+    int index = _proxyCredentials.indexOf(cr);
+    if (index != -1) {
+      _proxyCredentials.removeAt(index);
+    }
+  }
+
+  static String _findProxyFromEnvironment(
+      Uri url, Map<String, String> environment) {
+    checkNoProxy(String option) {
+      if (option == null) return null;
+      Iterator<String> names = option.split(",").map((s) => s.trim()).iterator;
+      while (names.moveNext()) {
+        var name = names.current;
+        if ((name.startsWith("[") &&
+                name.endsWith("]") &&
+                "[${url.host}]" == name) ||
+            (name.isNotEmpty && url.host.endsWith(name))) {
+          return "DIRECT";
+        }
+      }
+      return null;
+    }
+
+    checkProxy(String option) {
+      if (option == null) return null;
+      option = option.trim();
+      if (option.isEmpty) return null;
+      int pos = option.indexOf("://");
+      if (pos >= 0) {
+        option = option.substring(pos + 3);
+      }
+      pos = option.indexOf("/");
+      if (pos >= 0) {
+        option = option.substring(0, pos);
+      }
+      // Add default port if no port configured.
+      if (option.indexOf("[") == 0) {
+        var pos = option.lastIndexOf(":");
+        if (option.indexOf("]") > pos) option = "$option:1080";
+      } else {
+        if (option.indexOf(":") == -1) option = "$option:1080";
+      }
+      return "PROXY $option";
+    }
+
+    // Default to using the process current environment.
+    if (environment == null) environment = _platformEnvironmentCache;
+
+    String proxyCfg;
+
+    String noProxy = environment["no_proxy"];
+    if (noProxy == null) noProxy = environment["NO_PROXY"];
+    if ((proxyCfg = checkNoProxy(noProxy)) != null) {
+      return proxyCfg;
+    }
+
+    if (url.scheme == "http") {
+      String proxy = environment["http_proxy"];
+      if (proxy == null) proxy = environment["HTTP_PROXY"];
+      if ((proxyCfg = checkProxy(proxy)) != null) {
+        return proxyCfg;
+      }
+    } else if (url.scheme == "https") {
+      String proxy = environment["https_proxy"];
+      if (proxy == null) proxy = environment["HTTPS_PROXY"];
+      if ((proxyCfg = checkProxy(proxy)) != null) {
+        return proxyCfg;
+      }
+    }
+    return "DIRECT";
+  }
+
+  static Map<String, String> _platformEnvironmentCache = Platform.environment;
+}
+
+class _HttpConnection extends LinkedListEntry<_HttpConnection>
+    with _ServiceObject {
+  static const _ACTIVE = 0;
+  static const _IDLE = 1;
+  static const _CLOSING = 2;
+  static const _DETACHED = 3;
+
+  // Use HashMap, as we don't need to keep order.
+  static Map<int, _HttpConnection> _connections =
+      new HashMap<int, _HttpConnection>();
+
+  final /*_ServerSocket*/ _socket;
+  final _HttpServer _httpServer;
+  final _HttpParser _httpParser;
+  int _state = _IDLE;
+  StreamSubscription _subscription;
+  bool _idleMark = false;
+  Future _streamFuture;
+
+  _HttpConnection(this._socket, this._httpServer)
+      : _httpParser = new _HttpParser.requestParser() {
+    _connections[_serviceId] = this;
+    _httpParser.listenToStream(_socket);
+    _subscription = _httpParser.listen((incoming) {
+      _httpServer._markActive(this);
+      // If the incoming was closed, close the connection.
+      incoming.dataDone.then((closing) {
+        if (closing) destroy();
+      });
+      // Only handle one incoming request at the time. Keep the
+      // stream paused until the request has been send.
+      _subscription.pause();
+      _state = _ACTIVE;
+      var outgoing = new _HttpOutgoing(_socket);
+      var response = new _HttpResponse(
+          incoming.uri,
+          incoming.headers.protocolVersion,
+          outgoing,
+          _httpServer.defaultResponseHeaders,
+          _httpServer.serverHeader);
+      var request = new _HttpRequest(response, incoming, _httpServer, this);
+      _streamFuture = outgoing.done.then((_) {
+        response.deadline = null;
+        if (_state == _DETACHED) return;
+        if (response.persistentConnection &&
+            request.persistentConnection &&
+            incoming.fullBodyRead &&
+            !_httpParser.upgrade &&
+            !_httpServer.closed) {
+          _state = _IDLE;
+          _idleMark = false;
+          _httpServer._markIdle(this);
+          // Resume the subscription for incoming requests as the
+          // request is now processed.
+          _subscription.resume();
+        } else {
+          // Close socket, keep-alive not used or body sent before
+          // received data was handled.
+          destroy();
+        }
+      }, onError: (_) {
+        destroy();
+      });
+      outgoing.ignoreBody = request.method == "HEAD";
+      response._httpRequest = request;
+      _httpServer._handleRequest(request);
+    }, onDone: () {
+      destroy();
+    }, onError: (error) {
+      // Ignore failed requests that was closed before headers was received.
+      destroy();
+    });
+  }
+
+  void markIdle() {
+    _idleMark = true;
+  }
+
+  bool get isMarkedIdle => _idleMark;
+
+  void destroy() {
+    if (_state == _CLOSING || _state == _DETACHED) return;
+    _state = _CLOSING;
+    _socket.destroy();
+    _httpServer._connectionClosed(this);
+    _connections.remove(_serviceId);
+  }
+
+  Future<Socket> detachSocket() {
+    _state = _DETACHED;
+    // Remove connection from server.
+    _httpServer._connectionClosed(this);
+
+    _HttpDetachedIncoming detachedIncoming = _httpParser.detachIncoming();
+
+    return _streamFuture.then((_) {
+      _connections.remove(_serviceId);
+      return new _DetachedSocket(_socket, detachedIncoming);
+    });
+  }
+
+  HttpConnectionInfo get connectionInfo => _HttpConnectionInfo.create(_socket);
+
+  bool get _isActive => _state == _ACTIVE;
+  bool get _isIdle => _state == _IDLE;
+  bool get _isClosing => _state == _CLOSING;
+  bool get _isDetached => _state == _DETACHED;
+
+  String get _serviceTypePath => 'io/http/serverconnections';
+  String get _serviceTypeName => 'HttpServerConnection';
+
+  Map _toJSON(bool ref) {
+    var name = "${_socket.address.host}:${_socket.port} <-> "
+        "${_socket.remoteAddress.host}:${_socket.remotePort}";
+    var r = <String, dynamic>{
+      'id': _servicePath,
+      'type': _serviceType(ref),
+      'name': name,
+      'user_name': name,
+    };
+    if (ref) {
+      return r;
+    }
+    r['server'] = _httpServer._toJSON(true);
+    try {
+      r['socket'] = _socket._toJSON(true);
+    } catch (_) {
+      r['socket'] = {
+        'id': _servicePath,
+        'type': '@Socket',
+        'name': 'UserSocket',
+        'user_name': 'UserSocket',
+      };
+    }
+    switch (_state) {
+      case _ACTIVE:
+        r['state'] = "Active";
+        break;
+      case _IDLE:
+        r['state'] = "Idle";
+        break;
+      case _CLOSING:
+        r['state'] = "Closing";
+        break;
+      case _DETACHED:
+        r['state'] = "Detached";
+        break;
+      default:
+        r['state'] = 'Unknown';
+        break;
+    }
+    return r;
+  }
+}
+
+// HTTP server waiting for socket connections.
+class _HttpServer extends Stream<HttpRequest>
+    with _ServiceObject
+    implements HttpServer {
+  // Use default Map so we keep order.
+  static Map<int, _HttpServer> _servers = new Map<int, _HttpServer>();
+
+  String serverHeader;
+  final HttpHeaders defaultResponseHeaders = _initDefaultResponseHeaders();
+  bool autoCompress = false;
+
+  Duration _idleTimeout;
+  Timer _idleTimer;
+
+  static Future<HttpServer> bind(
+      address, int port, int backlog, bool v6Only, bool shared) {
+    return ServerSocket.bind(address, port,
+            backlog: backlog, v6Only: v6Only, shared: shared)
+        .then<HttpServer>((socket) {
+      return new _HttpServer._(socket, true);
+    });
+  }
+
+  static Future<HttpServer> bindSecure(
+      address,
+      int port,
+      SecurityContext context,
+      int backlog,
+      bool v6Only,
+      bool requestClientCertificate,
+      bool shared) {
+    return SecureServerSocket.bind(address, port, context,
+            backlog: backlog,
+            v6Only: v6Only,
+            requestClientCertificate: requestClientCertificate,
+            shared: shared)
+        .then<HttpServer>((socket) {
+      return new _HttpServer._(socket, true);
+    });
+  }
+
+  _HttpServer._(this._serverSocket, this._closeServer) {
+    _controller =
+        new StreamController<HttpRequest>(sync: true, onCancel: close);
+    idleTimeout = const Duration(seconds: 120);
+    _servers[_serviceId] = this;
+  }
+
+  _HttpServer.listenOn(this._serverSocket) : _closeServer = false {
+    _controller =
+        new StreamController<HttpRequest>(sync: true, onCancel: close);
+    idleTimeout = const Duration(seconds: 120);
+    _servers[_serviceId] = this;
+  }
+
+  static HttpHeaders _initDefaultResponseHeaders() {
+    var defaultResponseHeaders = new _HttpHeaders('1.1');
+    defaultResponseHeaders.contentType = ContentType.text;
+    defaultResponseHeaders.set('X-Frame-Options', 'SAMEORIGIN');
+    defaultResponseHeaders.set('X-Content-Type-Options', 'nosniff');
+    defaultResponseHeaders.set('X-XSS-Protection', '1; mode=block');
+    return defaultResponseHeaders;
+  }
+
+  Duration get idleTimeout => _idleTimeout;
+
+  void set idleTimeout(Duration duration) {
+    if (_idleTimer != null) {
+      _idleTimer.cancel();
+      _idleTimer = null;
+    }
+    _idleTimeout = duration;
+    if (_idleTimeout != null) {
+      _idleTimer = new Timer.periodic(_idleTimeout, (_) {
+        for (var idle in _idleConnections.toList()) {
+          if (idle.isMarkedIdle) {
+            idle.destroy();
+          } else {
+            idle.markIdle();
+          }
+        }
+      });
+    }
+  }
+
+  StreamSubscription<HttpRequest> listen(void onData(HttpRequest event),
+      {Function onError, void onDone(), bool cancelOnError}) {
+    _serverSocket.listen((Socket socket) {
+      socket.setOption(SocketOption.tcpNoDelay, true);
+      // Accept the client connection.
+      _HttpConnection connection = new _HttpConnection(socket, this);
+      _idleConnections.add(connection);
+    }, onError: (error, stackTrace) {
+      // Ignore HandshakeExceptions as they are bound to a single request,
+      // and are not fatal for the server.
+      if (error is! HandshakeException) {
+        _controller.addError(error, stackTrace);
+      }
+    }, onDone: _controller.close);
+    return _controller.stream.listen(onData,
+        onError: onError, onDone: onDone, cancelOnError: cancelOnError);
+  }
+
+  Future close({bool force: false}) {
+    closed = true;
+    Future result;
+    if (_serverSocket != null && _closeServer) {
+      result = _serverSocket.close();
+    } else {
+      result = new Future.value();
+    }
+    idleTimeout = null;
+    if (force) {
+      for (var c in _activeConnections.toList()) {
+        c.destroy();
+      }
+      assert(_activeConnections.isEmpty);
+    }
+    for (var c in _idleConnections.toList()) {
+      c.destroy();
+    }
+    _maybePerformCleanup();
+    return result;
+  }
+
+  void _maybePerformCleanup() {
+    if (closed &&
+        _idleConnections.isEmpty &&
+        _activeConnections.isEmpty &&
+        _sessionManagerInstance != null) {
+      _sessionManagerInstance.close();
+      _sessionManagerInstance = null;
+      _servers.remove(_serviceId);
+    }
+  }
+
+  int get port {
+    if (closed) throw new HttpException("HttpServer is not bound to a socket");
+    return _serverSocket.port;
+  }
+
+  InternetAddress get address {
+    if (closed) throw new HttpException("HttpServer is not bound to a socket");
+    return _serverSocket.address;
+  }
+
+  set sessionTimeout(int timeout) {
+    _sessionManager.sessionTimeout = timeout;
+  }
+
+  void _handleRequest(_HttpRequest request) {
+    if (!closed) {
+      _controller.add(request);
+    } else {
+      request._httpConnection.destroy();
+    }
+  }
+
+  void _connectionClosed(_HttpConnection connection) {
+    // Remove itself from either idle or active connections.
+    connection.unlink();
+    _maybePerformCleanup();
+  }
+
+  void _markIdle(_HttpConnection connection) {
+    _activeConnections.remove(connection);
+    _idleConnections.add(connection);
+  }
+
+  void _markActive(_HttpConnection connection) {
+    _idleConnections.remove(connection);
+    _activeConnections.add(connection);
+  }
+
+  _HttpSessionManager get _sessionManager {
+    // Lazy init.
+    if (_sessionManagerInstance == null) {
+      _sessionManagerInstance = new _HttpSessionManager();
+    }
+    return _sessionManagerInstance;
+  }
+
+  HttpConnectionsInfo connectionsInfo() {
+    HttpConnectionsInfo result = new HttpConnectionsInfo();
+    result.total = _activeConnections.length + _idleConnections.length;
+    _activeConnections.forEach((_HttpConnection conn) {
+      if (conn._isActive) {
+        result.active++;
+      } else {
+        assert(conn._isClosing);
+        result.closing++;
+      }
+    });
+    _idleConnections.forEach((_HttpConnection conn) {
+      result.idle++;
+      assert(conn._isIdle);
+    });
+    return result;
+  }
+
+  String get _serviceTypePath => 'io/http/servers';
+  String get _serviceTypeName => 'HttpServer';
+
+  Map<String, dynamic> _toJSON(bool ref) {
+    var r = <String, dynamic>{
+      'id': _servicePath,
+      'type': _serviceType(ref),
+      'name': '${address.host}:$port',
+      'user_name': '${address.host}:$port',
+    };
+    if (ref) {
+      return r;
+    }
+    try {
+      r['socket'] = _serverSocket._toJSON(true);
+    } catch (_) {
+      r['socket'] = {
+        'id': _servicePath,
+        'type': '@Socket',
+        'name': 'UserSocket',
+        'user_name': 'UserSocket',
+      };
+    }
+    r['port'] = port;
+    r['address'] = address.host;
+    r['active'] = _activeConnections.map((c) => c._toJSON(true)).toList();
+    r['idle'] = _idleConnections.map((c) => c._toJSON(true)).toList();
+    r['closed'] = closed;
+    return r;
+  }
+
+  _HttpSessionManager _sessionManagerInstance;
+
+  // Indicated if the http server has been closed.
+  bool closed = false;
+
+  // The server listen socket. Untyped as it can be both ServerSocket and
+  // SecureServerSocket.
+  final dynamic /*ServerSocket|SecureServerSocket*/ _serverSocket;
+  final bool _closeServer;
+
+  // Set of currently connected clients.
+  final LinkedList<_HttpConnection> _activeConnections =
+      new LinkedList<_HttpConnection>();
+  final LinkedList<_HttpConnection> _idleConnections =
+      new LinkedList<_HttpConnection>();
+  StreamController<HttpRequest> _controller;
+}
+
+class _ProxyConfiguration {
+  static const String PROXY_PREFIX = "PROXY ";
+  static const String DIRECT_PREFIX = "DIRECT";
+
+  _ProxyConfiguration(String configuration) : proxies = new List<_Proxy>() {
+    if (configuration == null) {
+      throw new HttpException("Invalid proxy configuration $configuration");
+    }
+    List<String> list = configuration.split(";");
+    list.forEach((String proxy) {
+      proxy = proxy.trim();
+      if (!proxy.isEmpty) {
+        if (proxy.startsWith(PROXY_PREFIX)) {
+          String username;
+          String password;
+          // Skip the "PROXY " prefix.
+          proxy = proxy.substring(PROXY_PREFIX.length).trim();
+          // Look for proxy authentication.
+          int at = proxy.indexOf("@");
+          if (at != -1) {
+            String userinfo = proxy.substring(0, at).trim();
+            proxy = proxy.substring(at + 1).trim();
+            int colon = userinfo.indexOf(":");
+            if (colon == -1 || colon == 0 || colon == proxy.length - 1) {
+              throw new HttpException(
+                  "Invalid proxy configuration $configuration");
+            }
+            username = userinfo.substring(0, colon).trim();
+            password = userinfo.substring(colon + 1).trim();
+          }
+          // Look for proxy host and port.
+          int colon = proxy.lastIndexOf(":");
+          if (colon == -1 || colon == 0 || colon == proxy.length - 1) {
+            throw new HttpException(
+                "Invalid proxy configuration $configuration");
+          }
+          String host = proxy.substring(0, colon).trim();
+          if (host.startsWith("[") && host.endsWith("]")) {
+            host = host.substring(1, host.length - 1);
+          }
+          String portString = proxy.substring(colon + 1).trim();
+          int port;
+          try {
+            port = int.parse(portString);
+          } on FormatException catch (e) {
+            throw new HttpException(
+                "Invalid proxy configuration $configuration, "
+                "invalid port '$portString'");
+          }
+          proxies.add(new _Proxy(host, port, username, password));
+        } else if (proxy.trim() == DIRECT_PREFIX) {
+          proxies.add(new _Proxy.direct());
+        } else {
+          throw new HttpException("Invalid proxy configuration $configuration");
+        }
+      }
+    });
+  }
+
+  const _ProxyConfiguration.direct() : proxies = const [const _Proxy.direct()];
+
+  final List<_Proxy> proxies;
+}
+
+class _Proxy {
+  final String host;
+  final int port;
+  final String username;
+  final String password;
+  final bool isDirect;
+
+  const _Proxy(this.host, this.port, this.username, this.password)
+      : isDirect = false;
+  const _Proxy.direct()
+      : host = null,
+        port = null,
+        username = null,
+        password = null,
+        isDirect = true;
+
+  bool get isAuthenticated => username != null;
+}
+
+class _HttpConnectionInfo implements HttpConnectionInfo {
+  InternetAddress remoteAddress;
+  int remotePort;
+  int localPort;
+
+  static _HttpConnectionInfo create(Socket socket) {
+    if (socket == null) return null;
+    try {
+      _HttpConnectionInfo info = new _HttpConnectionInfo();
+      return info
+        ..remoteAddress = socket.remoteAddress
+        ..remotePort = socket.remotePort
+        ..localPort = socket.port;
+    } catch (e) {}
+    return null;
+  }
+}
+
+class _DetachedSocket extends Stream<Uint8List> implements Socket {
+  final Stream<Uint8List> _incoming;
+  final Socket _socket;
+
+  _DetachedSocket(this._socket, this._incoming);
+
+  StreamSubscription<Uint8List> listen(void onData(Uint8List event),
+      {Function onError, void onDone(), bool cancelOnError}) {
+    return _incoming.listen(onData,
+        onError: onError, onDone: onDone, cancelOnError: cancelOnError);
+  }
+
+  Encoding get encoding => _socket.encoding;
+
+  void set encoding(Encoding value) {
+    _socket.encoding = value;
+  }
+
+  void write(Object obj) {
+    _socket.write(obj);
+  }
+
+  void writeln([Object obj = ""]) {
+    _socket.writeln(obj);
+  }
+
+  void writeCharCode(int charCode) {
+    _socket.writeCharCode(charCode);
+  }
+
+  void writeAll(Iterable objects, [String separator = ""]) {
+    _socket.writeAll(objects, separator);
+  }
+
+  void add(List<int> bytes) {
+    _socket.add(bytes);
+  }
+
+  void addError(error, [StackTrace stackTrace]) =>
+      _socket.addError(error, stackTrace);
+
+  Future addStream(Stream<List<int>> stream) {
+    return _socket.addStream(stream);
+  }
+
+  void destroy() {
+    _socket.destroy();
+  }
+
+  Future flush() => _socket.flush();
+
+  Future close() => _socket.close();
+
+  Future get done => _socket.done;
+
+  int get port => _socket.port;
+
+  InternetAddress get address => _socket.address;
+
+  InternetAddress get remoteAddress => _socket.remoteAddress;
+
+  int get remotePort => _socket.remotePort;
+
+  bool setOption(SocketOption option, bool enabled) {
+    return _socket.setOption(option, enabled);
+  }
+
+  Uint8List getRawOption(RawSocketOption option) {
+    return _socket.getRawOption(option);
+  }
+
+  void setRawOption(RawSocketOption option) {
+    _socket.setRawOption(option);
+  }
+
+  Map _toJSON(bool ref) {
+    return (_socket as dynamic)._toJSON(ref);
+  }
+}
+
+class _AuthenticationScheme {
+  final int _scheme;
+
+  static const UNKNOWN = const _AuthenticationScheme(-1);
+  static const BASIC = const _AuthenticationScheme(0);
+  static const DIGEST = const _AuthenticationScheme(1);
+
+  const _AuthenticationScheme(this._scheme);
+
+  factory _AuthenticationScheme.fromString(String scheme) {
+    if (scheme.toLowerCase() == "basic") return BASIC;
+    if (scheme.toLowerCase() == "digest") return DIGEST;
+    return UNKNOWN;
+  }
+
+  String toString() {
+    if (this == BASIC) return "Basic";
+    if (this == DIGEST) return "Digest";
+    return "Unknown";
+  }
+}
+
+abstract class _Credentials {
+  _HttpClientCredentials credentials;
+  String realm;
+  bool used = false;
+
+  // Digest specific fields.
+  String ha1;
+  String nonce;
+  String algorithm;
+  String qop;
+  int nonceCount;
+
+  _Credentials(this.credentials, this.realm) {
+    if (credentials.scheme == _AuthenticationScheme.DIGEST) {
+      // Calculate the H(A1) value once. There is no mentioning of
+      // username/password encoding in RFC 2617. However there is an
+      // open draft for adding an additional accept-charset parameter to
+      // the WWW-Authenticate and Proxy-Authenticate headers, see
+      // http://tools.ietf.org/html/draft-reschke-basicauth-enc-06. For
+      // now always use UTF-8 encoding.
+      _HttpClientDigestCredentials creds = credentials;
+      var hasher = new _MD5()
+        ..add(utf8.encode(creds.username))
+        ..add([_CharCode.COLON])
+        ..add(realm.codeUnits)
+        ..add([_CharCode.COLON])
+        ..add(utf8.encode(creds.password));
+      ha1 = _CryptoUtils.bytesToHex(hasher.close());
+    }
+  }
+
+  _AuthenticationScheme get scheme => credentials.scheme;
+
+  void authorize(HttpClientRequest request);
+}
+
+class _SiteCredentials extends _Credentials {
+  Uri uri;
+
+  _SiteCredentials(this.uri, realm, _HttpClientCredentials creds)
+      : super(creds, realm);
+
+  bool applies(Uri uri, _AuthenticationScheme scheme) {
+    if (scheme != null && credentials.scheme != scheme) return false;
+    if (uri.host != this.uri.host) return false;
+    int thisPort =
+        this.uri.port == 0 ? HttpClient.defaultHttpPort : this.uri.port;
+    int otherPort = uri.port == 0 ? HttpClient.defaultHttpPort : uri.port;
+    if (otherPort != thisPort) return false;
+    return uri.path.startsWith(this.uri.path);
+  }
+
+  void authorize(HttpClientRequest request) {
+    // Digest credentials cannot be used without a nonce from the
+    // server.
+    if (credentials.scheme == _AuthenticationScheme.DIGEST && nonce == null) {
+      return;
+    }
+    credentials.authorize(this, request);
+    used = true;
+  }
+}
+
+class _ProxyCredentials extends _Credentials {
+  String host;
+  int port;
+
+  _ProxyCredentials(this.host, this.port, realm, _HttpClientCredentials creds)
+      : super(creds, realm);
+
+  bool applies(_Proxy proxy, _AuthenticationScheme scheme) {
+    if (scheme != null && credentials.scheme != scheme) return false;
+    return proxy.host == host && proxy.port == port;
+  }
+
+  void authorize(HttpClientRequest request) {
+    // Digest credentials cannot be used without a nonce from the
+    // server.
+    if (credentials.scheme == _AuthenticationScheme.DIGEST && nonce == null) {
+      return;
+    }
+    credentials.authorizeProxy(this, request);
+  }
+}
+
+abstract class _HttpClientCredentials implements HttpClientCredentials {
+  _AuthenticationScheme get scheme;
+  void authorize(_Credentials credentials, HttpClientRequest request);
+  void authorizeProxy(_ProxyCredentials credentials, HttpClientRequest request);
+}
+
+class _HttpClientBasicCredentials extends _HttpClientCredentials
+    implements HttpClientBasicCredentials {
+  String username;
+  String password;
+
+  _HttpClientBasicCredentials(this.username, this.password);
+
+  _AuthenticationScheme get scheme => _AuthenticationScheme.BASIC;
+
+  String authorization() {
+    // There is no mentioning of username/password encoding in RFC
+    // 2617. However there is an open draft for adding an additional
+    // accept-charset parameter to the WWW-Authenticate and
+    // Proxy-Authenticate headers, see
+    // http://tools.ietf.org/html/draft-reschke-basicauth-enc-06. For
+    // now always use UTF-8 encoding.
+    String auth =
+        _CryptoUtils.bytesToBase64(utf8.encode("$username:$password"));
+    return "Basic $auth";
+  }
+
+  void authorize(_Credentials _, HttpClientRequest request) {
+    request.headers.set(HttpHeaders.authorizationHeader, authorization());
+  }
+
+  void authorizeProxy(_ProxyCredentials _, HttpClientRequest request) {
+    request.headers.set(HttpHeaders.proxyAuthorizationHeader, authorization());
+  }
+}
+
+class _HttpClientDigestCredentials extends _HttpClientCredentials
+    implements HttpClientDigestCredentials {
+  String username;
+  String password;
+
+  _HttpClientDigestCredentials(this.username, this.password);
+
+  _AuthenticationScheme get scheme => _AuthenticationScheme.DIGEST;
+
+  String authorization(_Credentials credentials, _HttpClientRequest request) {
+    String requestUri = request._requestUri();
+    _MD5 hasher = new _MD5()
+      ..add(request.method.codeUnits)
+      ..add([_CharCode.COLON])
+      ..add(requestUri.codeUnits);
+    var ha2 = _CryptoUtils.bytesToHex(hasher.close());
+
+    String qop;
+    String cnonce;
+    String nc;
+    var x;
+    hasher = new _MD5()..add(credentials.ha1.codeUnits)..add([_CharCode.COLON]);
+    if (credentials.qop == "auth") {
+      qop = credentials.qop;
+      cnonce = _CryptoUtils.bytesToHex(_CryptoUtils.getRandomBytes(4));
+      ++credentials.nonceCount;
+      nc = credentials.nonceCount.toRadixString(16);
+      nc = "00000000".substring(0, 8 - nc.length + 1) + nc;
+      hasher
+        ..add(credentials.nonce.codeUnits)
+        ..add([_CharCode.COLON])
+        ..add(nc.codeUnits)
+        ..add([_CharCode.COLON])
+        ..add(cnonce.codeUnits)
+        ..add([_CharCode.COLON])
+        ..add(credentials.qop.codeUnits)
+        ..add([_CharCode.COLON])
+        ..add(ha2.codeUnits);
+    } else {
+      hasher
+        ..add(credentials.nonce.codeUnits)
+        ..add([_CharCode.COLON])
+        ..add(ha2.codeUnits);
+    }
+    var response = _CryptoUtils.bytesToHex(hasher.close());
+
+    StringBuffer buffer = new StringBuffer()
+      ..write('Digest ')
+      ..write('username="$username"')
+      ..write(', realm="${credentials.realm}"')
+      ..write(', nonce="${credentials.nonce}"')
+      ..write(', uri="$requestUri"')
+      ..write(', algorithm="${credentials.algorithm}"');
+    if (qop == "auth") {
+      buffer
+        ..write(', qop="$qop"')
+        ..write(', cnonce="$cnonce"')
+        ..write(', nc="$nc"');
+    }
+    buffer.write(', response="$response"');
+    return buffer.toString();
+  }
+
+  void authorize(_Credentials credentials, HttpClientRequest request) {
+    request.headers.set(
+        HttpHeaders.authorizationHeader, authorization(credentials, request));
+  }
+
+  void authorizeProxy(
+      _ProxyCredentials credentials, HttpClientRequest request) {
+    request.headers.set(HttpHeaders.proxyAuthorizationHeader,
+        authorization(credentials, request));
+  }
+}
+
+class _RedirectInfo implements RedirectInfo {
+  final int statusCode;
+  final String method;
+  final Uri location;
+  const _RedirectInfo(this.statusCode, this.method, this.location);
+}
+
+String _getHttpVersion() {
+  var version = Platform.version;
+  // Only include major and minor version numbers.
+  int index = version.indexOf('.', version.indexOf('.') + 1);
+  version = version.substring(0, index);
+  return 'Dart/$version (dart:io)';
+}
diff --git a/sdk_nnbd/lib/_http/http_parser.dart b/sdk_nnbd/lib/_http/http_parser.dart
new file mode 100644
index 0000000..bd85b2b
--- /dev/null
+++ b/sdk_nnbd/lib/_http/http_parser.dart
@@ -0,0 +1,1062 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart._http;
+
+// Global constants.
+class _Const {
+  // Bytes for "HTTP".
+  static const HTTP = const [72, 84, 84, 80];
+  // Bytes for "HTTP/1.".
+  static const HTTP1DOT = const [72, 84, 84, 80, 47, 49, 46];
+  // Bytes for "HTTP/1.0".
+  static const HTTP10 = const [72, 84, 84, 80, 47, 49, 46, 48];
+  // Bytes for "HTTP/1.1".
+  static const HTTP11 = const [72, 84, 84, 80, 47, 49, 46, 49];
+
+  static const bool T = true;
+  static const bool F = false;
+  // Loopup-map for the following characters: '()<>@,;:\\"/[]?={} \t'.
+  static const SEPARATOR_MAP = const [
+    F, F, F, F, F, F, F, F, F, T, F, F, F, F, F, F, F, F, F, F, F, F, F, F, //
+    F, F, F, F, F, F, F, F, T, F, T, F, F, F, F, F, T, T, F, F, T, F, F, T, //
+    F, F, F, F, F, F, F, F, F, F, T, T, T, T, T, T, T, F, F, F, F, F, F, F, //
+    F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, T, T, T, F, F, //
+    F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, //
+    F, F, F, T, F, T, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, //
+    F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, //
+    F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, //
+    F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, //
+    F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, //
+    F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F
+  ];
+}
+
+// Frequently used character codes.
+class _CharCode {
+  static const int HT = 9;
+  static const int LF = 10;
+  static const int CR = 13;
+  static const int SP = 32;
+  static const int AMPERSAND = 38;
+  static const int COMMA = 44;
+  static const int DASH = 45;
+  static const int SLASH = 47;
+  static const int ZERO = 48;
+  static const int ONE = 49;
+  static const int COLON = 58;
+  static const int SEMI_COLON = 59;
+  static const int EQUAL = 61;
+}
+
+// States of the HTTP parser state machine.
+class _State {
+  static const int START = 0;
+  static const int METHOD_OR_RESPONSE_HTTP_VERSION = 1;
+  static const int RESPONSE_HTTP_VERSION = 2;
+  static const int REQUEST_LINE_METHOD = 3;
+  static const int REQUEST_LINE_URI = 4;
+  static const int REQUEST_LINE_HTTP_VERSION = 5;
+  static const int REQUEST_LINE_ENDING = 6;
+  static const int RESPONSE_LINE_STATUS_CODE = 7;
+  static const int RESPONSE_LINE_REASON_PHRASE = 8;
+  static const int RESPONSE_LINE_ENDING = 9;
+  static const int HEADER_START = 10;
+  static const int HEADER_FIELD = 11;
+  static const int HEADER_VALUE_START = 12;
+  static const int HEADER_VALUE = 13;
+  static const int HEADER_VALUE_FOLDING_OR_ENDING = 14;
+  static const int HEADER_VALUE_FOLD_OR_END = 15;
+  static const int HEADER_ENDING = 16;
+
+  static const int CHUNK_SIZE_STARTING_CR = 17;
+  static const int CHUNK_SIZE_STARTING_LF = 18;
+  static const int CHUNK_SIZE = 19;
+  static const int CHUNK_SIZE_EXTENSION = 20;
+  static const int CHUNK_SIZE_ENDING = 21;
+  static const int CHUNKED_BODY_DONE_CR = 22;
+  static const int CHUNKED_BODY_DONE_LF = 23;
+  static const int BODY = 24;
+  static const int CLOSED = 25;
+  static const int UPGRADED = 26;
+  static const int FAILURE = 27;
+
+  static const int FIRST_BODY_STATE = CHUNK_SIZE_STARTING_CR;
+}
+
+// HTTP version of the request or response being parsed.
+class _HttpVersion {
+  static const int UNDETERMINED = 0;
+  static const int HTTP10 = 1;
+  static const int HTTP11 = 2;
+}
+
+// States of the HTTP parser state machine.
+class _MessageType {
+  static const int UNDETERMINED = 0;
+  static const int REQUEST = 1;
+  static const int RESPONSE = 0;
+}
+
+/**
+ * The _HttpDetachedStreamSubscription takes a subscription and some extra data,
+ * and makes it possible to "inject" the data in from of other data events
+ * from the subscription.
+ *
+ * It does so by overriding pause/resume, so that once the
+ * _HttpDetachedStreamSubscription is resumed, it'll deliver the data before
+ * resuming the underlaying subscription.
+ */
+class _HttpDetachedStreamSubscription implements StreamSubscription<Uint8List> {
+  StreamSubscription<Uint8List> _subscription;
+  Uint8List _injectData;
+  bool _isCanceled = false;
+  int _pauseCount = 1;
+  Function _userOnData;
+  bool _scheduled = false;
+
+  _HttpDetachedStreamSubscription(
+      this._subscription, this._injectData, this._userOnData);
+
+  bool get isPaused => _subscription.isPaused;
+
+  Future<T> asFuture<T>([T futureValue]) =>
+      _subscription.asFuture<T>(futureValue);
+
+  Future cancel() {
+    _isCanceled = true;
+    _injectData = null;
+    return _subscription.cancel();
+  }
+
+  void onData(void handleData(Uint8List data)) {
+    _userOnData = handleData;
+    _subscription.onData(handleData);
+  }
+
+  void onDone(void handleDone()) {
+    _subscription.onDone(handleDone);
+  }
+
+  void onError(Function handleError) {
+    _subscription.onError(handleError);
+  }
+
+  void pause([Future resumeSignal]) {
+    if (_injectData == null) {
+      _subscription.pause(resumeSignal);
+    } else {
+      _pauseCount++;
+      if (resumeSignal != null) {
+        resumeSignal.whenComplete(resume);
+      }
+    }
+  }
+
+  void resume() {
+    if (_injectData == null) {
+      _subscription.resume();
+    } else {
+      _pauseCount--;
+      _maybeScheduleData();
+    }
+  }
+
+  void _maybeScheduleData() {
+    if (_scheduled) return;
+    if (_pauseCount != 0) return;
+    _scheduled = true;
+    scheduleMicrotask(() {
+      _scheduled = false;
+      if (_pauseCount > 0 || _isCanceled) return;
+      var data = _injectData;
+      _injectData = null;
+      // To ensure that 'subscription.isPaused' is false, we resume the
+      // subscription here. This is fine as potential events are delayed.
+      _subscription.resume();
+      if (_userOnData != null) {
+        _userOnData(data);
+      }
+    });
+  }
+}
+
+class _HttpDetachedIncoming extends Stream<Uint8List> {
+  final StreamSubscription<Uint8List> subscription;
+  final Uint8List bufferedData;
+
+  _HttpDetachedIncoming(this.subscription, this.bufferedData);
+
+  StreamSubscription<Uint8List> listen(void onData(Uint8List event),
+      {Function onError, void onDone(), bool cancelOnError}) {
+    if (subscription != null) {
+      subscription
+        ..onData(onData)
+        ..onError(onError)
+        ..onDone(onDone);
+      if (bufferedData == null) {
+        return subscription..resume();
+      }
+      return new _HttpDetachedStreamSubscription(
+          subscription, bufferedData, onData)
+        ..resume();
+    } else {
+      // TODO(26379): add test for this branch.
+      return new Stream<Uint8List>.fromIterable([bufferedData]).listen(onData,
+          onError: onError, onDone: onDone, cancelOnError: cancelOnError);
+    }
+  }
+}
+
+/**
+ * HTTP parser which parses the data stream given to [consume].
+ *
+ * If an HTTP parser error occurs, the parser will signal an error to either
+ * the current _HttpIncoming or the _parser itself.
+ *
+ * The connection upgrades (e.g. switching from HTTP/1.1 to the
+ * WebSocket protocol) is handled in a special way. If connection
+ * upgrade is specified in the headers, then on the callback to
+ * [:responseStart:] the [:upgrade:] property on the [:HttpParser:]
+ * object will be [:true:] indicating that from now on the protocol is
+ * not HTTP anymore and no more callbacks will happen, that is
+ * [:dataReceived:] and [:dataEnd:] are not called in this case as
+ * there is no more HTTP data. After the upgrade the method
+ * [:readUnparsedData:] can be used to read any remaining bytes in the
+ * HTTP parser which are part of the protocol the connection is
+ * upgrading to. These bytes cannot be processed by the HTTP parser
+ * and should be handled according to whatever protocol is being
+ * upgraded to.
+ */
+class _HttpParser extends Stream<_HttpIncoming> {
+  // State.
+  bool _parserCalled = false;
+
+  // The data that is currently being parsed.
+  Uint8List _buffer;
+  int _index;
+
+  final bool _requestParser;
+  int _state;
+  int _httpVersionIndex;
+  int _messageType;
+  int _statusCode = 0;
+  int _statusCodeLength = 0;
+  final List<int> _method = [];
+  final List<int> _uri_or_reason_phrase = [];
+  final List<int> _headerField = [];
+  final List<int> _headerValue = [];
+
+  int _httpVersion;
+  int _transferLength = -1;
+  bool _persistentConnection;
+  bool _connectionUpgrade;
+  bool _chunked;
+
+  bool _noMessageBody = false;
+  int _remainingContent = -1;
+
+  _HttpHeaders _headers;
+
+  // The current incoming connection.
+  _HttpIncoming _incoming;
+  StreamSubscription<Uint8List> _socketSubscription;
+  bool _paused = true;
+  bool _bodyPaused = false;
+  StreamController<_HttpIncoming> _controller;
+  StreamController<Uint8List> _bodyController;
+
+  factory _HttpParser.requestParser() {
+    return new _HttpParser._(true);
+  }
+
+  factory _HttpParser.responseParser() {
+    return new _HttpParser._(false);
+  }
+
+  _HttpParser._(this._requestParser) {
+    _controller = new StreamController<_HttpIncoming>(
+        sync: true,
+        onListen: () {
+          _paused = false;
+        },
+        onPause: () {
+          _paused = true;
+          _pauseStateChanged();
+        },
+        onResume: () {
+          _paused = false;
+          _pauseStateChanged();
+        },
+        onCancel: () {
+          if (_socketSubscription != null) {
+            _socketSubscription.cancel();
+          }
+        });
+    _reset();
+  }
+
+  StreamSubscription<_HttpIncoming> listen(void onData(_HttpIncoming event),
+      {Function onError, void onDone(), bool cancelOnError}) {
+    return _controller.stream.listen(onData,
+        onError: onError, onDone: onDone, cancelOnError: cancelOnError);
+  }
+
+  void listenToStream(Stream<Uint8List> stream) {
+    // Listen to the stream and handle data accordingly. When a
+    // _HttpIncoming is created, _dataPause, _dataResume, _dataDone is
+    // given to provide a way of controlling the parser.
+    // TODO(ajohnsen): Remove _dataPause, _dataResume and _dataDone and clean up
+    // how the _HttpIncoming signals the parser.
+    _socketSubscription =
+        stream.listen(_onData, onError: _controller.addError, onDone: _onDone);
+  }
+
+  void _parse() {
+    try {
+      _doParse();
+    } catch (e, s) {
+      _state = _State.FAILURE;
+      _reportError(e, s);
+    }
+  }
+
+  // Process end of headers. Returns true if the parser should stop
+  // parsing and return. This will be in case of either an upgrade
+  // request or a request or response with an empty body.
+  bool _headersEnd() {
+    _headers._mutable = false;
+
+    _transferLength = _headers.contentLength;
+    // Ignore the Content-Length header if Transfer-Encoding
+    // is chunked (RFC 2616 section 4.4)
+    if (_chunked) _transferLength = -1;
+
+    // If a request message has neither Content-Length nor
+    // Transfer-Encoding the message must not have a body (RFC
+    // 2616 section 4.3).
+    if (_messageType == _MessageType.REQUEST &&
+        _transferLength < 0 &&
+        _chunked == false) {
+      _transferLength = 0;
+    }
+    if (_connectionUpgrade) {
+      _state = _State.UPGRADED;
+      _transferLength = 0;
+    }
+    _createIncoming(_transferLength);
+    if (_requestParser) {
+      _incoming.method = new String.fromCharCodes(_method);
+      _incoming.uri =
+          Uri.parse(new String.fromCharCodes(_uri_or_reason_phrase));
+    } else {
+      _incoming.statusCode = _statusCode;
+      _incoming.reasonPhrase = new String.fromCharCodes(_uri_or_reason_phrase);
+    }
+    _method.clear();
+    _uri_or_reason_phrase.clear();
+    if (_connectionUpgrade) {
+      _incoming.upgraded = true;
+      _parserCalled = false;
+      var tmp = _incoming;
+      _closeIncoming();
+      _controller.add(tmp);
+      return true;
+    }
+    if (_transferLength == 0 ||
+        (_messageType == _MessageType.RESPONSE && _noMessageBody)) {
+      _reset();
+      var tmp = _incoming;
+      _closeIncoming();
+      _controller.add(tmp);
+      return false;
+    } else if (_chunked) {
+      _state = _State.CHUNK_SIZE;
+      _remainingContent = 0;
+    } else if (_transferLength > 0) {
+      _remainingContent = _transferLength;
+      _state = _State.BODY;
+    } else {
+      // Neither chunked nor content length. End of body
+      // indicated by close.
+      _state = _State.BODY;
+    }
+    _parserCalled = false;
+    _controller.add(_incoming);
+    return true;
+  }
+
+  // From RFC 2616.
+  // generic-message = start-line
+  //                   *(message-header CRLF)
+  //                   CRLF
+  //                   [ message-body ]
+  // start-line      = Request-Line | Status-Line
+  // Request-Line    = Method SP Request-URI SP HTTP-Version CRLF
+  // Status-Line     = HTTP-Version SP Status-Code SP Reason-Phrase CRLF
+  // message-header  = field-name ":" [ field-value ]
+  void _doParse() {
+    assert(!_parserCalled);
+    _parserCalled = true;
+    if (_state == _State.CLOSED) {
+      throw new HttpException("Data on closed connection");
+    }
+    if (_state == _State.FAILURE) {
+      throw new HttpException("Data on failed connection");
+    }
+    while (_buffer != null &&
+        _index < _buffer.length &&
+        _state != _State.FAILURE &&
+        _state != _State.UPGRADED) {
+      // Depending on _incoming, we either break on _bodyPaused or _paused.
+      if ((_incoming != null && _bodyPaused) ||
+          (_incoming == null && _paused)) {
+        _parserCalled = false;
+        return;
+      }
+      int byte = _buffer[_index++];
+      switch (_state) {
+        case _State.START:
+          if (byte == _Const.HTTP[0]) {
+            // Start parsing method or HTTP version.
+            _httpVersionIndex = 1;
+            _state = _State.METHOD_OR_RESPONSE_HTTP_VERSION;
+          } else {
+            // Start parsing method.
+            if (!_isTokenChar(byte)) {
+              throw new HttpException("Invalid request method");
+            }
+            _method.add(byte);
+            if (!_requestParser) {
+              throw new HttpException("Invalid response line");
+            }
+            _state = _State.REQUEST_LINE_METHOD;
+          }
+          break;
+
+        case _State.METHOD_OR_RESPONSE_HTTP_VERSION:
+          if (_httpVersionIndex < _Const.HTTP.length &&
+              byte == _Const.HTTP[_httpVersionIndex]) {
+            // Continue parsing HTTP version.
+            _httpVersionIndex++;
+          } else if (_httpVersionIndex == _Const.HTTP.length &&
+              byte == _CharCode.SLASH) {
+            // HTTP/ parsed. As method is a token this cannot be a
+            // method anymore.
+            _httpVersionIndex++;
+            if (_requestParser) {
+              throw new HttpException("Invalid request line");
+            }
+            _state = _State.RESPONSE_HTTP_VERSION;
+          } else {
+            // Did not parse HTTP version. Expect method instead.
+            for (int i = 0; i < _httpVersionIndex; i++) {
+              _method.add(_Const.HTTP[i]);
+            }
+            if (byte == _CharCode.SP) {
+              _state = _State.REQUEST_LINE_URI;
+            } else {
+              _method.add(byte);
+              _httpVersion = _HttpVersion.UNDETERMINED;
+              if (!_requestParser) {
+                throw new HttpException("Invalid response line");
+              }
+              _state = _State.REQUEST_LINE_METHOD;
+            }
+          }
+          break;
+
+        case _State.RESPONSE_HTTP_VERSION:
+          if (_httpVersionIndex < _Const.HTTP1DOT.length) {
+            // Continue parsing HTTP version.
+            _expect(byte, _Const.HTTP1DOT[_httpVersionIndex]);
+            _httpVersionIndex++;
+          } else if (_httpVersionIndex == _Const.HTTP1DOT.length &&
+              byte == _CharCode.ONE) {
+            // HTTP/1.1 parsed.
+            _httpVersion = _HttpVersion.HTTP11;
+            _persistentConnection = true;
+            _httpVersionIndex++;
+          } else if (_httpVersionIndex == _Const.HTTP1DOT.length &&
+              byte == _CharCode.ZERO) {
+            // HTTP/1.0 parsed.
+            _httpVersion = _HttpVersion.HTTP10;
+            _persistentConnection = false;
+            _httpVersionIndex++;
+          } else if (_httpVersionIndex == _Const.HTTP1DOT.length + 1) {
+            _expect(byte, _CharCode.SP);
+            // HTTP version parsed.
+            _state = _State.RESPONSE_LINE_STATUS_CODE;
+          } else {
+            throw new HttpException("Invalid response line");
+          }
+          break;
+
+        case _State.REQUEST_LINE_METHOD:
+          if (byte == _CharCode.SP) {
+            _state = _State.REQUEST_LINE_URI;
+          } else {
+            if (_Const.SEPARATOR_MAP[byte] ||
+                byte == _CharCode.CR ||
+                byte == _CharCode.LF) {
+              throw new HttpException("Invalid request method");
+            }
+            _method.add(byte);
+          }
+          break;
+
+        case _State.REQUEST_LINE_URI:
+          if (byte == _CharCode.SP) {
+            if (_uri_or_reason_phrase.length == 0) {
+              throw new HttpException("Invalid request URI");
+            }
+            _state = _State.REQUEST_LINE_HTTP_VERSION;
+            _httpVersionIndex = 0;
+          } else {
+            if (byte == _CharCode.CR || byte == _CharCode.LF) {
+              throw new HttpException("Invalid request URI");
+            }
+            _uri_or_reason_phrase.add(byte);
+          }
+          break;
+
+        case _State.REQUEST_LINE_HTTP_VERSION:
+          if (_httpVersionIndex < _Const.HTTP1DOT.length) {
+            _expect(byte, _Const.HTTP11[_httpVersionIndex]);
+            _httpVersionIndex++;
+          } else if (_httpVersionIndex == _Const.HTTP1DOT.length) {
+            if (byte == _CharCode.ONE) {
+              // HTTP/1.1 parsed.
+              _httpVersion = _HttpVersion.HTTP11;
+              _persistentConnection = true;
+              _httpVersionIndex++;
+            } else if (byte == _CharCode.ZERO) {
+              // HTTP/1.0 parsed.
+              _httpVersion = _HttpVersion.HTTP10;
+              _persistentConnection = false;
+              _httpVersionIndex++;
+            } else {
+              throw new HttpException("Invalid response line");
+            }
+          } else {
+            if (byte == _CharCode.CR) {
+              _state = _State.REQUEST_LINE_ENDING;
+            } else {
+              _expect(byte, _CharCode.LF);
+              _messageType = _MessageType.REQUEST;
+              _state = _State.HEADER_START;
+            }
+          }
+          break;
+
+        case _State.REQUEST_LINE_ENDING:
+          _expect(byte, _CharCode.LF);
+          _messageType = _MessageType.REQUEST;
+          _state = _State.HEADER_START;
+          break;
+
+        case _State.RESPONSE_LINE_STATUS_CODE:
+          if (byte == _CharCode.SP) {
+            _state = _State.RESPONSE_LINE_REASON_PHRASE;
+          } else if (byte == _CharCode.CR) {
+            // Some HTTP servers does not follow the spec. and send
+            // \r\n right after the status code.
+            _state = _State.RESPONSE_LINE_ENDING;
+          } else {
+            _statusCodeLength++;
+            if ((byte < 0x30 && 0x39 < byte) || _statusCodeLength > 3) {
+              throw new HttpException("Invalid response status code");
+            } else {
+              _statusCode = _statusCode * 10 + byte - 0x30;
+            }
+          }
+          break;
+
+        case _State.RESPONSE_LINE_REASON_PHRASE:
+          if (byte == _CharCode.CR) {
+            _state = _State.RESPONSE_LINE_ENDING;
+          } else {
+            if (byte == _CharCode.CR || byte == _CharCode.LF) {
+              throw new HttpException("Invalid response reason phrase");
+            }
+            _uri_or_reason_phrase.add(byte);
+          }
+          break;
+
+        case _State.RESPONSE_LINE_ENDING:
+          _expect(byte, _CharCode.LF);
+          _messageType == _MessageType.RESPONSE;
+          if (_statusCode < 100 || _statusCode > 599) {
+            throw new HttpException("Invalid response status code");
+          } else {
+            // Check whether this response will never have a body.
+            if (_statusCode <= 199 ||
+                _statusCode == 204 ||
+                _statusCode == 304) {
+              _noMessageBody = true;
+            }
+          }
+          _state = _State.HEADER_START;
+          break;
+
+        case _State.HEADER_START:
+          _headers = new _HttpHeaders(version);
+          if (byte == _CharCode.CR) {
+            _state = _State.HEADER_ENDING;
+          } else if (byte == _CharCode.LF) {
+            _state = _State.HEADER_ENDING;
+            _index--; // Make the new state see the LF again.
+          } else {
+            // Start of new header field.
+            _headerField.add(_toLowerCaseByte(byte));
+            _state = _State.HEADER_FIELD;
+          }
+          break;
+
+        case _State.HEADER_FIELD:
+          if (byte == _CharCode.COLON) {
+            _state = _State.HEADER_VALUE_START;
+          } else {
+            if (!_isTokenChar(byte)) {
+              throw new HttpException("Invalid header field name");
+            }
+            _headerField.add(_toLowerCaseByte(byte));
+          }
+          break;
+
+        case _State.HEADER_VALUE_START:
+          if (byte == _CharCode.CR) {
+            _state = _State.HEADER_VALUE_FOLDING_OR_ENDING;
+          } else if (byte == _CharCode.LF) {
+            _state = _State.HEADER_VALUE_FOLD_OR_END;
+          } else if (byte != _CharCode.SP && byte != _CharCode.HT) {
+            // Start of new header value.
+            _headerValue.add(byte);
+            _state = _State.HEADER_VALUE;
+          }
+          break;
+
+        case _State.HEADER_VALUE:
+          if (byte == _CharCode.CR) {
+            _state = _State.HEADER_VALUE_FOLDING_OR_ENDING;
+          } else if (byte == _CharCode.LF) {
+            _state = _State.HEADER_VALUE_FOLD_OR_END;
+          } else {
+            _headerValue.add(byte);
+          }
+          break;
+
+        case _State.HEADER_VALUE_FOLDING_OR_ENDING:
+          _expect(byte, _CharCode.LF);
+          _state = _State.HEADER_VALUE_FOLD_OR_END;
+          break;
+
+        case _State.HEADER_VALUE_FOLD_OR_END:
+          if (byte == _CharCode.SP || byte == _CharCode.HT) {
+            _state = _State.HEADER_VALUE_START;
+          } else {
+            String headerField = new String.fromCharCodes(_headerField);
+            String headerValue = new String.fromCharCodes(_headerValue);
+            if (headerField == "transfer-encoding" &&
+                _caseInsensitiveCompare("chunked".codeUnits, _headerValue)) {
+              _chunked = true;
+            }
+            if (headerField == "connection") {
+              List<String> tokens = _tokenizeFieldValue(headerValue);
+              final bool isResponse = _messageType == _MessageType.RESPONSE;
+              final bool isUpgradeCode =
+                  (_statusCode == HttpStatus.upgradeRequired) ||
+                      (_statusCode == HttpStatus.switchingProtocols);
+              for (int i = 0; i < tokens.length; i++) {
+                final bool isUpgrade = _caseInsensitiveCompare(
+                    "upgrade".codeUnits, tokens[i].codeUnits);
+                if ((isUpgrade && !isResponse) ||
+                    (isUpgrade && isResponse && isUpgradeCode)) {
+                  _connectionUpgrade = true;
+                }
+                _headers._add(headerField, tokens[i]);
+              }
+            } else {
+              _headers._add(headerField, headerValue);
+            }
+            _headerField.clear();
+            _headerValue.clear();
+
+            if (byte == _CharCode.CR) {
+              _state = _State.HEADER_ENDING;
+            } else if (byte == _CharCode.LF) {
+              _state = _State.HEADER_ENDING;
+              _index--; // Make the new state see the LF again.
+            } else {
+              // Start of new header field.
+              _headerField.add(_toLowerCaseByte(byte));
+              _state = _State.HEADER_FIELD;
+            }
+          }
+          break;
+
+        case _State.HEADER_ENDING:
+          _expect(byte, _CharCode.LF);
+          if (_headersEnd()) {
+            return;
+          } else {
+            break;
+          }
+          return;
+
+        case _State.CHUNK_SIZE_STARTING_CR:
+          _expect(byte, _CharCode.CR);
+          _state = _State.CHUNK_SIZE_STARTING_LF;
+          break;
+
+        case _State.CHUNK_SIZE_STARTING_LF:
+          _expect(byte, _CharCode.LF);
+          _state = _State.CHUNK_SIZE;
+          break;
+
+        case _State.CHUNK_SIZE:
+          if (byte == _CharCode.CR) {
+            _state = _State.CHUNK_SIZE_ENDING;
+          } else if (byte == _CharCode.SEMI_COLON) {
+            _state = _State.CHUNK_SIZE_EXTENSION;
+          } else {
+            int value = _expectHexDigit(byte);
+            _remainingContent = _remainingContent * 16 + value;
+          }
+          break;
+
+        case _State.CHUNK_SIZE_EXTENSION:
+          if (byte == _CharCode.CR) {
+            _state = _State.CHUNK_SIZE_ENDING;
+          }
+          break;
+
+        case _State.CHUNK_SIZE_ENDING:
+          _expect(byte, _CharCode.LF);
+          if (_remainingContent > 0) {
+            _state = _State.BODY;
+          } else {
+            _state = _State.CHUNKED_BODY_DONE_CR;
+          }
+          break;
+
+        case _State.CHUNKED_BODY_DONE_CR:
+          _expect(byte, _CharCode.CR);
+          _state = _State.CHUNKED_BODY_DONE_LF;
+          break;
+
+        case _State.CHUNKED_BODY_DONE_LF:
+          _expect(byte, _CharCode.LF);
+          _reset();
+          _closeIncoming();
+          break;
+
+        case _State.BODY:
+          // The body is not handled one byte at a time but in blocks.
+          _index--;
+          int dataAvailable = _buffer.length - _index;
+          if (_remainingContent >= 0 && dataAvailable > _remainingContent) {
+            dataAvailable = _remainingContent;
+          }
+          // Always present the data as a view. This way we can handle all
+          // cases like this, and the user will not experience different data
+          // typed (which could lead to polymorphic user code).
+          Uint8List data = new Uint8List.view(
+              _buffer.buffer, _buffer.offsetInBytes + _index, dataAvailable);
+          _bodyController.add(data);
+          if (_remainingContent != -1) {
+            _remainingContent -= data.length;
+          }
+          _index += data.length;
+          if (_remainingContent == 0) {
+            if (!_chunked) {
+              _reset();
+              _closeIncoming();
+            } else {
+              _state = _State.CHUNK_SIZE_STARTING_CR;
+            }
+          }
+          break;
+
+        case _State.FAILURE:
+          // Should be unreachable.
+          assert(false);
+          break;
+
+        default:
+          // Should be unreachable.
+          assert(false);
+          break;
+      }
+    }
+
+    _parserCalled = false;
+    if (_buffer != null && _index == _buffer.length) {
+      // If all data is parsed release the buffer and resume receiving
+      // data.
+      _releaseBuffer();
+      if (_state != _State.UPGRADED && _state != _State.FAILURE) {
+        _socketSubscription.resume();
+      }
+    }
+  }
+
+  void _onData(Uint8List buffer) {
+    _socketSubscription.pause();
+    assert(_buffer == null);
+    _buffer = buffer;
+    _index = 0;
+    _parse();
+  }
+
+  void _onDone() {
+    // onDone cancels the subscription.
+    _socketSubscription = null;
+    if (_state == _State.CLOSED || _state == _State.FAILURE) return;
+
+    if (_incoming != null) {
+      if (_state != _State.UPGRADED &&
+          !(_state == _State.START && !_requestParser) &&
+          !(_state == _State.BODY && !_chunked && _transferLength == -1)) {
+        _bodyController.addError(
+            new HttpException("Connection closed while receiving data"));
+      }
+      _closeIncoming(true);
+      _controller.close();
+      return;
+    }
+    // If the connection is idle the HTTP stream is closed.
+    if (_state == _State.START) {
+      if (!_requestParser) {
+        _reportError(new HttpException(
+            "Connection closed before full header was received"));
+      }
+      _controller.close();
+      return;
+    }
+
+    if (_state == _State.UPGRADED) {
+      _controller.close();
+      return;
+    }
+
+    if (_state < _State.FIRST_BODY_STATE) {
+      _state = _State.FAILURE;
+      // Report the error through the error callback if any. Otherwise
+      // throw the error.
+      _reportError(new HttpException(
+          "Connection closed before full header was received"));
+      _controller.close();
+      return;
+    }
+
+    if (!_chunked && _transferLength == -1) {
+      _state = _State.CLOSED;
+    } else {
+      _state = _State.FAILURE;
+      // Report the error through the error callback if any. Otherwise
+      // throw the error.
+      _reportError(
+          new HttpException("Connection closed before full body was received"));
+    }
+    _controller.close();
+  }
+
+  String get version {
+    switch (_httpVersion) {
+      case _HttpVersion.HTTP10:
+        return "1.0";
+      case _HttpVersion.HTTP11:
+        return "1.1";
+    }
+    return null;
+  }
+
+  int get messageType => _messageType;
+  int get transferLength => _transferLength;
+  bool get upgrade => _connectionUpgrade && _state == _State.UPGRADED;
+  bool get persistentConnection => _persistentConnection;
+
+  void set isHead(bool value) {
+    if (value) _noMessageBody = true;
+  }
+
+  _HttpDetachedIncoming detachIncoming() {
+    // Simulate detached by marking as upgraded.
+    _state = _State.UPGRADED;
+    return new _HttpDetachedIncoming(_socketSubscription, readUnparsedData());
+  }
+
+  Uint8List readUnparsedData() {
+    if (_buffer == null) return null;
+    if (_index == _buffer.length) return null;
+    var result = _buffer.sublist(_index);
+    _releaseBuffer();
+    return result;
+  }
+
+  void _reset() {
+    if (_state == _State.UPGRADED) return;
+    _state = _State.START;
+    _messageType = _MessageType.UNDETERMINED;
+    _headerField.clear();
+    _headerValue.clear();
+    _method.clear();
+    _uri_or_reason_phrase.clear();
+
+    _statusCode = 0;
+    _statusCodeLength = 0;
+
+    _httpVersion = _HttpVersion.UNDETERMINED;
+    _transferLength = -1;
+    _persistentConnection = false;
+    _connectionUpgrade = false;
+    _chunked = false;
+
+    _noMessageBody = false;
+    _remainingContent = -1;
+
+    _headers = null;
+  }
+
+  void _releaseBuffer() {
+    _buffer = null;
+    _index = null;
+  }
+
+  static bool _isTokenChar(int byte) {
+    return byte > 31 && byte < 128 && !_Const.SEPARATOR_MAP[byte];
+  }
+
+  static bool _isValueChar(int byte) {
+    return (byte > 31 && byte < 128) ||
+        (byte == _CharCode.SP) ||
+        (byte == _CharCode.HT);
+  }
+
+  static List<String> _tokenizeFieldValue(String headerValue) {
+    List<String> tokens = new List<String>();
+    int start = 0;
+    int index = 0;
+    while (index < headerValue.length) {
+      if (headerValue[index] == ",") {
+        tokens.add(headerValue.substring(start, index));
+        start = index + 1;
+      } else if (headerValue[index] == " " || headerValue[index] == "\t") {
+        start++;
+      }
+      index++;
+    }
+    tokens.add(headerValue.substring(start, index));
+    return tokens;
+  }
+
+  static int _toLowerCaseByte(int x) {
+    // Optimized version:
+    //  -  0x41 is 'A'
+    //  -  0x7f is ASCII mask
+    //  -  26 is the number of alpha characters.
+    //  -  0x20 is the delta between lower and upper chars.
+    return (((x - 0x41) & 0x7f) < 26) ? (x | 0x20) : x;
+  }
+
+  // expected should already be lowercase.
+  bool _caseInsensitiveCompare(List<int> expected, List<int> value) {
+    if (expected.length != value.length) return false;
+    for (int i = 0; i < expected.length; i++) {
+      if (expected[i] != _toLowerCaseByte(value[i])) return false;
+    }
+    return true;
+  }
+
+  int _expect(int val1, int val2) {
+    if (val1 != val2) {
+      throw new HttpException("Failed to parse HTTP");
+    }
+  }
+
+  int _expectHexDigit(int byte) {
+    if (0x30 <= byte && byte <= 0x39) {
+      return byte - 0x30; // 0 - 9
+    } else if (0x41 <= byte && byte <= 0x46) {
+      return byte - 0x41 + 10; // A - F
+    } else if (0x61 <= byte && byte <= 0x66) {
+      return byte - 0x61 + 10; // a - f
+    } else {
+      throw new HttpException("Failed to parse HTTP");
+    }
+  }
+
+  void _createIncoming(int transferLength) {
+    assert(_incoming == null);
+    assert(_bodyController == null);
+    assert(!_bodyPaused);
+    var incoming;
+    _bodyController = new StreamController<Uint8List>(
+        sync: true,
+        onListen: () {
+          if (incoming != _incoming) return;
+          assert(_bodyPaused);
+          _bodyPaused = false;
+          _pauseStateChanged();
+        },
+        onPause: () {
+          if (incoming != _incoming) return;
+          assert(!_bodyPaused);
+          _bodyPaused = true;
+          _pauseStateChanged();
+        },
+        onResume: () {
+          if (incoming != _incoming) return;
+          assert(_bodyPaused);
+          _bodyPaused = false;
+          _pauseStateChanged();
+        },
+        onCancel: () {
+          if (incoming != _incoming) return;
+          if (_socketSubscription != null) {
+            _socketSubscription.cancel();
+          }
+          _closeIncoming(true);
+          _controller.close();
+        });
+    incoming = _incoming =
+        new _HttpIncoming(_headers, transferLength, _bodyController.stream);
+    _bodyPaused = true;
+    _pauseStateChanged();
+  }
+
+  void _closeIncoming([bool closing = false]) {
+    // Ignore multiple close (can happen in re-entrance).
+    if (_incoming == null) return;
+    var tmp = _incoming;
+    tmp.close(closing);
+    _incoming = null;
+    if (_bodyController != null) {
+      _bodyController.close();
+      _bodyController = null;
+    }
+    _bodyPaused = false;
+    _pauseStateChanged();
+  }
+
+  void _pauseStateChanged() {
+    if (_incoming != null) {
+      if (!_bodyPaused && !_parserCalled) {
+        _parse();
+      }
+    } else {
+      if (!_paused && !_parserCalled) {
+        _parse();
+      }
+    }
+  }
+
+  void _reportError(error, [stackTrace]) {
+    if (_socketSubscription != null) _socketSubscription.cancel();
+    _state = _State.FAILURE;
+    _controller.addError(error, stackTrace);
+    _controller.close();
+  }
+}
diff --git a/sdk_nnbd/lib/_http/http_session.dart b/sdk_nnbd/lib/_http/http_session.dart
new file mode 100644
index 0000000..3907609
--- /dev/null
+++ b/sdk_nnbd/lib/_http/http_session.dart
@@ -0,0 +1,205 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart._http;
+
+const String _DART_SESSION_ID = "DARTSESSID";
+
+// A _HttpSession is a node in a double-linked list, with _next and _prev being
+// the previous and next pointers.
+class _HttpSession implements HttpSession {
+  // Destroyed marked. Used by the http connection to see if a session is valid.
+  bool _destroyed = false;
+  bool _isNew = true;
+  DateTime _lastSeen;
+  Function _timeoutCallback;
+  _HttpSessionManager _sessionManager;
+  // Pointers in timeout queue.
+  _HttpSession _prev;
+  _HttpSession _next;
+  final String id;
+
+  final Map _data = new HashMap();
+
+  _HttpSession(this._sessionManager, this.id) : _lastSeen = new DateTime.now();
+
+  void destroy() {
+    _destroyed = true;
+    _sessionManager._removeFromTimeoutQueue(this);
+    _sessionManager._sessions.remove(id);
+  }
+
+  // Mark the session as seen. This will reset the timeout and move the node to
+  // the end of the timeout queue.
+  void _markSeen() {
+    _lastSeen = new DateTime.now();
+    _sessionManager._bumpToEnd(this);
+  }
+
+  DateTime get lastSeen => _lastSeen;
+
+  bool get isNew => _isNew;
+
+  void set onTimeout(void callback()) {
+    _timeoutCallback = callback;
+  }
+
+  // Map implementation:
+  bool containsValue(value) => _data.containsValue(value);
+  bool containsKey(key) => _data.containsKey(key);
+  operator [](key) => _data[key];
+  void operator []=(key, value) {
+    _data[key] = value;
+  }
+
+  putIfAbsent(key, ifAbsent) => _data.putIfAbsent(key, ifAbsent);
+  addAll(Map other) => _data.addAll(other);
+  remove(key) => _data.remove(key);
+  void clear() {
+    _data.clear();
+  }
+
+  void forEach(void f(key, value)) {
+    _data.forEach(f);
+  }
+
+  Iterable<MapEntry> get entries => _data.entries;
+
+  void addEntries(Iterable<MapEntry> entries) {
+    _data.addEntries(entries);
+  }
+
+  Map<K, V> map<K, V>(MapEntry<K, V> transform(key, value)) =>
+      _data.map(transform);
+
+  void removeWhere(bool test(key, value)) {
+    _data.removeWhere(test);
+  }
+
+  Map<K, V> cast<K, V>() => _data.cast<K, V>();
+  update(key, update(value), {ifAbsent()}) =>
+      _data.update(key, update, ifAbsent: ifAbsent);
+
+  void updateAll(update(key, value)) {
+    _data.updateAll(update);
+  }
+
+  Iterable get keys => _data.keys;
+  Iterable get values => _data.values;
+  int get length => _data.length;
+  bool get isEmpty => _data.isEmpty;
+  bool get isNotEmpty => _data.isNotEmpty;
+
+  String toString() => 'HttpSession id:$id $_data';
+}
+
+// Private class used to manage all the active sessions. The sessions are stored
+// in two ways:
+//
+//  * In a map, mapping from ID to HttpSession.
+//  * In a linked list, used as a timeout queue.
+class _HttpSessionManager {
+  Map<String, _HttpSession> _sessions;
+  int _sessionTimeout = 20 * 60; // 20 mins.
+  _HttpSession _head;
+  _HttpSession _tail;
+  Timer _timer;
+
+  _HttpSessionManager() : _sessions = {};
+
+  String createSessionId() {
+    const int _KEY_LENGTH = 16; // 128 bits.
+    var data = _CryptoUtils.getRandomBytes(_KEY_LENGTH);
+    return _CryptoUtils.bytesToHex(data);
+  }
+
+  _HttpSession getSession(String id) => _sessions[id];
+
+  _HttpSession createSession() {
+    var id = createSessionId();
+    // TODO(ajohnsen): Consider adding a limit and throwing an exception.
+    // Should be very unlikely however.
+    while (_sessions.containsKey(id)) {
+      id = createSessionId();
+    }
+    var session = _sessions[id] = new _HttpSession(this, id);
+    _addToTimeoutQueue(session);
+    return session;
+  }
+
+  void set sessionTimeout(int timeout) {
+    _sessionTimeout = timeout;
+    _stopTimer();
+    _startTimer();
+  }
+
+  void close() {
+    _stopTimer();
+  }
+
+  void _bumpToEnd(_HttpSession session) {
+    _removeFromTimeoutQueue(session);
+    _addToTimeoutQueue(session);
+  }
+
+  void _addToTimeoutQueue(_HttpSession session) {
+    if (_head == null) {
+      assert(_tail == null);
+      _tail = _head = session;
+      _startTimer();
+    } else {
+      assert(_timer != null);
+      assert(_tail != null);
+      // Add to end.
+      _tail._next = session;
+      session._prev = _tail;
+      _tail = session;
+    }
+  }
+
+  void _removeFromTimeoutQueue(_HttpSession session) {
+    if (session._next != null) {
+      session._next._prev = session._prev;
+    }
+    if (session._prev != null) {
+      session._prev._next = session._next;
+    }
+    if (_head == session) {
+      // We removed the head element, start new timer.
+      _head = session._next;
+      _stopTimer();
+      _startTimer();
+    }
+    if (_tail == session) {
+      _tail = session._prev;
+    }
+    session._next = session._prev = null;
+  }
+
+  void _timerTimeout() {
+    _stopTimer(); // Clear timer.
+    assert(_head != null);
+    var session = _head;
+    session.destroy(); // Will remove the session from timeout queue and map.
+    if (session._timeoutCallback != null) {
+      session._timeoutCallback();
+    }
+  }
+
+  void _startTimer() {
+    assert(_timer == null);
+    if (_head != null) {
+      int seconds = new DateTime.now().difference(_head.lastSeen).inSeconds;
+      _timer = new Timer(
+          new Duration(seconds: _sessionTimeout - seconds), _timerTimeout);
+    }
+  }
+
+  void _stopTimer() {
+    if (_timer != null) {
+      _timer.cancel();
+      _timer = null;
+    }
+  }
+}
diff --git a/sdk_nnbd/lib/_http/http_sources.gni b/sdk_nnbd/lib/_http/http_sources.gni
new file mode 100644
index 0000000..1ce36b4
--- /dev/null
+++ b/sdk_nnbd/lib/_http/http_sources.gni
@@ -0,0 +1,18 @@
+# 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.
+
+http_sdk_sources = [
+  "http.dart",
+
+  # The above file needs to be first if additional parts are added to the lib.
+  "crypto.dart",
+  "http_date.dart",
+  "http_headers.dart",
+  "http_impl.dart",
+  "http_parser.dart",
+  "http_session.dart",
+  "overrides.dart",
+  "websocket.dart",
+  "websocket_impl.dart",
+]
diff --git a/sdk_nnbd/lib/_http/overrides.dart b/sdk_nnbd/lib/_http/overrides.dart
new file mode 100644
index 0000000..7f9e689
--- /dev/null
+++ b/sdk_nnbd/lib/_http/overrides.dart
@@ -0,0 +1,118 @@
+// 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.
+
+part of dart._http;
+
+final _httpOverridesToken = new Object();
+
+const _asyncRunZoned = runZoned;
+
+/// This class facilitates overriding [HttpClient] with a mock implementation.
+/// It should be extended by another class in client code with overrides
+/// that construct a mock implementation. The implementation in this base class
+/// defaults to the actual [HttpClient] implementation. For example:
+///
+/// ```
+/// class MyHttpClient implements HttpClient {
+///   ...
+///   // An implementation of the HttpClient interface
+///   ...
+/// }
+///
+/// main() {
+///   HttpOverrides.runZoned(() {
+///     ...
+///     // Operations will use MyHttpClient instead of the real HttpClient
+///     // implementation whenever HttpClient is used.
+///     ...
+///   }, createHttpClient: (SecurityContext c) => new MyHttpClient(c));
+/// }
+/// ```
+abstract class HttpOverrides {
+  static HttpOverrides _global;
+
+  static HttpOverrides get current {
+    return Zone.current[_httpOverridesToken] ?? _global;
+  }
+
+  /// The [HttpOverrides] to use in the root [Zone].
+  ///
+  /// These are the [HttpOverrides] that will be used in the root Zone, and in
+  /// Zone's that do not set [HttpOverrides] and whose ancestors up to the root
+  /// Zone do not set [HttpOverrides].
+  static set global(HttpOverrides overrides) {
+    _global = overrides;
+  }
+
+  /// Runs [body] in a fresh [Zone] using the provided overrides.
+  static R runZoned<R>(R body(),
+      {HttpClient Function(SecurityContext) createHttpClient,
+      String Function(Uri uri, Map<String, String> environment)
+          findProxyFromEnvironment,
+      ZoneSpecification zoneSpecification,
+      Function onError}) {
+    HttpOverrides overrides =
+        new _HttpOverridesScope(createHttpClient, findProxyFromEnvironment);
+    return _asyncRunZoned<R>(body,
+        zoneValues: {_httpOverridesToken: overrides},
+        zoneSpecification: zoneSpecification,
+        onError: onError);
+  }
+
+  /// Runs [body] in a fresh [Zone] using the overrides found in [overrides].
+  ///
+  /// Note that [overrides] should be an instance of a class that extends
+  /// [HttpOverrides].
+  static R runWithHttpOverrides<R>(R body(), HttpOverrides overrides,
+      {ZoneSpecification zoneSpecification, Function onError}) {
+    return _asyncRunZoned<R>(body,
+        zoneValues: {_httpOverridesToken: overrides},
+        zoneSpecification: zoneSpecification,
+        onError: onError);
+  }
+
+  /// Returns a new [HttpClient] using the given [context].
+  ///
+  /// When this override is installed, this function overrides the behavior of
+  /// `new HttpClient`.
+  HttpClient createHttpClient(SecurityContext context) {
+    return new _HttpClient(context);
+  }
+
+  /// Resolves the proxy server to be used for HTTP connections.
+  ///
+  /// When this override is installed, this function overrides the behavior of
+  /// `HttpClient.findProxyFromEnvironment`.
+  String findProxyFromEnvironment(Uri url, Map<String, String> environment) {
+    return _HttpClient._findProxyFromEnvironment(url, environment);
+  }
+}
+
+class _HttpOverridesScope extends HttpOverrides {
+  final HttpOverrides _previous = HttpOverrides.current;
+
+  final HttpClient Function(SecurityContext) _createHttpClient;
+  final String Function(Uri uri, Map<String, String> environment)
+      _findProxyFromEnvironment;
+
+  _HttpOverridesScope(this._createHttpClient, this._findProxyFromEnvironment);
+
+  @override
+  HttpClient createHttpClient(SecurityContext context) {
+    if (_createHttpClient != null) return _createHttpClient(context);
+    if (_previous != null) return _previous.createHttpClient(context);
+    return super.createHttpClient(context);
+  }
+
+  @override
+  String findProxyFromEnvironment(Uri url, Map<String, String> environment) {
+    if (_findProxyFromEnvironment != null) {
+      return _findProxyFromEnvironment(url, environment);
+    }
+    if (_previous != null) {
+      return _previous.findProxyFromEnvironment(url, environment);
+    }
+    return super.findProxyFromEnvironment(url, environment);
+  }
+}
diff --git a/sdk_nnbd/lib/_http/websocket.dart b/sdk_nnbd/lib/_http/websocket.dart
new file mode 100644
index 0000000..5a949af
--- /dev/null
+++ b/sdk_nnbd/lib/_http/websocket.dart
@@ -0,0 +1,497 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart._http;
+
+/**
+ * WebSocket status codes used when closing a WebSocket connection.
+ */
+abstract class WebSocketStatus {
+  static const int normalClosure = 1000;
+  static const int goingAway = 1001;
+  static const int protocolError = 1002;
+  static const int unsupportedData = 1003;
+  static const int reserved1004 = 1004;
+  static const int noStatusReceived = 1005;
+  static const int abnormalClosure = 1006;
+  static const int invalidFramePayloadData = 1007;
+  static const int policyViolation = 1008;
+  static const int messageTooBig = 1009;
+  static const int missingMandatoryExtension = 1010;
+  static const int internalServerError = 1011;
+  static const int reserved1015 = 1015;
+
+  @Deprecated("Use normalClosure instead")
+  static const int NORMAL_CLOSURE = normalClosure;
+  @Deprecated("Use goingAway instead")
+  static const int GOING_AWAY = goingAway;
+  @Deprecated("Use protocolError instead")
+  static const int PROTOCOL_ERROR = protocolError;
+  @Deprecated("Use unsupportedData instead")
+  static const int UNSUPPORTED_DATA = unsupportedData;
+  @Deprecated("Use reserved1004 instead")
+  static const int RESERVED_1004 = reserved1004;
+  @Deprecated("Use noStatusReceived instead")
+  static const int NO_STATUS_RECEIVED = noStatusReceived;
+  @Deprecated("Use abnormalClosure instead")
+  static const int ABNORMAL_CLOSURE = abnormalClosure;
+  @Deprecated("Use invalidFramePayloadData instead")
+  static const int INVALID_FRAME_PAYLOAD_DATA = invalidFramePayloadData;
+  @Deprecated("Use policyViolation instead")
+  static const int POLICY_VIOLATION = policyViolation;
+  @Deprecated("Use messageTooBig instead")
+  static const int MESSAGE_TOO_BIG = messageTooBig;
+  @Deprecated("Use missingMandatoryExtension instead")
+  static const int MISSING_MANDATORY_EXTENSION = missingMandatoryExtension;
+  @Deprecated("Use internalServerError instead")
+  static const int INTERNAL_SERVER_ERROR = internalServerError;
+  @Deprecated("Use reserved1015 instead")
+  static const int RESERVED_1015 = reserved1015;
+}
+
+/// Options controlling compression in a [WebSocket].
+///
+/// A [CompressionOptions] instance can be passed to [WebSocket.connect], or
+/// used in other similar places where [WebSocket] compression is configured.
+///
+/// In most cases the default [compressionDefault] is sufficient, but in some
+/// situations, it might be desirable to use different compression parameters,
+/// for example to preserve memory on small devices.
+class CompressionOptions {
+  /// Default [WebSocket] compression configuration.
+  ///
+  /// Enables compression with default window sizes and no reuse. This is the
+  /// default options used by [WebSocket.connect] if no [CompressionOptions] is
+  /// supplied.
+  ///
+  /// * `clientNoContextTakeover`: false
+  /// * `serverNoContextTakeover`: false
+  /// * `clientMaxWindowBits`: null (default maximal window size of 15 bits)
+  /// * `serverMaxWindowBits`: null (default maximal window size of 15 bits)
+  static const CompressionOptions compressionDefault =
+      const CompressionOptions();
+  @Deprecated("Use compressionDefault instead")
+  static const CompressionOptions DEFAULT = compressionDefault;
+
+  /// No-compression configuration.
+  ///
+  /// Disables compression when used as compression configuration for a
+  /// [WebSocket].
+  static const CompressionOptions compressionOff =
+      const CompressionOptions(enabled: false);
+  @Deprecated("Use compressionOff instead")
+  static const CompressionOptions OFF = compressionOff;
+
+  /// Whether the client will reuse its compression instances.
+  final bool clientNoContextTakeover;
+
+  /// Whether the server will reuse its compression instances.
+  final bool serverNoContextTakeover;
+
+  /// The maximal window size bit count requested by the client.
+  ///
+  /// The windows size for the compression is always a power of two, so the
+  /// number of bits precisely determines the window size.
+  ///
+  /// If set to `null`, the client has no preference, and the compression can
+  /// use up to its default maximum window size of 15 bits depending on the
+  /// server's preference.
+  final int clientMaxWindowBits;
+
+  /// The maximal window size bit count requested by the server.
+  ///
+  /// The windows size for the compression is always a power of two, so the
+  /// number of bits precisely determines the window size.
+  ///
+  /// If set to `null`, the server has no preference, and the compression can
+  /// use up to its default maximum window size of 15 bits depending on the
+  /// client's preference.
+  final int serverMaxWindowBits;
+
+  /// Whether WebSocket compression is enabled.
+  ///
+  /// If not enabled, the remaining fields have no effect, and the
+  /// [compressionOff] instance can, and should, be reused instead of creating a
+  /// new instance with compression disabled.
+  final bool enabled;
+
+  const CompressionOptions(
+      {this.clientNoContextTakeover = false,
+      this.serverNoContextTakeover = false,
+      this.clientMaxWindowBits,
+      this.serverMaxWindowBits,
+      this.enabled = true});
+
+  /// Parses list of requested server headers to return server compression
+  /// response headers.
+  ///
+  /// Uses [serverMaxWindowBits] value if set, otherwise will attempt to use
+  /// value from headers. Defaults to [WebSocket.DEFAULT_WINDOW_BITS]. Returns a
+  /// [_CompressionMaxWindowBits] object which contains the response headers and
+  /// negotiated max window bits.
+  _CompressionMaxWindowBits _createServerResponseHeader(HeaderValue requested) {
+    var info = new _CompressionMaxWindowBits();
+
+    int mwb;
+    String part;
+    if (requested?.parameters != null) {
+      part = requested.parameters[_serverMaxWindowBits];
+    }
+    if (part != null) {
+      if (part.length >= 2 && part.startsWith('0')) {
+        throw new ArgumentError("Illegal 0 padding on value.");
+      } else {
+        mwb = serverMaxWindowBits == null
+            ? int.parse(part,
+                onError: (source) => _WebSocketImpl.DEFAULT_WINDOW_BITS)
+            : serverMaxWindowBits;
+        info.headerValue = "; server_max_window_bits=${mwb}";
+        info.maxWindowBits = mwb;
+      }
+    } else {
+      info.headerValue = "";
+      info.maxWindowBits = _WebSocketImpl.DEFAULT_WINDOW_BITS;
+    }
+    return info;
+  }
+
+  /// Returns default values for client compression request headers.
+  String _createClientRequestHeader(HeaderValue requested, int size) {
+    var info = "";
+
+    // If responding to a valid request, specify size
+    if (requested != null) {
+      info = "; client_max_window_bits=$size";
+    } else {
+      // Client request. Specify default
+      if (clientMaxWindowBits == null) {
+        info = "; client_max_window_bits";
+      } else {
+        info = "; client_max_window_bits=$clientMaxWindowBits";
+      }
+      if (serverMaxWindowBits != null) {
+        info += "; server_max_window_bits=$serverMaxWindowBits";
+      }
+    }
+
+    return info;
+  }
+
+  /// Create a Compression Header.
+  ///
+  /// If [requested] is null or contains client request headers, returns Client
+  /// compression request headers with default settings for
+  /// `client_max_window_bits` header value.  If [requested] contains server
+  /// response headers this method returns a Server compression response header
+  /// negotiating the max window bits for both client and server as requested
+  /// `server_max_window_bits` value.  This method returns a
+  /// [_CompressionMaxWindowBits] object with the response headers and
+  /// negotiated `maxWindowBits` value.
+  _CompressionMaxWindowBits _createHeader([HeaderValue requested]) {
+    var info = new _CompressionMaxWindowBits("", 0);
+    if (!enabled) {
+      return info;
+    }
+
+    info.headerValue = _WebSocketImpl.PER_MESSAGE_DEFLATE;
+
+    if (clientNoContextTakeover &&
+        (requested == null ||
+            (requested != null &&
+                requested.parameters.containsKey(_clientNoContextTakeover)))) {
+      info.headerValue += "; client_no_context_takeover";
+    }
+
+    if (serverNoContextTakeover &&
+        (requested == null ||
+            (requested != null &&
+                requested.parameters.containsKey(_serverNoContextTakeover)))) {
+      info.headerValue += "; server_no_context_takeover";
+    }
+
+    var headerList = _createServerResponseHeader(requested);
+    info.headerValue += headerList.headerValue;
+    info.maxWindowBits = headerList.maxWindowBits;
+
+    info.headerValue +=
+        _createClientRequestHeader(requested, info.maxWindowBits);
+
+    return info;
+  }
+}
+
+/**
+ * The [WebSocketTransformer] provides the ability to upgrade a
+ * [HttpRequest] to a [WebSocket] connection. It supports both
+ * upgrading a single [HttpRequest] and upgrading a stream of
+ * [HttpRequest]s.
+ *
+ * To upgrade a single [HttpRequest] use the static [upgrade] method.
+ *
+ *     HttpServer server;
+ *     server.listen((request) {
+ *       if (...) {
+ *         WebSocketTransformer.upgrade(request).then((websocket) {
+ *           ...
+ *         });
+ *       } else {
+ *         // Do normal HTTP request processing.
+ *       }
+ *     });
+ *
+ * To transform a stream of [HttpRequest] events as it implements a
+ * stream transformer that transforms a stream of HttpRequest into a
+ * stream of WebSockets by upgrading each HttpRequest from the HTTP or
+ * HTTPS server, to the WebSocket protocol.
+ *
+ *     server.transform(new WebSocketTransformer()).listen((webSocket) => ...);
+ *
+ * This transformer strives to implement WebSockets as specified by RFC6455.
+ */
+abstract class WebSocketTransformer
+    implements StreamTransformer<HttpRequest, WebSocket> {
+  /**
+   * Create a new [WebSocketTransformer].
+   *
+   * If [protocolSelector] is provided, [protocolSelector] will be called to
+   * select what protocol to use, if any were provided by the client.
+   * [protocolSelector] is should return either a [String] or a [Future]
+   * completing with a [String]. The [String] must exist in the list of
+   * protocols.
+   *
+   * If [compression] is provided, the [WebSocket] created will be configured
+   * to negotiate with the specified [CompressionOptions]. If none is specified
+   * then the [WebSocket] will be created with the default [CompressionOptions].
+   */
+  factory WebSocketTransformer(
+      {/*String|Future<String>*/ protocolSelector(List<String> protocols),
+      CompressionOptions compression: CompressionOptions.compressionDefault}) {
+    return new _WebSocketTransformerImpl(protocolSelector, compression);
+  }
+
+  /**
+   * Upgrades a [HttpRequest] to a [WebSocket] connection. If the
+   * request is not a valid WebSocket upgrade request an HTTP response
+   * with status code 500 will be returned. Otherwise the returned
+   * future will complete with the [WebSocket] when the upgrade process
+   * is complete.
+   *
+   * If [protocolSelector] is provided, [protocolSelector] will be called to
+   * select what protocol to use, if any were provided by the client.
+   * [protocolSelector] is should return either a [String] or a [Future]
+   * completing with a [String]. The [String] must exist in the list of
+   * protocols.
+   *
+   * If [compression] is provided, the [WebSocket] created will be configured
+   * to negotiate with the specified [CompressionOptions]. If none is specified
+   * then the [WebSocket] will be created with the default [CompressionOptions].
+   */
+  static Future<WebSocket> upgrade(HttpRequest request,
+      {protocolSelector(List<String> protocols),
+      CompressionOptions compression: CompressionOptions.compressionDefault}) {
+    return _WebSocketTransformerImpl._upgrade(
+        request, protocolSelector, compression);
+  }
+
+  /**
+   * Checks whether the request is a valid WebSocket upgrade request.
+   */
+  static bool isUpgradeRequest(HttpRequest request) {
+    return _WebSocketTransformerImpl._isUpgradeRequest(request);
+  }
+}
+
+/**
+ * A two-way HTTP communication object for client or server applications.
+ *
+ * The stream exposes the messages received. A text message will be of type
+ * `String` and a binary message will be of type `List<int>`.
+ */
+abstract class WebSocket
+    implements
+        Stream<dynamic /*String|List<int>*/ >,
+        StreamSink<dynamic /*String|List<int>*/ > {
+  /**
+   * Possible states of the connection.
+   */
+  static const int connecting = 0;
+  static const int open = 1;
+  static const int closing = 2;
+  static const int closed = 3;
+
+  @Deprecated("Use connecting instead")
+  static const int CONNECTING = connecting;
+  @Deprecated("Use open instead")
+  static const int OPEN = open;
+  @Deprecated("Use closing instead")
+  static const int CLOSING = closing;
+  @Deprecated("Use closed instead")
+  static const int CLOSED = closed;
+
+  /**
+   * Set and get the interval for sending ping signals. If a ping message is not
+   * answered by a pong message from the peer, the `WebSocket` is assumed
+   * disconnected and the connection is closed with a
+   * [WebSocketStatus.GOING_AWAY] close code. When a ping signal is sent, the
+   * pong message must be received within [pingInterval].
+   *
+   * There are never two outstanding pings at any given time, and the next ping
+   * timer starts when the pong is received.
+   *
+   * Set the [pingInterval] to `null` to disable sending ping messages.
+   *
+   * The default value is `null`.
+   */
+  Duration pingInterval;
+
+  /**
+   * Create a new WebSocket connection. The URL supplied in [url]
+   * must use the scheme `ws` or `wss`.
+   *
+   * The [protocols] argument is specifying the subprotocols the
+   * client is willing to speak.
+   *
+   * The [headers] argument is specifying additional HTTP headers for
+   * setting up the connection. This would typically be the `Origin`
+   * header and potentially cookies. The keys of the map are the header
+   * fields and the values are either String or List<String>.
+   *
+   * If [headers] is provided, there are a number of headers
+   * which are controlled by the WebSocket connection process. These
+   * headers are:
+   *
+   *   - `connection`
+   *   - `sec-websocket-key`
+   *   - `sec-websocket-protocol`
+   *   - `sec-websocket-version`
+   *   - `upgrade`
+   *
+   * If any of these are passed in the `headers` map they will be ignored.
+   *
+   * If the `url` contains user information this will be passed as basic
+   * authentication when setting up the connection.
+   */
+  static Future<WebSocket> connect(String url,
+          {Iterable<String> protocols,
+          Map<String, dynamic> headers,
+          CompressionOptions compression:
+              CompressionOptions.compressionDefault}) =>
+      _WebSocketImpl.connect(url, protocols, headers, compression: compression);
+
+  @Deprecated('This constructor will be removed in Dart 2.0. Use `implements`'
+      ' instead of `extends` if implementing this abstract class.')
+  WebSocket();
+
+  /**
+   * Creates a WebSocket from an already-upgraded socket.
+   *
+   * The initial WebSocket handshake must have occurred prior to this call. A
+   * WebSocket client can automatically perform the handshake using
+   * [WebSocket.connect], while a server can do so using
+   * [WebSocketTransformer.upgrade]. To manually upgrade an [HttpRequest],
+   * [HttpResponse.detachSocket] may be called.
+   *
+   * [protocol] should be the protocol negotiated by this handshake, if any.
+   *
+   * [serverSide] must be passed explicitly. If it's `false`, the WebSocket will
+   * act as the client and mask the messages it sends. If it's `true`, it will
+   * act as the server and will not mask its messages.
+   *
+   * If [compression] is provided, the [WebSocket] created will be configured
+   * to negotiate with the specified [CompressionOptions]. If none is specified
+   * then the [WebSocket] will be created with the default [CompressionOptions].
+   */
+  factory WebSocket.fromUpgradedSocket(Socket socket,
+      {String protocol,
+      bool serverSide,
+      CompressionOptions compression: CompressionOptions.compressionDefault}) {
+    if (serverSide == null) {
+      throw new ArgumentError("The serverSide argument must be passed "
+          "explicitly to WebSocket.fromUpgradedSocket.");
+    }
+    return new _WebSocketImpl._fromSocket(
+        socket, protocol, compression, serverSide);
+  }
+
+  /**
+   * Returns the current state of the connection.
+   */
+  int get readyState;
+
+  /**
+   * The extensions property is initially the empty string. After the
+   * WebSocket connection is established this string reflects the
+   * extensions used by the server.
+   */
+  String get extensions;
+
+  /**
+   * The protocol property is initially the empty string. After the
+   * WebSocket connection is established the value is the subprotocol
+   * selected by the server. If no subprotocol is negotiated the
+   * value will remain [:null:].
+   */
+  String get protocol;
+
+  /**
+   * The close code set when the WebSocket connection is closed. If
+   * there is no close code available this property will be [:null:]
+   */
+  int get closeCode;
+
+  /**
+   * The close reason set when the WebSocket connection is closed. If
+   * there is no close reason available this property will be [:null:]
+   */
+  String get closeReason;
+
+  /**
+   * Closes the WebSocket connection. Set the optional [code] and [reason]
+   * arguments to send close information to the remote peer. If they are
+   * omitted, the peer will see [WebSocketStatus.NO_STATUS_RECEIVED] code
+   * with no reason.
+   */
+  Future close([int code, String reason]);
+
+  /**
+   * Sends data on the WebSocket connection. The data in [data] must
+   * be either a `String`, or a `List<int>` holding bytes.
+   */
+  void add(/*String|List<int>*/ data);
+
+  /**
+   * Sends data from a stream on WebSocket connection. Each data event from
+   * [stream] will be send as a single WebSocket frame. The data from [stream]
+   * must be either `String`s, or `List<int>`s holding bytes.
+   */
+  Future addStream(Stream stream);
+
+  /**
+   * Sends a text message with the text represented by [bytes].
+   *
+   * The [bytes] should be valid UTF-8 encoded Unicode characters. If they are
+   * not, the receiving end will close the connection.
+   */
+  void addUtf8Text(List<int> bytes);
+
+  /**
+   * Gets the user agent used for WebSocket connections.
+   */
+  static String get userAgent => _WebSocketImpl.userAgent;
+
+  /**
+   * Sets the user agent to use for WebSocket connections.
+   */
+  static set userAgent(String userAgent) {
+    _WebSocketImpl.userAgent = userAgent;
+  }
+}
+
+class WebSocketException implements IOException {
+  final String message;
+
+  const WebSocketException([this.message = ""]);
+
+  String toString() => "WebSocketException: $message";
+}
diff --git a/sdk_nnbd/lib/_http/websocket_impl.dart b/sdk_nnbd/lib/_http/websocket_impl.dart
new file mode 100644
index 0000000..8750ccc
--- /dev/null
+++ b/sdk_nnbd/lib/_http/websocket_impl.dart
@@ -0,0 +1,1317 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart._http;
+
+const String _webSocketGUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
+const String _clientNoContextTakeover = "client_no_context_takeover";
+const String _serverNoContextTakeover = "server_no_context_takeover";
+const String _clientMaxWindowBits = "client_max_window_bits";
+const String _serverMaxWindowBits = "server_max_window_bits";
+
+// Matches _WebSocketOpcode.
+class _WebSocketMessageType {
+  static const int NONE = 0;
+  static const int TEXT = 1;
+  static const int BINARY = 2;
+}
+
+class _WebSocketOpcode {
+  static const int CONTINUATION = 0;
+  static const int TEXT = 1;
+  static const int BINARY = 2;
+  static const int RESERVED_3 = 3;
+  static const int RESERVED_4 = 4;
+  static const int RESERVED_5 = 5;
+  static const int RESERVED_6 = 6;
+  static const int RESERVED_7 = 7;
+  static const int CLOSE = 8;
+  static const int PING = 9;
+  static const int PONG = 10;
+  static const int RESERVED_B = 11;
+  static const int RESERVED_C = 12;
+  static const int RESERVED_D = 13;
+  static const int RESERVED_E = 14;
+  static const int RESERVED_F = 15;
+}
+
+class _EncodedString {
+  final List<int> bytes;
+  _EncodedString(this.bytes);
+}
+
+/**
+ *  Stores the header and integer value derived from negotiation of
+ *  client_max_window_bits and server_max_window_bits. headerValue will be
+ *  set in the Websocket response headers.
+ */
+class _CompressionMaxWindowBits {
+  String headerValue;
+  int maxWindowBits;
+  _CompressionMaxWindowBits([this.headerValue, this.maxWindowBits]);
+  String toString() => headerValue;
+}
+
+/**
+ * The web socket protocol transformer handles the protocol byte stream
+ * which is supplied through the `handleData`. As the protocol is processed,
+ * it'll output frame data as either a List<int> or String.
+ *
+ * Important information about usage: Be sure you use cancelOnError, so the
+ * socket will be closed when the processor encounter an error. Not using it
+ * will lead to undefined behaviour.
+ */
+class _WebSocketProtocolTransformer extends StreamTransformerBase<List<int>,
+        dynamic /*List<int>|_WebSocketPing|_WebSocketPong*/ >
+    implements EventSink<List<int>> {
+  static const int START = 0;
+  static const int LEN_FIRST = 1;
+  static const int LEN_REST = 2;
+  static const int MASK = 3;
+  static const int PAYLOAD = 4;
+  static const int CLOSED = 5;
+  static const int FAILURE = 6;
+  static const int FIN = 0x80;
+  static const int RSV1 = 0x40;
+  static const int RSV2 = 0x20;
+  static const int RSV3 = 0x10;
+  static const int OPCODE = 0xF;
+
+  int _state = START;
+  bool _fin = false;
+  bool _compressed = false;
+  int _opcode = -1;
+  int _len = -1;
+  bool _masked = false;
+  int _remainingLenBytes = -1;
+  int _remainingMaskingKeyBytes = 4;
+  int _remainingPayloadBytes = -1;
+  int _unmaskingIndex = 0;
+  int _currentMessageType = _WebSocketMessageType.NONE;
+  int closeCode = WebSocketStatus.NO_STATUS_RECEIVED;
+  String closeReason = "";
+
+  EventSink<dynamic /*List<int>|_WebSocketPing|_WebSocketPong*/ > _eventSink;
+
+  final bool _serverSide;
+  final List _maskingBytes = new List(4);
+  final BytesBuilder _payload = new BytesBuilder(copy: false);
+
+  _WebSocketPerMessageDeflate _deflate;
+  _WebSocketProtocolTransformer([this._serverSide = false, this._deflate]);
+
+  Stream<dynamic /*List<int>|_WebSocketPing|_WebSocketPong*/ > bind(
+      Stream<List<int>> stream) {
+    return new Stream.eventTransformed(stream, (EventSink eventSink) {
+      if (_eventSink != null) {
+        throw new StateError("WebSocket transformer already used.");
+      }
+      _eventSink = eventSink;
+      return this;
+    });
+  }
+
+  void addError(Object error, [StackTrace stackTrace]) {
+    _eventSink.addError(error, stackTrace);
+  }
+
+  void close() {
+    _eventSink.close();
+  }
+
+  /**
+   * Process data received from the underlying communication channel.
+   */
+  void add(List<int> bytes) {
+    var buffer = bytes is Uint8List ? bytes : new Uint8List.fromList(bytes);
+    int index = 0;
+    int lastIndex = buffer.length;
+    if (_state == CLOSED) {
+      throw new WebSocketException("Data on closed connection");
+    }
+    if (_state == FAILURE) {
+      throw new WebSocketException("Data on failed connection");
+    }
+    while ((index < lastIndex) && _state != CLOSED && _state != FAILURE) {
+      int byte = buffer[index];
+      if (_state <= LEN_REST) {
+        if (_state == START) {
+          _fin = (byte & FIN) != 0;
+
+          if ((byte & (RSV2 | RSV3)) != 0) {
+            // The RSV2, RSV3 bits must both be zero.
+            throw new WebSocketException("Protocol error");
+          }
+
+          _opcode = (byte & OPCODE);
+
+          if (_opcode != _WebSocketOpcode.CONTINUATION) {
+            if ((byte & RSV1) != 0) {
+              _compressed = true;
+            } else {
+              _compressed = false;
+            }
+          }
+
+          if (_opcode <= _WebSocketOpcode.BINARY) {
+            if (_opcode == _WebSocketOpcode.CONTINUATION) {
+              if (_currentMessageType == _WebSocketMessageType.NONE) {
+                throw new WebSocketException("Protocol error");
+              }
+            } else {
+              assert(_opcode == _WebSocketOpcode.TEXT ||
+                  _opcode == _WebSocketOpcode.BINARY);
+              if (_currentMessageType != _WebSocketMessageType.NONE) {
+                throw new WebSocketException("Protocol error");
+              }
+              _currentMessageType = _opcode;
+            }
+          } else if (_opcode >= _WebSocketOpcode.CLOSE &&
+              _opcode <= _WebSocketOpcode.PONG) {
+            // Control frames cannot be fragmented.
+            if (!_fin) throw new WebSocketException("Protocol error");
+          } else {
+            throw new WebSocketException("Protocol error");
+          }
+          _state = LEN_FIRST;
+        } else if (_state == LEN_FIRST) {
+          _masked = (byte & 0x80) != 0;
+          _len = byte & 0x7F;
+          if (_isControlFrame() && _len > 125) {
+            throw new WebSocketException("Protocol error");
+          }
+          if (_len == 126) {
+            _len = 0;
+            _remainingLenBytes = 2;
+            _state = LEN_REST;
+          } else if (_len == 127) {
+            _len = 0;
+            _remainingLenBytes = 8;
+            _state = LEN_REST;
+          } else {
+            assert(_len < 126);
+            _lengthDone();
+          }
+        } else {
+          assert(_state == LEN_REST);
+          _len = _len << 8 | byte;
+          _remainingLenBytes--;
+          if (_remainingLenBytes == 0) {
+            _lengthDone();
+          }
+        }
+      } else {
+        if (_state == MASK) {
+          _maskingBytes[4 - _remainingMaskingKeyBytes--] = byte;
+          if (_remainingMaskingKeyBytes == 0) {
+            _maskDone();
+          }
+        } else {
+          assert(_state == PAYLOAD);
+          // The payload is not handled one byte at a time but in blocks.
+          int payloadLength = min(lastIndex - index, _remainingPayloadBytes);
+          _remainingPayloadBytes -= payloadLength;
+          // Unmask payload if masked.
+          if (_masked) {
+            _unmask(index, payloadLength, buffer);
+          }
+          // Control frame and data frame share _payloads.
+          _payload.add(new Uint8List.view(buffer.buffer, index, payloadLength));
+          index += payloadLength;
+          if (_isControlFrame()) {
+            if (_remainingPayloadBytes == 0) _controlFrameEnd();
+          } else {
+            if (_currentMessageType != _WebSocketMessageType.TEXT &&
+                _currentMessageType != _WebSocketMessageType.BINARY) {
+              throw new WebSocketException("Protocol error");
+            }
+            if (_remainingPayloadBytes == 0) _messageFrameEnd();
+          }
+
+          // Hack - as we always do index++ below.
+          index--;
+        }
+      }
+
+      // Move to the next byte.
+      index++;
+    }
+  }
+
+  void _unmask(int index, int length, Uint8List buffer) {
+    const int BLOCK_SIZE = 16;
+    // Skip Int32x4-version if message is small.
+    if (length >= BLOCK_SIZE) {
+      // Start by aligning to 16 bytes.
+      final int startOffset = BLOCK_SIZE - (index & 15);
+      final int end = index + startOffset;
+      for (int i = index; i < end; i++) {
+        buffer[i] ^= _maskingBytes[_unmaskingIndex++ & 3];
+      }
+      index += startOffset;
+      length -= startOffset;
+      final int blockCount = length ~/ BLOCK_SIZE;
+      if (blockCount > 0) {
+        // Create mask block.
+        int mask = 0;
+        for (int i = 3; i >= 0; i--) {
+          mask = (mask << 8) | _maskingBytes[(_unmaskingIndex + i) & 3];
+        }
+        Int32x4 blockMask = new Int32x4(mask, mask, mask, mask);
+        Int32x4List blockBuffer =
+            new Int32x4List.view(buffer.buffer, index, blockCount);
+        for (int i = 0; i < blockBuffer.length; i++) {
+          blockBuffer[i] ^= blockMask;
+        }
+        final int bytes = blockCount * BLOCK_SIZE;
+        index += bytes;
+        length -= bytes;
+      }
+    }
+    // Handle end.
+    final int end = index + length;
+    for (int i = index; i < end; i++) {
+      buffer[i] ^= _maskingBytes[_unmaskingIndex++ & 3];
+    }
+  }
+
+  void _lengthDone() {
+    if (_masked) {
+      if (!_serverSide) {
+        throw new WebSocketException("Received masked frame from server");
+      }
+      _state = MASK;
+    } else {
+      if (_serverSide) {
+        throw new WebSocketException("Received unmasked frame from client");
+      }
+      _remainingPayloadBytes = _len;
+      _startPayload();
+    }
+  }
+
+  void _maskDone() {
+    _remainingPayloadBytes = _len;
+    _startPayload();
+  }
+
+  void _startPayload() {
+    // If there is no actual payload perform perform callbacks without
+    // going through the PAYLOAD state.
+    if (_remainingPayloadBytes == 0) {
+      if (_isControlFrame()) {
+        switch (_opcode) {
+          case _WebSocketOpcode.CLOSE:
+            _state = CLOSED;
+            _eventSink.close();
+            break;
+          case _WebSocketOpcode.PING:
+            _eventSink.add(new _WebSocketPing());
+            break;
+          case _WebSocketOpcode.PONG:
+            _eventSink.add(new _WebSocketPong());
+            break;
+        }
+        _prepareForNextFrame();
+      } else {
+        _messageFrameEnd();
+      }
+    } else {
+      _state = PAYLOAD;
+    }
+  }
+
+  void _messageFrameEnd() {
+    if (_fin) {
+      var bytes = _payload.takeBytes();
+      if (_deflate != null && _compressed) {
+        bytes = _deflate.processIncomingMessage(bytes);
+      }
+
+      switch (_currentMessageType) {
+        case _WebSocketMessageType.TEXT:
+          _eventSink.add(utf8.decode(bytes));
+          break;
+        case _WebSocketMessageType.BINARY:
+          _eventSink.add(bytes);
+          break;
+      }
+      _currentMessageType = _WebSocketMessageType.NONE;
+    }
+    _prepareForNextFrame();
+  }
+
+  void _controlFrameEnd() {
+    switch (_opcode) {
+      case _WebSocketOpcode.CLOSE:
+        closeCode = WebSocketStatus.NO_STATUS_RECEIVED;
+        var payload = _payload.takeBytes();
+        if (payload.length > 0) {
+          if (payload.length == 1) {
+            throw new WebSocketException("Protocol error");
+          }
+          closeCode = payload[0] << 8 | payload[1];
+          if (closeCode == WebSocketStatus.NO_STATUS_RECEIVED) {
+            throw new WebSocketException("Protocol error");
+          }
+          if (payload.length > 2) {
+            closeReason = utf8.decode(payload.sublist(2));
+          }
+        }
+        _state = CLOSED;
+        _eventSink.close();
+        break;
+
+      case _WebSocketOpcode.PING:
+        _eventSink.add(new _WebSocketPing(_payload.takeBytes()));
+        break;
+
+      case _WebSocketOpcode.PONG:
+        _eventSink.add(new _WebSocketPong(_payload.takeBytes()));
+        break;
+    }
+    _prepareForNextFrame();
+  }
+
+  bool _isControlFrame() {
+    return _opcode == _WebSocketOpcode.CLOSE ||
+        _opcode == _WebSocketOpcode.PING ||
+        _opcode == _WebSocketOpcode.PONG;
+  }
+
+  void _prepareForNextFrame() {
+    if (_state != CLOSED && _state != FAILURE) _state = START;
+    _fin = false;
+    _opcode = -1;
+    _len = -1;
+    _remainingLenBytes = -1;
+    _remainingMaskingKeyBytes = 4;
+    _remainingPayloadBytes = -1;
+    _unmaskingIndex = 0;
+  }
+}
+
+class _WebSocketPing {
+  final List<int> payload;
+  _WebSocketPing([this.payload = null]);
+}
+
+class _WebSocketPong {
+  final List<int> payload;
+  _WebSocketPong([this.payload = null]);
+}
+
+typedef /*String|Future<String>*/ _ProtocolSelector(List<String> protocols);
+
+class _WebSocketTransformerImpl
+    extends StreamTransformerBase<HttpRequest, WebSocket>
+    implements WebSocketTransformer {
+  final StreamController<WebSocket> _controller =
+      new StreamController<WebSocket>(sync: true);
+  final _ProtocolSelector _protocolSelector;
+  final CompressionOptions _compression;
+
+  _WebSocketTransformerImpl(this._protocolSelector, this._compression);
+
+  Stream<WebSocket> bind(Stream<HttpRequest> stream) {
+    stream.listen((request) {
+      _upgrade(request, _protocolSelector, _compression)
+          .then((WebSocket webSocket) => _controller.add(webSocket))
+          .catchError(_controller.addError);
+    }, onDone: () {
+      _controller.close();
+    });
+
+    return _controller.stream;
+  }
+
+  static List<String> _tokenizeFieldValue(String headerValue) {
+    List<String> tokens = new List<String>();
+    int start = 0;
+    int index = 0;
+    while (index < headerValue.length) {
+      if (headerValue[index] == ",") {
+        tokens.add(headerValue.substring(start, index));
+        start = index + 1;
+      } else if (headerValue[index] == " " || headerValue[index] == "\t") {
+        start++;
+      }
+      index++;
+    }
+    tokens.add(headerValue.substring(start, index));
+    return tokens;
+  }
+
+  static Future<WebSocket> _upgrade(HttpRequest request,
+      _ProtocolSelector _protocolSelector, CompressionOptions compression) {
+    var response = request.response;
+    if (!_isUpgradeRequest(request)) {
+      // Send error response.
+      response
+        ..statusCode = HttpStatus.badRequest
+        ..close();
+      return new Future.error(
+          new WebSocketException("Invalid WebSocket upgrade request"));
+    }
+
+    Future<WebSocket> upgrade(String protocol) {
+      // Send the upgrade response.
+      response
+        ..statusCode = HttpStatus.switchingProtocols
+        ..headers.add(HttpHeaders.connectionHeader, "Upgrade")
+        ..headers.add(HttpHeaders.upgradeHeader, "websocket");
+      String key = request.headers.value("Sec-WebSocket-Key");
+      _SHA1 sha1 = new _SHA1();
+      sha1.add("$key$_webSocketGUID".codeUnits);
+      String accept = _CryptoUtils.bytesToBase64(sha1.close());
+      response.headers.add("Sec-WebSocket-Accept", accept);
+      if (protocol != null) {
+        response.headers.add("Sec-WebSocket-Protocol", protocol);
+      }
+
+      var deflate = _negotiateCompression(request, response, compression);
+
+      response.headers.contentLength = 0;
+      return response.detachSocket().then<WebSocket>((socket) =>
+          new _WebSocketImpl._fromSocket(
+              socket, protocol, compression, true, deflate));
+    }
+
+    var protocols = request.headers['Sec-WebSocket-Protocol'];
+    if (protocols != null && _protocolSelector != null) {
+      // The suggested protocols can be spread over multiple lines, each
+      // consisting of multiple protocols. To unify all of them, first join
+      // the lists with ', ' and then tokenize.
+      protocols = _tokenizeFieldValue(protocols.join(', '));
+      return new Future<String>(() => _protocolSelector(protocols))
+          .then<String>((protocol) {
+        if (protocols.indexOf(protocol) < 0) {
+          throw new WebSocketException(
+              "Selected protocol is not in the list of available protocols");
+        }
+        return protocol;
+      }).catchError((error) {
+        response
+          ..statusCode = HttpStatus.internalServerError
+          ..close();
+        throw error;
+      }).then<WebSocket>(upgrade);
+    } else {
+      return upgrade(null);
+    }
+  }
+
+  static _WebSocketPerMessageDeflate _negotiateCompression(HttpRequest request,
+      HttpResponse response, CompressionOptions compression) {
+    var extensionHeader = request.headers.value("Sec-WebSocket-Extensions");
+
+    extensionHeader ??= "";
+
+    var hv = HeaderValue.parse(extensionHeader, valueSeparator: ',');
+    if (compression.enabled && hv.value == _WebSocketImpl.PER_MESSAGE_DEFLATE) {
+      var info = compression._createHeader(hv);
+
+      response.headers.add("Sec-WebSocket-Extensions", info.headerValue);
+      var serverNoContextTakeover =
+          (hv.parameters.containsKey(_serverNoContextTakeover) &&
+              compression.serverNoContextTakeover);
+      var clientNoContextTakeover =
+          (hv.parameters.containsKey(_clientNoContextTakeover) &&
+              compression.clientNoContextTakeover);
+      var deflate = new _WebSocketPerMessageDeflate(
+          serverNoContextTakeover: serverNoContextTakeover,
+          clientNoContextTakeover: clientNoContextTakeover,
+          serverMaxWindowBits: info.maxWindowBits,
+          clientMaxWindowBits: info.maxWindowBits,
+          serverSide: true);
+
+      return deflate;
+    }
+
+    return null;
+  }
+
+  static bool _isUpgradeRequest(HttpRequest request) {
+    if (request.method != "GET") {
+      return false;
+    }
+    if (request.headers[HttpHeaders.connectionHeader] == null) {
+      return false;
+    }
+    bool isUpgrade = false;
+    request.headers[HttpHeaders.connectionHeader].forEach((String value) {
+      if (value.toLowerCase() == "upgrade") isUpgrade = true;
+    });
+    if (!isUpgrade) return false;
+    String upgrade = request.headers.value(HttpHeaders.upgradeHeader);
+    if (upgrade == null || upgrade.toLowerCase() != "websocket") {
+      return false;
+    }
+    String version = request.headers.value("Sec-WebSocket-Version");
+    if (version == null || version != "13") {
+      return false;
+    }
+    String key = request.headers.value("Sec-WebSocket-Key");
+    if (key == null) {
+      return false;
+    }
+    return true;
+  }
+}
+
+class _WebSocketPerMessageDeflate {
+  bool serverNoContextTakeover;
+  bool clientNoContextTakeover;
+  int clientMaxWindowBits;
+  int serverMaxWindowBits;
+  bool serverSide;
+
+  RawZLibFilter decoder;
+  RawZLibFilter encoder;
+
+  _WebSocketPerMessageDeflate(
+      {this.clientMaxWindowBits: _WebSocketImpl.DEFAULT_WINDOW_BITS,
+      this.serverMaxWindowBits: _WebSocketImpl.DEFAULT_WINDOW_BITS,
+      this.serverNoContextTakeover: false,
+      this.clientNoContextTakeover: false,
+      this.serverSide: false});
+
+  void _ensureDecoder() {
+    if (decoder == null) {
+      decoder = new RawZLibFilter.inflateFilter(
+          windowBits: serverSide ? clientMaxWindowBits : serverMaxWindowBits,
+          raw: true);
+    }
+  }
+
+  void _ensureEncoder() {
+    if (encoder == null) {
+      encoder = new RawZLibFilter.deflateFilter(
+          windowBits: serverSide ? serverMaxWindowBits : clientMaxWindowBits,
+          raw: true);
+    }
+  }
+
+  Uint8List processIncomingMessage(List<int> msg) {
+    _ensureDecoder();
+
+    var data = <int>[];
+    data.addAll(msg);
+    data.addAll(const [0x00, 0x00, 0xff, 0xff]);
+
+    decoder.process(data, 0, data.length);
+    var result = <int>[];
+    List<int> out;
+
+    while ((out = decoder.processed()) != null) {
+      result.addAll(out);
+    }
+
+    if ((serverSide && clientNoContextTakeover) ||
+        (!serverSide && serverNoContextTakeover)) {
+      decoder = null;
+    }
+
+    return new Uint8List.fromList(result);
+  }
+
+  List<int> processOutgoingMessage(List<int> msg) {
+    _ensureEncoder();
+    var result = <int>[];
+    Uint8List buffer;
+
+    if (msg is! Uint8List) {
+      for (var i = 0; i < msg.length; i++) {
+        if (msg[i] < 0 || 255 < msg[i]) {
+          throw new ArgumentError("List element is not a byte value "
+              "(value ${msg[i]} at index $i)");
+        }
+      }
+      buffer = new Uint8List.fromList(msg);
+    } else {
+      buffer = msg;
+    }
+
+    encoder.process(buffer, 0, buffer.length);
+
+    List<int> out;
+    while ((out = encoder.processed()) != null) {
+      result.addAll(out);
+    }
+
+    if ((!serverSide && clientNoContextTakeover) ||
+        (serverSide && serverNoContextTakeover)) {
+      encoder = null;
+    }
+
+    if (result.length > 4) {
+      result = result.sublist(0, result.length - 4);
+    }
+
+    // RFC 7692 7.2.3.6. "Generating an Empty Fragment" says that if the
+    // compression library doesn't generate any data when the bufer is empty,
+    // then an empty uncompressed deflate block is used for this purpose. The
+    // 0x00 block has the BFINAL header bit set to 0 and the BTYPE header set to
+    // 00 along with 5 bits of padding. This block decodes to zero bytes.
+    if (result.length == 0) {
+      return [0x00];
+    }
+
+    return result;
+  }
+}
+
+// TODO(ajohnsen): Make this transformer reusable.
+class _WebSocketOutgoingTransformer
+    extends StreamTransformerBase<dynamic, List<int>> implements EventSink {
+  final _WebSocketImpl webSocket;
+  EventSink<List<int>> _eventSink;
+
+  _WebSocketPerMessageDeflate _deflateHelper;
+
+  _WebSocketOutgoingTransformer(this.webSocket) {
+    _deflateHelper = webSocket._deflate;
+  }
+
+  Stream<List<int>> bind(Stream stream) {
+    return new Stream<List<int>>.eventTransformed(stream,
+        (EventSink<List<int>> eventSink) {
+      if (_eventSink != null) {
+        throw new StateError("WebSocket transformer already used");
+      }
+      _eventSink = eventSink;
+      return this;
+    });
+  }
+
+  void add(message) {
+    if (message is _WebSocketPong) {
+      addFrame(_WebSocketOpcode.PONG, message.payload);
+      return;
+    }
+    if (message is _WebSocketPing) {
+      addFrame(_WebSocketOpcode.PING, message.payload);
+      return;
+    }
+    List<int> data;
+    int opcode;
+    if (message != null) {
+      if (message is String) {
+        opcode = _WebSocketOpcode.TEXT;
+        data = utf8.encode(message);
+      } else if (message is List<int>) {
+        opcode = _WebSocketOpcode.BINARY;
+        data = message;
+      } else if (message is _EncodedString) {
+        opcode = _WebSocketOpcode.TEXT;
+        data = message.bytes;
+      } else {
+        throw new ArgumentError(message);
+      }
+
+      if (_deflateHelper != null) {
+        data = _deflateHelper.processOutgoingMessage(data);
+      }
+    } else {
+      opcode = _WebSocketOpcode.TEXT;
+    }
+    addFrame(opcode, data);
+  }
+
+  void addError(Object error, [StackTrace stackTrace]) {
+    _eventSink.addError(error, stackTrace);
+  }
+
+  void close() {
+    int code = webSocket._outCloseCode;
+    String reason = webSocket._outCloseReason;
+    List<int> data;
+    if (code != null) {
+      data = new List<int>();
+      data.add((code >> 8) & 0xFF);
+      data.add(code & 0xFF);
+      if (reason != null) {
+        data.addAll(utf8.encode(reason));
+      }
+    }
+    addFrame(_WebSocketOpcode.CLOSE, data);
+    _eventSink.close();
+  }
+
+  void addFrame(int opcode, List<int> data) {
+    createFrame(
+            opcode,
+            data,
+            webSocket._serverSide,
+            _deflateHelper != null &&
+                (opcode == _WebSocketOpcode.TEXT ||
+                    opcode == _WebSocketOpcode.BINARY))
+        .forEach((e) {
+      _eventSink.add(e);
+    });
+  }
+
+  static Iterable<List<int>> createFrame(
+      int opcode, List<int> data, bool serverSide, bool compressed) {
+    bool mask = !serverSide; // Masking not implemented for server.
+    int dataLength = data == null ? 0 : data.length;
+    // Determine the header size.
+    int headerSize = (mask) ? 6 : 2;
+    if (dataLength > 65535) {
+      headerSize += 8;
+    } else if (dataLength > 125) {
+      headerSize += 2;
+    }
+    Uint8List header = new Uint8List(headerSize);
+    int index = 0;
+
+    // Set FIN and opcode.
+    var hoc = _WebSocketProtocolTransformer.FIN |
+        (compressed ? _WebSocketProtocolTransformer.RSV1 : 0) |
+        (opcode & _WebSocketProtocolTransformer.OPCODE);
+
+    header[index++] = hoc;
+    // Determine size and position of length field.
+    int lengthBytes = 1;
+    if (dataLength > 65535) {
+      header[index++] = 127;
+      lengthBytes = 8;
+    } else if (dataLength > 125) {
+      header[index++] = 126;
+      lengthBytes = 2;
+    }
+    // Write the length in network byte order into the header.
+    for (int i = 0; i < lengthBytes; i++) {
+      header[index++] = dataLength >> (((lengthBytes - 1) - i) * 8) & 0xFF;
+    }
+    if (mask) {
+      header[1] |= 1 << 7;
+      var maskBytes = _CryptoUtils.getRandomBytes(4);
+      header.setRange(index, index + 4, maskBytes);
+      index += 4;
+      if (data != null) {
+        Uint8List list;
+        // If this is a text message just do the masking inside the
+        // encoded data.
+        if (opcode == _WebSocketOpcode.TEXT && data is Uint8List) {
+          list = data;
+        } else {
+          if (data is Uint8List) {
+            list = new Uint8List.fromList(data);
+          } else {
+            list = new Uint8List(data.length);
+            for (int i = 0; i < data.length; i++) {
+              if (data[i] < 0 || 255 < data[i]) {
+                throw new ArgumentError("List element is not a byte value "
+                    "(value ${data[i]} at index $i)");
+              }
+              list[i] = data[i];
+            }
+          }
+        }
+        const int BLOCK_SIZE = 16;
+        int blockCount = list.length ~/ BLOCK_SIZE;
+        if (blockCount > 0) {
+          // Create mask block.
+          int mask = 0;
+          for (int i = 3; i >= 0; i--) {
+            mask = (mask << 8) | maskBytes[i];
+          }
+          Int32x4 blockMask = new Int32x4(mask, mask, mask, mask);
+          Int32x4List blockBuffer =
+              new Int32x4List.view(list.buffer, 0, blockCount);
+          for (int i = 0; i < blockBuffer.length; i++) {
+            blockBuffer[i] ^= blockMask;
+          }
+        }
+        // Handle end.
+        for (int i = blockCount * BLOCK_SIZE; i < list.length; i++) {
+          list[i] ^= maskBytes[i & 3];
+        }
+        data = list;
+      }
+    }
+    assert(index == headerSize);
+    if (data == null) {
+      return [header];
+    } else {
+      return [header, data];
+    }
+  }
+}
+
+class _WebSocketConsumer implements StreamConsumer {
+  final _WebSocketImpl webSocket;
+  final Socket socket;
+  StreamController _controller;
+  StreamSubscription _subscription;
+  bool _issuedPause = false;
+  bool _closed = false;
+  Completer _closeCompleter = new Completer<WebSocket>();
+  Completer _completer;
+
+  _WebSocketConsumer(this.webSocket, this.socket);
+
+  void _onListen() {
+    if (_subscription != null) {
+      _subscription.cancel();
+    }
+  }
+
+  void _onPause() {
+    if (_subscription != null) {
+      _subscription.pause();
+    } else {
+      _issuedPause = true;
+    }
+  }
+
+  void _onResume() {
+    if (_subscription != null) {
+      _subscription.resume();
+    } else {
+      _issuedPause = false;
+    }
+  }
+
+  void _cancel() {
+    if (_subscription != null) {
+      var subscription = _subscription;
+      _subscription = null;
+      subscription.cancel();
+    }
+  }
+
+  _ensureController() {
+    if (_controller != null) return;
+    _controller = new StreamController(
+        sync: true,
+        onPause: _onPause,
+        onResume: _onResume,
+        onCancel: _onListen);
+    var stream = _controller.stream
+        .transform(new _WebSocketOutgoingTransformer(webSocket));
+    socket.addStream(stream).then((_) {
+      _done();
+      _closeCompleter.complete(webSocket);
+    }, onError: (error, StackTrace stackTrace) {
+      _closed = true;
+      _cancel();
+      if (error is ArgumentError) {
+        if (!_done(error, stackTrace)) {
+          _closeCompleter.completeError(error, stackTrace);
+        }
+      } else {
+        _done();
+        _closeCompleter.complete(webSocket);
+      }
+    });
+  }
+
+  bool _done([error, StackTrace stackTrace]) {
+    if (_completer == null) return false;
+    if (error != null) {
+      _completer.completeError(error, stackTrace);
+    } else {
+      _completer.complete(webSocket);
+    }
+    _completer = null;
+    return true;
+  }
+
+  Future addStream(var stream) {
+    if (_closed) {
+      stream.listen(null).cancel();
+      return new Future.value(webSocket);
+    }
+    _ensureController();
+    _completer = new Completer();
+    _subscription = stream.listen((data) {
+      _controller.add(data);
+    }, onDone: _done, onError: _done, cancelOnError: true);
+    if (_issuedPause) {
+      _subscription.pause();
+      _issuedPause = false;
+    }
+    return _completer.future;
+  }
+
+  Future close() {
+    _ensureController();
+    Future closeSocket() {
+      return socket.close().catchError((_) {}).then((_) => webSocket);
+    }
+
+    _controller.close();
+    return _closeCompleter.future.then((_) => closeSocket());
+  }
+
+  void add(data) {
+    if (_closed) return;
+    _ensureController();
+    // Stop sending message if _controller has been closed.
+    // https://github.com/dart-lang/sdk/issues/37441
+    if (_controller.isClosed) return;
+    _controller.add(data);
+  }
+
+  void closeSocket() {
+    _closed = true;
+    _cancel();
+    close();
+  }
+}
+
+class _WebSocketImpl extends Stream with _ServiceObject implements WebSocket {
+  // Use default Map so we keep order.
+  static Map<int, _WebSocketImpl> _webSockets = new Map<int, _WebSocketImpl>();
+  static const int DEFAULT_WINDOW_BITS = 15;
+  static const String PER_MESSAGE_DEFLATE = "permessage-deflate";
+
+  final String protocol;
+
+  StreamController _controller;
+  StreamSubscription _subscription;
+  StreamSink _sink;
+
+  final _socket;
+  final bool _serverSide;
+  int _readyState = WebSocket.connecting;
+  bool _writeClosed = false;
+  int _closeCode;
+  String _closeReason;
+  Duration _pingInterval;
+  Timer _pingTimer;
+  _WebSocketConsumer _consumer;
+
+  int _outCloseCode;
+  String _outCloseReason;
+  Timer _closeTimer;
+  _WebSocketPerMessageDeflate _deflate;
+
+  static final HttpClient _httpClient = new HttpClient();
+
+  static Future<WebSocket> connect(
+      String url, Iterable<String> protocols, Map<String, dynamic> headers,
+      {CompressionOptions compression: CompressionOptions.compressionDefault}) {
+    Uri uri = Uri.parse(url);
+    if (uri.scheme != "ws" && uri.scheme != "wss") {
+      throw new WebSocketException("Unsupported URL scheme '${uri.scheme}'");
+    }
+
+    Random random = new Random();
+    // Generate 16 random bytes.
+    Uint8List nonceData = new Uint8List(16);
+    for (int i = 0; i < 16; i++) {
+      nonceData[i] = random.nextInt(256);
+    }
+    String nonce = _CryptoUtils.bytesToBase64(nonceData);
+
+    uri = new Uri(
+        scheme: uri.scheme == "wss" ? "https" : "http",
+        userInfo: uri.userInfo,
+        host: uri.host,
+        port: uri.port,
+        path: uri.path,
+        query: uri.query,
+        fragment: uri.fragment);
+    return _httpClient.openUrl("GET", uri).then((request) {
+      if (uri.userInfo != null && !uri.userInfo.isEmpty) {
+        // If the URL contains user information use that for basic
+        // authorization.
+        String auth = _CryptoUtils.bytesToBase64(utf8.encode(uri.userInfo));
+        request.headers.set(HttpHeaders.authorizationHeader, "Basic $auth");
+      }
+      if (headers != null) {
+        headers.forEach((field, value) => request.headers.add(field, value));
+      }
+      // Setup the initial handshake.
+      request.headers
+        ..set(HttpHeaders.connectionHeader, "Upgrade")
+        ..set(HttpHeaders.upgradeHeader, "websocket")
+        ..set("Sec-WebSocket-Key", nonce)
+        ..set("Cache-Control", "no-cache")
+        ..set("Sec-WebSocket-Version", "13");
+      if (protocols != null) {
+        request.headers.add("Sec-WebSocket-Protocol", protocols.toList());
+      }
+
+      if (compression.enabled) {
+        request.headers
+            .add("Sec-WebSocket-Extensions", compression._createHeader());
+      }
+
+      return request.close();
+    }).then((response) {
+      void error(String message) {
+        // Flush data.
+        response.detachSocket().then((socket) {
+          socket.destroy();
+        });
+        throw new WebSocketException(message);
+      }
+
+      if (response.statusCode != HttpStatus.switchingProtocols ||
+          response.headers[HttpHeaders.connectionHeader] == null ||
+          !response.headers[HttpHeaders.connectionHeader]
+              .any((value) => value.toLowerCase() == "upgrade") ||
+          response.headers.value(HttpHeaders.upgradeHeader).toLowerCase() !=
+              "websocket") {
+        error("Connection to '$uri' was not upgraded to websocket");
+      }
+      String accept = response.headers.value("Sec-WebSocket-Accept");
+      if (accept == null) {
+        error("Response did not contain a 'Sec-WebSocket-Accept' header");
+      }
+      _SHA1 sha1 = new _SHA1();
+      sha1.add("$nonce$_webSocketGUID".codeUnits);
+      List<int> expectedAccept = sha1.close();
+      List<int> receivedAccept = _CryptoUtils.base64StringToBytes(accept);
+      if (expectedAccept.length != receivedAccept.length) {
+        error("Response header 'Sec-WebSocket-Accept' is the wrong length");
+      }
+      for (int i = 0; i < expectedAccept.length; i++) {
+        if (expectedAccept[i] != receivedAccept[i]) {
+          error("Bad response 'Sec-WebSocket-Accept' header");
+        }
+      }
+      var protocol = response.headers.value('Sec-WebSocket-Protocol');
+
+      _WebSocketPerMessageDeflate deflate =
+          negotiateClientCompression(response, compression);
+
+      return response.detachSocket().then<WebSocket>((socket) =>
+          new _WebSocketImpl._fromSocket(
+              socket, protocol, compression, false, deflate));
+    });
+  }
+
+  static _WebSocketPerMessageDeflate negotiateClientCompression(
+      HttpClientResponse response, CompressionOptions compression) {
+    String extensionHeader = response.headers.value('Sec-WebSocket-Extensions');
+
+    if (extensionHeader == null) {
+      extensionHeader = "";
+    }
+
+    var hv = HeaderValue.parse(extensionHeader, valueSeparator: ',');
+
+    if (compression.enabled && hv.value == PER_MESSAGE_DEFLATE) {
+      var serverNoContextTakeover =
+          hv.parameters.containsKey(_serverNoContextTakeover);
+      var clientNoContextTakeover =
+          hv.parameters.containsKey(_clientNoContextTakeover);
+
+      int getWindowBits(String type) {
+        var o = hv.parameters[type];
+        if (o == null) {
+          return DEFAULT_WINDOW_BITS;
+        }
+
+        return int.parse(o, onError: (s) => DEFAULT_WINDOW_BITS);
+      }
+
+      return new _WebSocketPerMessageDeflate(
+          clientMaxWindowBits: getWindowBits(_clientMaxWindowBits),
+          serverMaxWindowBits: getWindowBits(_serverMaxWindowBits),
+          clientNoContextTakeover: clientNoContextTakeover,
+          serverNoContextTakeover: serverNoContextTakeover);
+    }
+
+    return null;
+  }
+
+  _WebSocketImpl._fromSocket(
+      this._socket, this.protocol, CompressionOptions compression,
+      [this._serverSide = false, _WebSocketPerMessageDeflate deflate]) {
+    _consumer = new _WebSocketConsumer(this, _socket);
+    _sink = new _StreamSinkImpl(_consumer);
+    _readyState = WebSocket.open;
+    _deflate = deflate;
+
+    var transformer = new _WebSocketProtocolTransformer(_serverSide, _deflate);
+    _subscription = transformer.bind(_socket).listen((data) {
+      if (data is _WebSocketPing) {
+        if (!_writeClosed) _consumer.add(new _WebSocketPong(data.payload));
+      } else if (data is _WebSocketPong) {
+        // Simply set pingInterval, as it'll cancel any timers.
+        pingInterval = _pingInterval;
+      } else {
+        _controller.add(data);
+      }
+    }, onError: (error, stackTrace) {
+      if (_closeTimer != null) _closeTimer.cancel();
+      if (error is FormatException) {
+        _close(WebSocketStatus.INVALID_FRAME_PAYLOAD_DATA);
+      } else {
+        _close(WebSocketStatus.PROTOCOL_ERROR);
+      }
+      // An error happened, set the close code set above.
+      _closeCode = _outCloseCode;
+      _closeReason = _outCloseReason;
+      _controller.close();
+    }, onDone: () {
+      if (_closeTimer != null) _closeTimer.cancel();
+      if (_readyState == WebSocket.open) {
+        _readyState = WebSocket.closing;
+        if (!_isReservedStatusCode(transformer.closeCode)) {
+          _close(transformer.closeCode, transformer.closeReason);
+        } else {
+          _close();
+        }
+        _readyState = WebSocket.closed;
+      }
+      // Protocol close, use close code from transformer.
+      _closeCode = transformer.closeCode;
+      _closeReason = transformer.closeReason;
+      _controller.close();
+    }, cancelOnError: true);
+    _subscription.pause();
+    _controller = new StreamController(
+        sync: true,
+        onListen: _subscription.resume,
+        onCancel: () {
+          _subscription.cancel();
+          _subscription = null;
+        },
+        onPause: _subscription.pause,
+        onResume: _subscription.resume);
+
+    _webSockets[_serviceId] = this;
+  }
+
+  StreamSubscription listen(void onData(message),
+      {Function onError, void onDone(), bool cancelOnError}) {
+    return _controller.stream.listen(onData,
+        onError: onError, onDone: onDone, cancelOnError: cancelOnError);
+  }
+
+  Duration get pingInterval => _pingInterval;
+
+  void set pingInterval(Duration interval) {
+    if (_writeClosed) return;
+    if (_pingTimer != null) _pingTimer.cancel();
+    _pingInterval = interval;
+
+    if (_pingInterval == null) return;
+
+    _pingTimer = new Timer(_pingInterval, () {
+      if (_writeClosed) return;
+      _consumer.add(new _WebSocketPing());
+      _pingTimer = new Timer(_pingInterval, () {
+        // No pong received.
+        _close(WebSocketStatus.GOING_AWAY);
+      });
+    });
+  }
+
+  int get readyState => _readyState;
+
+  String get extensions => null;
+  int get closeCode => _closeCode;
+  String get closeReason => _closeReason;
+
+  void add(data) {
+    _sink.add(data);
+  }
+
+  void addUtf8Text(List<int> bytes) {
+    ArgumentError.checkNotNull(bytes, "bytes");
+    _sink.add(new _EncodedString(bytes));
+  }
+
+  void addError(error, [StackTrace stackTrace]) {
+    _sink.addError(error, stackTrace);
+  }
+
+  Future addStream(Stream stream) => _sink.addStream(stream);
+  Future get done => _sink.done;
+
+  Future close([int code, String reason]) {
+    if (_isReservedStatusCode(code)) {
+      throw new WebSocketException("Reserved status code $code");
+    }
+    if (_outCloseCode == null) {
+      _outCloseCode = code;
+      _outCloseReason = reason;
+    }
+    if (!_controller.isClosed) {
+      // If a close has not yet been received from the other end then
+      //   1) make sure to listen on the stream so the close frame will be
+      //      processed if received.
+      //   2) set a timer terminate the connection if a close frame is
+      //      not received.
+      if (!_controller.hasListener && _subscription != null) {
+        _controller.stream.drain().catchError((_) => {});
+      }
+      if (_closeTimer == null) {
+        // When closing the web-socket, we no longer accept data.
+        _closeTimer = new Timer(const Duration(seconds: 5), () {
+          // Reuse code and reason from the local close.
+          _closeCode = _outCloseCode;
+          _closeReason = _outCloseReason;
+          if (_subscription != null) _subscription.cancel();
+          _controller.close();
+          _webSockets.remove(_serviceId);
+        });
+      }
+    }
+    return _sink.close();
+  }
+
+  static String get userAgent => _httpClient.userAgent;
+
+  static set userAgent(String userAgent) {
+    _httpClient.userAgent = userAgent;
+  }
+
+  void _close([int code, String reason]) {
+    if (_writeClosed) return;
+    if (_outCloseCode == null) {
+      _outCloseCode = code;
+      _outCloseReason = reason;
+    }
+    _writeClosed = true;
+    _consumer.closeSocket();
+    _webSockets.remove(_serviceId);
+  }
+
+  String get _serviceTypePath => 'io/websockets';
+  String get _serviceTypeName => 'WebSocket';
+
+  Map<String, dynamic> _toJSON(bool ref) {
+    var name = '${_socket.address.host}:${_socket.port}';
+    var r = <String, dynamic>{
+      'id': _servicePath,
+      'type': _serviceType(ref),
+      'name': name,
+      'user_name': name,
+    };
+    if (ref) {
+      return r;
+    }
+    try {
+      r['socket'] = _socket._toJSON(true);
+    } catch (_) {
+      r['socket'] = {
+        'id': _servicePath,
+        'type': '@Socket',
+        'name': 'UserSocket',
+        'user_name': 'UserSocket',
+      };
+    }
+    return r;
+  }
+
+  static bool _isReservedStatusCode(int code) {
+    return code != null &&
+        (code < WebSocketStatus.NORMAL_CLOSURE ||
+            code == WebSocketStatus.RESERVED_1004 ||
+            code == WebSocketStatus.NO_STATUS_RECEIVED ||
+            code == WebSocketStatus.ABNORMAL_CLOSURE ||
+            (code > WebSocketStatus.INTERNAL_SERVER_ERROR &&
+                code < WebSocketStatus.RESERVED_1015) ||
+            (code >= WebSocketStatus.RESERVED_1015 && code < 3000));
+  }
+}
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/lib/js/dart2js/js_dart2js.dart b/sdk_nnbd/lib/_internal/js_dev_runtime/lib/js/dart2js/js_dart2js.dart
new file mode 100644
index 0000000..91d6847
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/lib/js/dart2js/js_dart2js.dart
@@ -0,0 +1,595 @@
+// Copyright (c) 2015, 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.
+
+/**
+ * Support for interoperating with JavaScript.
+ *
+ * This library provides access to JavaScript objects from Dart, allowing
+ * Dart code to get and set properties, and call methods of JavaScript objects
+ * and invoke JavaScript functions. The library takes care of converting
+ * between Dart and JavaScript objects where possible, or providing proxies if
+ * conversion isn't possible.
+ *
+ * This library does not yet make Dart objects usable from JavaScript, their
+ * methods and proeprties are not accessible, though it does allow Dart
+ * functions to be passed into and called from JavaScript.
+ *
+ * [JsObject] is the core type and represents a proxy of a JavaScript object.
+ * JsObject gives access to the underlying JavaScript objects properties and
+ * methods. `JsObject`s can be acquired by calls to JavaScript, or they can be
+ * created from proxies to JavaScript constructors.
+ *
+ * The top-level getter [context] provides a [JsObject] that represents the
+ * global object in JavaScript, usually `window`.
+ *
+ * The following example shows an alert dialog via a JavaScript call to the
+ * global function `alert()`:
+ *
+ *     import 'dart:js';
+ *
+ *     main() => context.callMethod('alert', ['Hello from Dart!']);
+ *
+ * This example shows how to create a [JsObject] from a JavaScript constructor
+ * and access its properties:
+ *
+ *     import 'dart:js';
+ *
+ *     main() {
+ *       var object = new JsObject(context['Object']);
+ *       object['greeting'] = 'Hello';
+ *       object['greet'] = (name) => "${object['greeting']} $name";
+ *       var message = object.callMethod('greet', ['JavaScript']);
+ *       context['console'].callMethod('log', [message]);
+ *     }
+ *
+ * ## Proxying and automatic conversion
+ *
+ * When setting properties on a JsObject or passing arguments to a Javascript
+ * method or function, Dart objects are automatically converted or proxied to
+ * JavaScript objects. When accessing JavaScript properties, or when a Dart
+ * closure is invoked from JavaScript, the JavaScript objects are also
+ * converted to Dart.
+ *
+ * Functions and closures are proxied in such a way that they are callable. A
+ * Dart closure assigned to a JavaScript property is proxied by a function in
+ * JavaScript. A JavaScript function accessed from Dart is proxied by a
+ * [JsFunction], which has a [apply] method to invoke it.
+ *
+ * The following types are transferred directly and not proxied:
+ *
+ * * "Basic" types: `null`, `bool`, `num`, `String`, `DateTime`
+ * * `Blob`
+ * * `Event`
+ * * `HtmlCollection`
+ * * `ImageData`
+ * * `KeyRange`
+ * * `Node`
+ * * `NodeList`
+ * * `TypedData`, including its subclasses like `Int32List`, but _not_
+ *   `ByteBuffer`
+ * * `Window`
+ *
+ * ## Converting collections with JsObject.jsify()
+ *
+ * To create a JavaScript collection from a Dart collection use the
+ * [JsObject.jsify] constructor, which converts Dart [Map]s and [Iterable]s
+ * into JavaScript Objects and Arrays.
+ *
+ * The following expression creates a new JavaScript object with the properties
+ * `a` and `b` defined:
+ *
+ *     var jsMap = new JsObject.jsify({'a': 1, 'b': 2});
+ *
+ * This expression creates a JavaScript array:
+ *
+ *     var jsArray = new JsObject.jsify([1, 2, 3]);
+ */
+library dart.js;
+
+import 'dart:collection' show HashMap, ListMixin;
+
+import 'dart:_js_helper' show Primitives;
+import 'dart:_foreign_helper' show JS;
+import 'dart:_runtime' as dart;
+
+final JsObject context = _wrapToDart(dart.global_);
+
+/**
+ * Proxies a JavaScript object to Dart.
+ *
+ * The properties of the JavaScript object are accessible via the `[]` and
+ * `[]=` operators. Methods are callable via [callMethod].
+ */
+class JsObject {
+  // The wrapped JS object.
+  final dynamic _jsObject;
+
+  // This should only be called from _wrapToDart
+  JsObject._fromJs(this._jsObject) {
+    assert(_jsObject != null);
+  }
+
+  /**
+   * Constructs a new JavaScript object from [constructor] and returns a proxy
+   * to it.
+   */
+  factory JsObject(JsFunction constructor, [List arguments]) {
+    var ctor = constructor._jsObject;
+    if (arguments == null) {
+      return _wrapToDart(JS('', 'new #()', ctor));
+    }
+    var unwrapped = List.from(arguments.map(_convertToJS));
+    return _wrapToDart(JS('', 'new #(...#)', ctor, unwrapped));
+  }
+
+  /**
+   * Constructs a [JsObject] that proxies a native Dart object; _for expert use
+   * only_.
+   *
+   * Use this constructor only if you wish to get access to JavaScript
+   * properties attached to a browser host object, such as a Node or Blob, that
+   * is normally automatically converted into a native Dart object.
+   *
+   * An exception will be thrown if [object] either is `null` or has the type
+   * `bool`, `num`, or `String`.
+   */
+  factory JsObject.fromBrowserObject(object) {
+    if (object is num || object is String || object is bool || object == null) {
+      throw ArgumentError("object cannot be a num, string, bool, or null");
+    }
+    return _wrapToDart(_convertToJS(object));
+  }
+
+  /**
+   * Recursively converts a JSON-like collection of Dart objects to a
+   * collection of JavaScript objects and returns a [JsObject] proxy to it.
+   *
+   * [object] must be a [Map] or [Iterable], the contents of which are also
+   * converted. Maps and Iterables are copied to a new JavaScript object.
+   * Primitives and other transferable values are directly converted to their
+   * JavaScript type, and all other objects are proxied.
+   */
+  factory JsObject.jsify(object) {
+    if ((object is! Map) && (object is! Iterable)) {
+      throw ArgumentError("object must be a Map or Iterable");
+    }
+    return _wrapToDart(_convertDataTree(object));
+  }
+
+  static _convertDataTree(data) {
+    var _convertedObjects = HashMap.identity();
+
+    _convert(o) {
+      if (_convertedObjects.containsKey(o)) {
+        return _convertedObjects[o];
+      }
+      if (o is Map) {
+        final convertedMap = JS('', '{}');
+        _convertedObjects[o] = convertedMap;
+        for (var key in o.keys) {
+          JS('', '#[#] = #', convertedMap, key, _convert(o[key]));
+        }
+        return convertedMap;
+      } else if (o is Iterable) {
+        var convertedList = [];
+        _convertedObjects[o] = convertedList;
+        convertedList.addAll(o.map(_convert));
+        return convertedList;
+      } else {
+        return _convertToJS(o);
+      }
+    }
+
+    return _convert(data);
+  }
+
+  /**
+   * Returns the value associated with [property] from the proxied JavaScript
+   * object.
+   *
+   * The type of [property] must be either [String] or [num].
+   */
+  dynamic operator [](Object property) {
+    if (property is! String && property is! num) {
+      throw ArgumentError("property is not a String or num");
+    }
+    return _convertToDart(JS('', '#[#]', _jsObject, property));
+  }
+
+  /**
+   * Sets the value associated with [property] on the proxied JavaScript
+   * object.
+   *
+   * The type of [property] must be either [String] or [num].
+   */
+  void operator []=(Object property, value) {
+    if (property is! String && property is! num) {
+      throw ArgumentError("property is not a String or num");
+    }
+    JS('', '#[#] = #', _jsObject, property, _convertToJS(value));
+  }
+
+  int get hashCode => 0;
+
+  bool operator ==(other) =>
+      other is JsObject && JS<bool>('!', '# === #', _jsObject, other._jsObject);
+
+  /**
+   * Returns `true` if the JavaScript object contains the specified property
+   * either directly or though its prototype chain.
+   *
+   * This is the equivalent of the `in` operator in JavaScript.
+   */
+  bool hasProperty(property) {
+    if (property is! String && property is! num) {
+      throw ArgumentError("property is not a String or num");
+    }
+    return JS<bool>('!', '# in #', property, _jsObject);
+  }
+
+  /**
+   * Removes [property] from the JavaScript object.
+   *
+   * This is the equivalent of the `delete` operator in JavaScript.
+   */
+  void deleteProperty(property) {
+    if (property is! String && property is! num) {
+      throw ArgumentError("property is not a String or num");
+    }
+    JS<bool>('!', 'delete #[#]', _jsObject, property);
+  }
+
+  /**
+   * Returns `true` if the JavaScript object has [type] in its prototype chain.
+   *
+   * This is the equivalent of the `instanceof` operator in JavaScript.
+   */
+  bool instanceof(JsFunction type) {
+    return JS<bool>('!', '# instanceof #', _jsObject, _convertToJS(type));
+  }
+
+  /**
+   * Returns the result of the JavaScript objects `toString` method.
+   */
+  String toString() {
+    try {
+      return JS<String>('!', 'String(#)', _jsObject);
+    } catch (e) {
+      return super.toString();
+    }
+  }
+
+  /**
+   * Calls [method] on the JavaScript object with the arguments [args] and
+   * returns the result.
+   *
+   * The type of [method] must be either [String] or [num].
+   */
+  dynamic callMethod(method, [List args]) {
+    if (method is! String && method is! num) {
+      throw ArgumentError("method is not a String or num");
+    }
+    if (args != null) args = List.from(args.map(_convertToJS));
+    var fn = JS('', '#[#]', _jsObject, method);
+    if (JS<bool>('!', 'typeof(#) !== "function"', fn)) {
+      throw NoSuchMethodError(_jsObject, Symbol(method), args, {});
+    }
+    return _convertToDart(JS('', '#.apply(#, #)', fn, _jsObject, args));
+  }
+}
+
+/**
+ * Proxies a JavaScript Function object.
+ */
+class JsFunction extends JsObject {
+  /**
+   * Returns a [JsFunction] that captures its 'this' binding and calls [f]
+   * with the value of this passed as the first argument.
+   */
+  factory JsFunction.withThis(Function f) {
+    return JsFunction._fromJs(JS(
+        '',
+        'function(/*...arguments*/) {'
+            '  let args = [#(this)];'
+            '  for (let arg of arguments) {'
+            '    args.push(#(arg));'
+            '  }'
+            '  return #(#(...args));'
+            '}',
+        _convertToDart,
+        _convertToDart,
+        _convertToJS,
+        f));
+  }
+
+  JsFunction._fromJs(jsObject) : super._fromJs(jsObject);
+
+  /**
+   * Invokes the JavaScript function with arguments [args]. If [thisArg] is
+   * supplied it is the value of `this` for the invocation.
+   */
+  dynamic apply(List args, {thisArg}) => _convertToDart(JS(
+      '',
+      '#.apply(#, #)',
+      _jsObject,
+      _convertToJS(thisArg),
+      args == null ? null : List.from(args.map(_convertToJS))));
+}
+
+// TODO(jmesserly): this is totally unnecessary in dev_compiler.
+/** A [List] that proxies a JavaScript array. */
+class JsArray<E> extends JsObject with ListMixin<E> {
+  /**
+   * Creates a new JavaScript array.
+   */
+  JsArray() : super._fromJs([]);
+
+  /**
+   * Creates a new JavaScript array and initializes it to the contents of
+   * [other].
+   */
+  JsArray.from(Iterable<E> other)
+      : super._fromJs([]..addAll(other.map(_convertToJS)));
+
+  JsArray._fromJs(jsObject) : super._fromJs(jsObject);
+
+  _checkIndex(int index) {
+    if (index is int && (index < 0 || index >= length)) {
+      throw RangeError.range(index, 0, length);
+    }
+  }
+
+  _checkInsertIndex(int index) {
+    if (index is int && (index < 0 || index >= length + 1)) {
+      throw RangeError.range(index, 0, length);
+    }
+  }
+
+  static _checkRange(int start, int end, int length) {
+    if (start < 0 || start > length) {
+      throw RangeError.range(start, 0, length);
+    }
+    if (end < start || end > length) {
+      throw RangeError.range(end, start, length);
+    }
+  }
+
+  // Methods required by ListMixin
+
+  E operator [](Object index) {
+    // TODO(justinfagnani): fix the semantics for non-ints
+    // dartbug.com/14605
+    if (index is num && index == index.toInt()) {
+      _checkIndex(index);
+    }
+    return super[index] as E;
+  }
+
+  void operator []=(Object index, value) {
+    // TODO(justinfagnani): fix the semantics for non-ints
+    // dartbug.com/14605
+    if (index is num && index == index.toInt()) {
+      _checkIndex(index);
+    }
+    super[index] = value;
+  }
+
+  int get length {
+    // Check the length honours the List contract.
+    var len = JS('', '#.length', _jsObject);
+    // JavaScript arrays have lengths which are unsigned 32-bit integers.
+    if (JS<bool>(
+        '!', 'typeof # === "number" && (# >>> 0) === #', len, len, len)) {
+      return JS<int>('!', '#', len);
+    }
+    throw StateError('Bad JsArray length');
+  }
+
+  void set length(int length) {
+    super['length'] = length;
+  }
+
+  // Methods overridden for better performance
+
+  void add(E value) {
+    callMethod('push', [value]);
+  }
+
+  void addAll(Iterable<E> iterable) {
+    var list = (JS<bool>('!', '# instanceof Array', iterable))
+        ? iterable
+        : List.from(iterable);
+    callMethod('push', list);
+  }
+
+  void insert(int index, E element) {
+    _checkInsertIndex(index);
+    callMethod('splice', [index, 0, element]);
+  }
+
+  E removeAt(int index) {
+    _checkIndex(index);
+    return callMethod('splice', [index, 1])[0] as E;
+  }
+
+  E removeLast() {
+    if (length == 0) throw RangeError(-1);
+    return callMethod('pop') as E;
+  }
+
+  void removeRange(int start, int end) {
+    _checkRange(start, end, length);
+    callMethod('splice', [start, end - start]);
+  }
+
+  void setRange(int start, int end, Iterable<E> iterable, [int skipCount = 0]) {
+    _checkRange(start, end, this.length);
+    int length = end - start;
+    if (length == 0) return;
+    if (skipCount < 0) throw ArgumentError(skipCount);
+    var args = <Object>[start, length]
+      ..addAll(iterable.skip(skipCount).take(length));
+    callMethod('splice', args);
+  }
+
+  void sort([int compare(E a, E b)]) {
+    // Note: arr.sort(null) is a type error in FF
+    callMethod('sort', compare == null ? [] : [compare]);
+  }
+}
+
+// Cross frame objects should not be considered browser types.
+// We include the instanceof Object test to filter out cross frame objects
+// on FireFox. Surprisingly on FireFox the instanceof Window test succeeds for
+// cross frame windows while the instanceof Object test fails.
+bool _isBrowserType(o) => JS(
+    'bool',
+    '# instanceof Object && ('
+        '# instanceof Blob || '
+        '# instanceof Event || '
+        '(window.KeyRange && # instanceof KeyRange) || '
+        '(window.IDBKeyRange && # instanceof IDBKeyRange) || '
+        '# instanceof ImageData || '
+        '# instanceof Node || '
+        // Int8Array.__proto__ is TypedArray.
+        '(window.Int8Array && # instanceof Int8Array.__proto__) || '
+        '# instanceof Window)',
+    o,
+    o,
+    o,
+    o,
+    o,
+    o,
+    o,
+    o,
+    o);
+
+class _DartObject {
+  final _dartObj;
+  _DartObject(this._dartObj);
+}
+
+dynamic _convertToJS(dynamic o) {
+  if (o == null || o is String || o is num || o is bool || _isBrowserType(o)) {
+    return o;
+  } else if (o is DateTime) {
+    return Primitives.lazyAsJsDate(o);
+  } else if (o is JsObject) {
+    return o._jsObject;
+  } else if (o is Function) {
+    return _putIfAbsent(_jsProxies, o, _wrapDartFunction);
+  } else {
+    // TODO(jmesserly): for now, we wrap other objects, to keep compatibility
+    // with the original dart:js behavior.
+    return _putIfAbsent(_jsProxies, o, (o) => _DartObject(o));
+  }
+}
+
+dynamic _wrapDartFunction(f) {
+  var wrapper = JS(
+      '',
+      'function(/*...arguments*/) {'
+          '  let args = Array.prototype.map.call(arguments, #);'
+          '  return #(#(...args));'
+          '}',
+      _convertToDart,
+      _convertToJS,
+      f);
+  JS('', '#.set(#, #)', _dartProxies, wrapper, f);
+
+  return wrapper;
+}
+
+// converts a Dart object to a reference to a native JS object
+// which might be a DartObject JS->Dart proxy
+Object _convertToDart(o) {
+  if (o == null || o is String || o is num || o is bool || _isBrowserType(o)) {
+    return o;
+  } else if (JS('!', '# instanceof Date', o)) {
+    num ms = JS('!', '#.getTime()', o);
+    return DateTime.fromMillisecondsSinceEpoch(ms);
+  } else if (o is _DartObject &&
+      !identical(dart.getReifiedType(o), dart.jsobject)) {
+    return o._dartObj;
+  } else {
+    return _wrapToDart(o);
+  }
+}
+
+Object _wrapToDart(o) => _putIfAbsent(_dartProxies, o, _wrapToDartHelper);
+
+Object _wrapToDartHelper(o) {
+  if (JS<bool>('!', 'typeof # == "function"', o)) {
+    return JsFunction._fromJs(o);
+  }
+  if (JS<bool>('!', '# instanceof Array', o)) {
+    return JsArray._fromJs(o);
+  }
+  return JsObject._fromJs(o);
+}
+
+final _dartProxies = JS('', 'new WeakMap()');
+final _jsProxies = JS('', 'new WeakMap()');
+
+Object _putIfAbsent(weakMap, o, getValue(o)) {
+  var value = JS('', '#.get(#)', weakMap, o);
+  if (value == null) {
+    value = getValue(o);
+    JS('', '#.set(#, #)', weakMap, o, value);
+  }
+  return value;
+}
+
+Expando<Function> _interopExpando = Expando<Function>();
+
+/// Returns a wrapper around function [f] that can be called from JavaScript
+/// using the package:js Dart-JavaScript interop.
+///
+/// For performance reasons in Dart2Js, by default Dart functions cannot be
+/// passed directly to JavaScript unless this method is called to create
+/// a Function compatible with both Dart and JavaScript.
+/// Calling this method repeatedly on a function will return the same function.
+/// The [Function] returned by this method can be used from both Dart and
+/// JavaScript. We may remove the need to call this method completely in the
+/// future if Dart2Js is refactored so that its function calling conventions
+/// are more compatible with JavaScript.
+F allowInterop<F extends Function>(F f) {
+  var ret = _interopExpando[f];
+  if (ret == null) {
+    ret = JS(
+        '',
+        'function (...args) {'
+            ' return #(#, args);'
+            '}',
+        dart.dcall,
+        f);
+    _interopExpando[f] = ret;
+  }
+  return ret;
+}
+
+Expando<Function> _interopCaptureThisExpando = Expando<Function>();
+
+/// Returns a [Function] that when called from JavaScript captures its 'this'
+/// binding and calls [f] with the value of this passed as the first argument.
+/// When called from Dart, [null] will be passed as the first argument.
+///
+/// See the documentation for [allowInterop]. This method should only be used
+/// with package:js Dart-JavaScript interop.
+Function allowInteropCaptureThis(Function f) {
+  var ret = _interopCaptureThisExpando[f];
+  if (ret == null) {
+    ret = JS(
+        '',
+        'function(...arguments) {'
+            '  let args = [this];'
+            '  args.push.apply(args, arguments);'
+            '  return #(#, args);'
+            '}',
+        dart.dcall,
+        f);
+    _interopCaptureThisExpando[f] = ret;
+  }
+  return ret;
+}
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/lib/js_util/dart2js/js_util_dart2js.dart b/sdk_nnbd/lib/_internal/js_dev_runtime/lib/js_util/dart2js/js_util_dart2js.dart
new file mode 100644
index 0000000..4b9fdb0
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/lib/js_util/dart2js/js_util_dart2js.dart
@@ -0,0 +1,126 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// Utility methods to efficiently manipulate typed JSInterop objects in cases
+/// where the name to call is not known at runtime. You should only use these
+/// methods when the same effect cannot be achieved with @JS annotations.
+/// These methods would be extension methods on JSObject if Dart supported
+/// extension methods.
+library dart.js_util;
+
+import 'dart:_foreign_helper' show JS;
+import 'dart:collection' show HashMap;
+
+/// WARNING: performance of this method is much worse than other uitil
+/// methods in this library. Only use this method as a last resort.
+///
+/// Recursively converts a JSON-like collection of Dart objects to a
+/// collection of JavaScript objects and returns a [JsObject] proxy to it.
+///
+/// [object] must be a [Map] or [Iterable], the contents of which are also
+/// converted. Maps and Iterables are copied to a new JavaScript object.
+/// Primitives and other transferrable values are directly converted to their
+/// JavaScript type, and all other objects are proxied.
+jsify(object) {
+  if ((object is! Map) && (object is! Iterable)) {
+    throw ArgumentError("object must be a Map or Iterable");
+  }
+  return _convertDataTree(object);
+}
+
+_convertDataTree(data) {
+  var _convertedObjects = HashMap.identity();
+
+  _convert(o) {
+    if (_convertedObjects.containsKey(o)) {
+      return _convertedObjects[o];
+    }
+    if (o is Map) {
+      final convertedMap = JS('=Object', '{}');
+      _convertedObjects[o] = convertedMap;
+      for (var key in o.keys) {
+        JS('=Object', '#[#]=#', convertedMap, key, _convert(o[key]));
+      }
+      return convertedMap;
+    } else if (o is Iterable) {
+      var convertedList = [];
+      _convertedObjects[o] = convertedList;
+      convertedList.addAll(o.map(_convert));
+      return convertedList;
+    } else {
+      return o;
+    }
+  }
+
+  return _convert(data);
+}
+
+newObject() => JS('=Object', '{}');
+
+hasProperty(o, name) => JS<bool>('!', '# in #', name, o);
+getProperty(o, name) => JS('Object', '#[#]', o, name);
+setProperty(o, name, value) => JS('', '#[#]=#', o, name, value);
+
+callMethod(o, String method, List args) =>
+    JS('Object', '#[#].apply(#, #)', o, method, o, args);
+
+instanceof(o, Function type) => JS<bool>('!', '# instanceof #', o, type);
+callConstructor(Function constr, List arguments) {
+  if (arguments == null) {
+    return JS('Object', 'new #()', constr);
+  }
+
+  if (JS<bool>('!', '# instanceof Array', arguments)) {
+    int argumentCount = JS('!', '#.length', arguments);
+    switch (argumentCount) {
+      case 0:
+        return JS('Object', 'new #()', constr);
+
+      case 1:
+        var arg0 = JS('', '#[0]', arguments);
+        return JS('Object', 'new #(#)', constr, arg0);
+
+      case 2:
+        var arg0 = JS('', '#[0]', arguments);
+        var arg1 = JS('', '#[1]', arguments);
+        return JS('Object', 'new #(#, #)', constr, arg0, arg1);
+
+      case 3:
+        var arg0 = JS('', '#[0]', arguments);
+        var arg1 = JS('', '#[1]', arguments);
+        var arg2 = JS('', '#[2]', arguments);
+        return JS('Object', 'new #(#, #, #)', constr, arg0, arg1, arg2);
+
+      case 4:
+        var arg0 = JS('', '#[0]', arguments);
+        var arg1 = JS('', '#[1]', arguments);
+        var arg2 = JS('', '#[2]', arguments);
+        var arg3 = JS('', '#[3]', arguments);
+        return JS(
+            'Object', 'new #(#, #, #, #)', constr, arg0, arg1, arg2, arg3);
+    }
+  }
+
+  // The following code solves the problem of invoking a JavaScript
+  // constructor with an unknown number arguments.
+  // First bind the constructor to the argument list using bind.apply().
+  // The first argument to bind() is the binding of 't', so add 'null' to
+  // the arguments list passed to apply().
+  // After that, use the JavaScript 'new' operator which overrides any binding
+  // of 'this' with the new instance.
+  var args = <dynamic>[null]..addAll(arguments);
+  var factoryFunction = JS('', '#.bind.apply(#, #)', constr, constr, args);
+  // Without this line, calling factoryFunction as a constructor throws
+  JS<String>('!', 'String(#)', factoryFunction);
+  // This could return an UnknownJavaScriptObject, or a native
+  // object for which there is an interceptor
+  return JS('Object', 'new #()', factoryFunction);
+
+  // TODO(sra): Investigate:
+  //
+  //     var jsObj = JS('', 'Object.create(#.prototype)', constr);
+  //     JS('', '#.apply(#, #)', constr, jsObj,
+  //         []..addAll(arguments.map(_convertToJS)));
+  //     return _wrapToDart(jsObj);
+}
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/libraries.dart b/sdk_nnbd/lib/_internal/js_dev_runtime/libraries.dart
new file mode 100644
index 0000000..d5cffa2
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/libraries.dart
@@ -0,0 +1,310 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library libraries;
+
+/**
+ * A bit flag used by [LibraryInfo] indicating that a library is used by dart2js
+ */
+const int DART2JS_PLATFORM = 1;
+
+/**
+ * A bit flag used by [LibraryInfo] indicating that a library is used by the VM
+ */
+const int VM_PLATFORM = 2;
+
+/// The contexts that a library can be used from.
+enum Category {
+  /// Indicates that a library can be used in a browser context.
+  client,
+
+  /// Indicates that a library can be used in a command line context.
+  server,
+
+  /// Indicates that a library can be used from embedded devices.
+  embedded
+}
+
+Category parseCategory(String name) {
+  switch (name) {
+    case "Client":
+      return Category.client;
+    case "Server":
+      return Category.server;
+    case "Embedded":
+      return Category.embedded;
+  }
+  return null;
+}
+
+/// Mapping of "dart:" library name (e.g. "core") to information about that
+/// library.
+const Map<String, LibraryInfo> libraries = const {
+  "async": const LibraryInfo("async/async.dart",
+      categories: "Client,Server",
+      maturity: Maturity.STABLE,
+      dart2jsPatchPath: "_internal/js_runtime/lib/async_patch.dart"),
+  "collection": const LibraryInfo("collection/collection.dart",
+      categories: "Client,Server,Embedded",
+      maturity: Maturity.STABLE,
+      dart2jsPatchPath: "_internal/js_runtime/lib/collection_patch.dart"),
+  "convert": const LibraryInfo("convert/convert.dart",
+      categories: "Client,Server",
+      maturity: Maturity.STABLE,
+      dart2jsPatchPath: "_internal/js_runtime/lib/convert_patch.dart"),
+  "core": const LibraryInfo("core/core.dart",
+      categories: "Client,Server,Embedded",
+      maturity: Maturity.STABLE,
+      dart2jsPatchPath: "_internal/js_runtime/lib/core_patch.dart"),
+  "developer": const LibraryInfo("developer/developer.dart",
+      categories: "Client,Server,Embedded",
+      maturity: Maturity.UNSTABLE,
+      dart2jsPatchPath: "_internal/js_runtime/lib/developer_patch.dart"),
+  "html": const LibraryInfo("html/dart2js/html_dart2js.dart",
+      categories: "Client",
+      maturity: Maturity.WEB_STABLE,
+      platforms: DART2JS_PLATFORM),
+  "html_common": const LibraryInfo("html/html_common/html_common.dart",
+      categories: "Client",
+      maturity: Maturity.WEB_STABLE,
+      dart2jsPath: "html/html_common/html_common_dart2js.dart",
+      documented: false,
+      implementation: true),
+  "indexed_db": const LibraryInfo("indexed_db/dart2js/indexed_db_dart2js.dart",
+      categories: "Client",
+      maturity: Maturity.WEB_STABLE,
+      platforms: DART2JS_PLATFORM),
+  "_http":
+      const LibraryInfo("_http/http.dart", categories: "", documented: false),
+  "io": const LibraryInfo("io/io.dart",
+      categories: "Server",
+      dart2jsPatchPath: "_internal/js_runtime/lib/io_patch.dart"),
+  "isolate": const LibraryInfo("isolate/isolate.dart",
+      categories: "Client,Server",
+      maturity: Maturity.STABLE,
+      dart2jsPatchPath: "_internal/js_runtime/lib/isolate_patch.dart"),
+  "js": const LibraryInfo("js/dart2js/js_dart2js.dart",
+      categories: "Client",
+      maturity: Maturity.STABLE,
+      platforms: DART2JS_PLATFORM),
+  "js_util": const LibraryInfo("js_util/dart2js/js_util_dart2js.dart",
+      categories: "Client",
+      maturity: Maturity.STABLE,
+      platforms: DART2JS_PLATFORM),
+  "math": const LibraryInfo("math/math.dart",
+      categories: "Client,Server,Embedded",
+      maturity: Maturity.STABLE,
+      dart2jsPatchPath: "_internal/js_runtime/lib/math_patch.dart"),
+  "mirrors": const LibraryInfo("mirrors/mirrors.dart",
+      categories: "Client,Server",
+      maturity: Maturity.UNSTABLE,
+      dart2jsPatchPath: "_internal/js_runtime/lib/mirrors_patch.dart"),
+  "nativewrappers": const LibraryInfo("html/dartium/nativewrappers.dart",
+      categories: "Client",
+      implementation: true,
+      documented: false,
+      platforms: DART2JS_PLATFORM),
+  "typed_data": const LibraryInfo("typed_data/typed_data.dart",
+      categories: "Client,Server,Embedded",
+      maturity: Maturity.STABLE,
+      dart2jsPatchPath: "_internal/js_runtime/lib/typed_data_patch.dart"),
+  "_native_typed_data": const LibraryInfo(
+      "_internal/js_runtime/lib/native_typed_data.dart",
+      categories: "",
+      implementation: true,
+      documented: false,
+      platforms: DART2JS_PLATFORM),
+  "cli": const LibraryInfo("cli/cli.dart",
+      categories: "Server",
+      dart2jsPatchPath: "_internal/js_runtime/lib/cli_patch.dart"),
+  "svg": const LibraryInfo("svg/dart2js/svg_dart2js.dart",
+      categories: "Client",
+      maturity: Maturity.WEB_STABLE,
+      platforms: DART2JS_PLATFORM),
+  "web_audio": const LibraryInfo("web_audio/dart2js/web_audio_dart2js.dart",
+      categories: "Client",
+      maturity: Maturity.WEB_STABLE,
+      platforms: DART2JS_PLATFORM),
+  "web_gl": const LibraryInfo("web_gl/dart2js/web_gl_dart2js.dart",
+      categories: "Client",
+      maturity: Maturity.WEB_STABLE,
+      platforms: DART2JS_PLATFORM),
+  "web_sql": const LibraryInfo("web_sql/dart2js/web_sql_dart2js.dart",
+      categories: "Client",
+      maturity: Maturity.WEB_STABLE,
+      platforms: DART2JS_PLATFORM),
+  "_internal": const LibraryInfo("internal/internal.dart",
+      categories: "",
+      documented: false,
+      dart2jsPatchPath: "_internal/js_runtime/lib/internal_patch.dart"),
+  "_js_helper": const LibraryInfo("_internal/js_runtime/lib/js_helper.dart",
+      categories: "", documented: false, platforms: DART2JS_PLATFORM),
+  "_interceptors": const LibraryInfo(
+      "_internal/js_runtime/lib/interceptors.dart",
+      categories: "",
+      documented: false,
+      platforms: DART2JS_PLATFORM),
+  "_foreign_helper": const LibraryInfo(
+      "_internal/js_runtime/lib/foreign_helper.dart",
+      categories: "",
+      documented: false,
+      platforms: DART2JS_PLATFORM),
+  "_isolate_helper": const LibraryInfo(
+      "_internal/js_runtime/lib/isolate_helper.dart",
+      categories: "",
+      documented: false,
+      platforms: DART2JS_PLATFORM),
+  "_js_mirrors": const LibraryInfo("_internal/js_runtime/lib/js_mirrors.dart",
+      categories: "", documented: false, platforms: DART2JS_PLATFORM),
+  "_js_primitives": const LibraryInfo(
+      "_internal/js_runtime/lib/js_primitives.dart",
+      categories: "",
+      documented: false,
+      platforms: DART2JS_PLATFORM),
+  "_metadata": const LibraryInfo("html/html_common/metadata.dart",
+      categories: "", documented: false, platforms: DART2JS_PLATFORM),
+  "_debugger": const LibraryInfo("_internal/js_runtime/lib/debugger.dart",
+      category: "", documented: false, platforms: DART2JS_PLATFORM),
+  "_runtime": const LibraryInfo(
+      "_internal/js_runtime/lib/ddc_runtime/runtime.dart",
+      category: "",
+      documented: false,
+      platforms: DART2JS_PLATFORM),
+};
+
+/**
+ * Information about a "dart:" library.
+ */
+class LibraryInfo {
+  /**
+   * Path to the library's *.dart file relative to this file.
+   */
+  final String path;
+
+  /**
+   * The categories in which the library can be used encoded as a
+   * comma-separated String.
+   */
+  final String _categories;
+
+  /**
+   * Path to the dart2js library's *.dart file relative to this file
+   * or null if dart2js uses the common library path defined above.
+   * Access using the [#getDart2JsPath()] method.
+   */
+  final String dart2jsPath;
+
+  /**
+   * Path to the dart2js library's patch file relative to this file
+   * or null if no dart2js patch file associated with this library.
+   * Access using the [#getDart2JsPatchPath()] method.
+   */
+  final String dart2jsPatchPath;
+
+  /**
+   * True if this library is documented and should be shown to the user.
+   */
+  final bool documented;
+
+  /**
+   * Bit flags indicating which platforms consume this library.
+   * See [DART2JS_LIBRARY] and [VM_LIBRARY].
+   */
+  final int platforms;
+
+  /**
+   * True if the library contains implementation details for another library.
+   * The implication is that these libraries are less commonly used
+   * and that tools like Dart Editor should not show these libraries
+   * in a list of all libraries unless the user specifically asks the tool to
+   * do so.
+   */
+  final bool implementation;
+
+  /**
+   * States the current maturity of this library.
+   */
+  final Maturity maturity;
+
+  const LibraryInfo(this.path,
+      {String categories: "",
+      this.dart2jsPath,
+      this.dart2jsPatchPath,
+      this.implementation: false,
+      this.documented: true,
+      this.maturity: Maturity.UNSPECIFIED,
+      this.platforms: DART2JS_PLATFORM | VM_PLATFORM})
+      : _categories = categories;
+
+  bool get isDart2jsLibrary => (platforms & DART2JS_PLATFORM) != 0;
+  bool get isVmLibrary => (platforms & VM_PLATFORM) != 0;
+
+  /**
+   * The categories in which the library can be used.
+   *
+   * If no categories are specified, the library is internal and can not be
+   * loaded by user code.
+   */
+  List<Category> get categories {
+    // `"".split(,)` returns [""] not [], so we handle that case separately.
+    if (_categories == "") return const <Category>[];
+    return _categories.split(",").map(parseCategory).toList();
+  }
+
+  bool get isInternal => categories.isEmpty;
+
+  /// The original "categories" String that was passed to the constructor.
+  ///
+  /// Can be used to construct a slightly modified copy of this LibraryInfo.
+  String get categoriesString {
+    return _categories;
+  }
+}
+
+/**
+ * Abstraction to capture the maturity of a library.
+ */
+class Maturity {
+  final int level;
+  final String name;
+  final String description;
+
+  const Maturity(this.level, this.name, this.description);
+
+  String toString() => "$name: $level\n$description\n";
+
+  static const Maturity DEPRECATED = const Maturity(0, "Deprecated",
+      "This library will be remove before next major release.");
+
+  static const Maturity EXPERIMENTAL = const Maturity(
+      1,
+      "Experimental",
+      "This library is experimental and will likely change or be removed\n"
+          "in future versions.");
+
+  static const Maturity UNSTABLE = const Maturity(
+      2,
+      "Unstable",
+      "This library is in still changing and have not yet endured\n"
+          "sufficient real-world testing.\n"
+          "Backwards-compatibility is NOT guaranteed.");
+
+  static const Maturity WEB_STABLE = const Maturity(
+      3,
+      "Web Stable",
+      "This library is tracking the DOM evolution as defined by WC3.\n"
+          "Backwards-compatibility is NOT guaranteed.");
+
+  static const Maturity STABLE = const Maturity(
+      4,
+      "Stable",
+      "The library is stable. API backwards-compatibility is guaranteed.\n"
+          "However implementation details might change.");
+
+  static const Maturity LOCKED = const Maturity(5, "Locked",
+      "This library will not change except when serious bugs are encountered.");
+
+  static const Maturity UNSPECIFIED = const Maturity(-1, "Unspecified",
+      "The maturity for this library has not been specified.");
+}
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/patch/async_patch.dart b/sdk_nnbd/lib/_internal/js_dev_runtime/patch/async_patch.dart
new file mode 100644
index 0000000..894aef4
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/patch/async_patch.dart
@@ -0,0 +1,472 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Patch file for the dart:async library.
+
+import 'dart:_js_helper' show notNull, patch, ReifyFunctionTypes;
+import 'dart:_isolate_helper' show TimerImpl;
+import 'dart:_foreign_helper' show JS, JSExportName;
+import 'dart:_runtime' as dart;
+
+/// This function adapts ES6 generators to implement Dart's async/await.
+///
+/// It's designed to interact with Dart's Future and follow Dart async/await
+/// semantics.
+///
+/// See https://github.com/dart-lang/sdk/issues/27315 for ideas on reconciling
+/// Dart's Future and ES6 Promise. At that point we should use native JS
+/// async/await.
+///
+/// Inspired by `co`: https://github.com/tj/co/blob/master/index.js, which is a
+/// stepping stone for ES async/await.
+@JSExportName('async')
+@ReifyFunctionTypes(false)
+_async<T>(Function() initGenerator) {
+  var iter;
+  Object Function(Object) onValue;
+  Object Function(Object, StackTrace) onError;
+
+  onAwait(Object value) {
+    _Future f;
+    if (value is _Future) {
+      f = value;
+    } else if (value is Future) {
+      f = _Future();
+      _Future._chainForeignFuture(value, f);
+    } else {
+      f = _Future.value(value);
+    }
+    f = JS('', '#', f._thenAwait(onValue, onError));
+    return f;
+  }
+
+  onValue = (value) {
+    var iteratorResult = JS('', '#.next(#)', iter, value);
+    value = JS('', '#.value', iteratorResult);
+    return JS<bool>('!', '#.done', iteratorResult) ? value : onAwait(value);
+  };
+
+  // If the awaited Future throws, we want to convert this to an exception
+  // thrown from the `yield` point, as if it was thrown there.
+  //
+  // If the exception is not caught inside `gen`, it will emerge here, which
+  // will send it to anyone listening on this async function's Future<T>.
+  //
+  // In essence, we are giving the code inside the generator a chance to
+  // use try-catch-finally.
+  onError = (value, stackTrace) {
+    var iteratorResult = JS(
+        '', '#.throw(#)', iter, dart.createErrorWithStack(value, stackTrace));
+    value = JS('', '#.value', iteratorResult);
+    return JS<bool>('!', '#.done', iteratorResult) ? value : onAwait(value);
+  };
+
+  var zone = Zone.current;
+  if (!identical(zone, _rootZone)) {
+    onValue = zone.registerUnaryCallback(onValue);
+    onError = zone.registerBinaryCallback(onError);
+  }
+
+  var asyncFuture = _Future<T>();
+
+  // This will be set to true once we've yielded to the event loop.
+  //
+  // Before we've done that, we need to complete the future asynchronously to
+  // match dart2js/VM. See https://github.com/dart-lang/sdk/issues/33330
+  //
+  // Once we've yielded to the event loop we can complete synchronously.
+  // Other implementations call this `isSync` to indicate that.
+  bool isRunningAsEvent = false;
+  runBody() {
+    try {
+      iter = JS('', '#[Symbol.iterator]()', initGenerator());
+      var iteratorValue = JS('', '#.next(null)', iter);
+      var value = JS('', '#.value', iteratorValue);
+      if (JS<bool>('!', '#.done', iteratorValue)) {
+        // TODO(jmesserly): this is a workaround for ignored cast failures.
+        // Remove it once we've fixed those. We should be able to call:
+        //
+        //     if (isRunningAsEvent) {
+        //       asyncFuture._complete(value);
+        //     } else {
+        //       asyncFuture._asyncComplete(value);
+        //     }
+        //
+        // But if the user code returns `Future<dynamic>` instead of
+        // `Future<T>`, that function won't recognize it as a future and will
+        // instead treat it as a completed value.
+        if (value is Future) {
+          if (value is _Future) {
+            _Future._chainCoreFuture(value, asyncFuture);
+          } else {
+            _Future._chainForeignFuture(value, asyncFuture);
+          }
+        } else if (isRunningAsEvent) {
+          asyncFuture._completeWithValue(JS('', '#', value));
+        } else {
+          asyncFuture._asyncComplete(JS('', '#', value));
+        }
+      } else {
+        _Future._chainCoreFuture(onAwait(value), asyncFuture);
+      }
+    } catch (e, s) {
+      if (isRunningAsEvent) {
+        _completeWithErrorCallback(asyncFuture, e, s);
+      } else {
+        _asyncCompleteWithErrorCallback(asyncFuture, e, s);
+      }
+    }
+  }
+
+  if (dart.startAsyncSynchronously) {
+    runBody();
+    isRunningAsEvent = true;
+  } else {
+    isRunningAsEvent = true;
+    scheduleMicrotask(runBody);
+  }
+  return asyncFuture;
+}
+
+@patch
+class _AsyncRun {
+  @patch
+  static void _scheduleImmediate(void Function() callback) {
+    _scheduleImmediateClosure(callback);
+  }
+
+  // Lazily initialized.
+  static final _scheduleImmediateClosure = _initializeScheduleImmediate();
+
+  static void Function(void Function()) _initializeScheduleImmediate() {
+    // d8 support, see preambles/d8.js for the definiton of `scheduleImmediate`.
+    //
+    // TODO(jmesserly): do we need this? It's only for our d8 stack trace test.
+    if (JS('', '#.scheduleImmediate', dart.global_) != null) {
+      return _scheduleImmediateJSOverride;
+    }
+    return _scheduleImmediateWithPromise;
+  }
+
+  @ReifyFunctionTypes(false)
+  static void _scheduleImmediateJSOverride(void Function() callback) {
+    dart.addAsyncCallback();
+    JS('void', '#.scheduleImmediate(#)', dart.global_, () {
+      dart.removeAsyncCallback();
+      callback();
+    });
+  }
+
+  @ReifyFunctionTypes(false)
+  static Object _scheduleImmediateWithPromise(void Function() callback) {
+    dart.addAsyncCallback();
+    JS('', '#.Promise.resolve(null).then(#)', dart.global_, () {
+      dart.removeAsyncCallback();
+      callback();
+    });
+  }
+}
+
+@patch
+class DeferredLibrary {
+  @patch
+  Future<Null> load() {
+    throw 'DeferredLibrary not supported. '
+        'please use the `import "lib.dart" deferred as lib` syntax.';
+  }
+}
+
+@patch
+class Timer {
+  @patch
+  static Timer _createTimer(Duration duration, void callback()) {
+    int milliseconds = duration.inMilliseconds;
+    if (milliseconds < 0) milliseconds = 0;
+    return TimerImpl(milliseconds, callback);
+  }
+
+  @patch
+  static Timer _createPeriodicTimer(
+      Duration duration, void callback(Timer timer)) {
+    int milliseconds = duration.inMilliseconds;
+    if (milliseconds < 0) milliseconds = 0;
+    return TimerImpl.periodic(milliseconds, callback);
+  }
+}
+
+@patch
+void _rethrow(Object error, StackTrace stackTrace) {
+  JS('', 'throw #', dart.createErrorWithStack(error, stackTrace));
+}
+
+/// Used by the compiler to implement `async*` functions.
+///
+/// This is inspired by _AsyncStarStreamController in dart-lang/sdk's
+/// runtime/lib/core_patch.dart
+///
+/// Given input like:
+///
+///     foo() async* {
+///       yield 1;
+///       yield* bar();
+///       print(await baz());
+///     }
+///
+/// This compiles to:
+///
+///     function foo() {
+///       return new (AsyncStarImplOfT()).new(function*(stream) {
+///         if (stream.add(1)) return;
+///         yield;
+///         if (stream.addStream(bar()) return;
+///         yield;
+///         print(yield baz());
+///      });
+///     }
+///
+class _AsyncStarImpl<T> {
+  StreamController<T> controller;
+  Object Function(_AsyncStarImpl<T>) initGenerator;
+  @notNull
+  bool isSuspendedAtYieldStar = false;
+  @notNull
+  bool onListenReceived = false;
+  @notNull
+  bool isScheduled = false;
+  @notNull
+  bool isSuspendedAtYield = false;
+
+  /// Whether we're suspended at an `await`.
+  @notNull
+  bool isSuspendedAtAwait = false;
+
+  Completer cancellationCompleter;
+  Object jsIterator;
+
+  Null Function(Object, StackTrace) _handleErrorCallback;
+  void Function([Object]) _runBodyCallback;
+
+  _AsyncStarImpl(this.initGenerator) {
+    controller = StreamController(
+        onListen: JS('!', 'this.onListen.bind(this)'),
+        onResume: JS('!', 'this.onResume.bind(this)'),
+        onCancel: JS('!', 'this.onCancel.bind(this)'));
+    jsIterator = JS('!', '#[Symbol.iterator]()', initGenerator(this));
+  }
+
+  /// The stream produced by this `async*` function.
+  Stream<T> get stream => controller.stream;
+
+  /// Returns the callback used for error handling.
+  ///
+  /// This callback throws the error back into the user code, at the appropriate
+  /// location (e.g. `await` `yield` or `yield*`). This gives user code a chance
+  /// to handle it try-catch. If they do not handle, the error gets routed to
+  /// the [stream] as an error via [addError].
+  ///
+  /// As a performance optimization, this callback is only bound once to the
+  /// current [Zone]. This works because a single subscription stream should
+  /// always be running in its original zone. An `async*` method will always
+  /// save/restore the zone that was active when `listen()` was first called,
+  /// similar to a stream. This follows from section 16.14 of the Dart 4th
+  /// edition spec:
+  ///
+  /// > If `f` is marked `async*` (9), then a fresh instance `s` implementing
+  /// > the built-in class `Stream` is associated with the invocation and
+  /// > immediately returned. When `s` is listened to, execution of the body of
+  /// > `f` will begin.
+  ///
+  Null Function(Object, StackTrace) get handleError {
+    if (_handleErrorCallback == null) {
+      _handleErrorCallback = (error, StackTrace stackTrace) {
+        try {
+          JS('', '#.throw(#)', jsIterator,
+              dart.createErrorWithStack(error, stackTrace));
+        } catch (e, newStack) {
+          // The generator didn't catch the error, or it threw a new one.
+          // Make sure to propagate the new error.
+          addError(e, newStack);
+        }
+      };
+      var zone = Zone.current;
+      if (!identical(zone, Zone.root)) {
+        _handleErrorCallback = zone.bindBinaryCallback(_handleErrorCallback);
+      }
+    }
+    return _handleErrorCallback;
+  }
+
+  void scheduleGenerator() {
+    // TODO(jmesserly): is this isPaused check in the right place? Assuming the
+    // async* Stream yields, then is paused (by other code), the body will
+    // already be scheduled. This will cause at least one more iteration to
+    // run (adding another data item to the Stream) before actually pausing.
+    // It could be fixed by moving the `isPaused` check inside `runBody`.
+    if (isScheduled ||
+        controller.isPaused ||
+        isSuspendedAtYieldStar ||
+        isSuspendedAtAwait) {
+      return;
+    }
+    isScheduled = true;
+    // Capture the current zone. See comment on [handleError] for more
+    // information about this optimization.
+    var zone = Zone.current;
+    if (_runBodyCallback == null) {
+      _runBodyCallback = JS('!', '#.bind(this)', runBody);
+      if (!identical(zone, Zone.root)) {
+        var registered = zone.registerUnaryCallback(_runBodyCallback);
+        _runBodyCallback = ([arg]) => zone.runUnaryGuarded(registered, arg);
+      }
+    }
+    zone.scheduleMicrotask(_runBodyCallback);
+  }
+
+  void runBody(awaitValue) {
+    isScheduled = false;
+    isSuspendedAtYield = false;
+    isSuspendedAtAwait = false;
+
+    Object iterResult;
+    try {
+      iterResult = JS('', '#.next(#)', jsIterator, awaitValue);
+    } catch (e, s) {
+      addError(e, s);
+      return null;
+    }
+
+    if (JS('!', '#.done', iterResult)) {
+      close();
+      return null;
+    }
+
+    // If we're suspended at a yield/yield*, we're done for now.
+    if (isSuspendedAtYield || isSuspendedAtYieldStar) return null;
+
+    // Handle `await`: if we get a value passed to `yield` it means we are
+    // waiting on this Future. Make sure to prevent scheduling, and pass the
+    // value back as the result of the `yield`.
+    //
+    // TODO(jmesserly): is the timing here correct? The assumption here is
+    // that we should schedule `await` in `async*` the same as in `async`.
+    isSuspendedAtAwait = true;
+    FutureOr<Object> value = JS('', '#.value', iterResult);
+
+    // TODO(jmesserly): this logic was copied from `async` function impl.
+    _Future f;
+    if (value is _Future) {
+      f = value;
+    } else if (value is Future) {
+      f = _Future();
+      _Future._chainForeignFuture(value, f);
+    } else {
+      f = _Future.value(value);
+    }
+    f._thenAwait(_runBodyCallback, handleError);
+  }
+
+  /// Adds element to [stream] and returns true if the caller should terminate
+  /// execution of the generator.
+  ///
+  /// This is called from generated code like this:
+  ///
+  ///     if (controller.add(1)) return;
+  ///     yield;
+  //
+  // TODO(hausner): Per spec, the generator should be suspended before exiting
+  // when the stream is closed. We could add a getter like this:
+  //
+  //     get isCancelled => controller.hasListener;
+  //
+  // The generator would translate a 'yield e' statement to
+  //
+  //     controller.add(1);
+  //     suspend; // this is `yield` in JS.
+  //     if (controller.isCancelled) return;
+  bool add(T event) {
+    if (!onListenReceived) _fatal("yield before stream is listened to");
+    if (isSuspendedAtYield) _fatal("unexpected yield");
+    // If stream is cancelled, tell caller to exit the async generator.
+    if (!controller.hasListener) {
+      return true;
+    }
+    controller.add(event);
+    scheduleGenerator();
+    isSuspendedAtYield = true;
+    return false;
+  }
+
+  /// Adds the elements of [stream] into this [controller]'s stream, and returns
+  /// true if the caller should terminate execution of the generator.
+  ///
+  /// The generator will be scheduled again when all of the elements of the
+  /// added stream have been consumed.
+  bool addStream(Stream<T> stream) {
+    if (!onListenReceived) _fatal("yield* before stream is listened to");
+    // If stream is cancelled, tell caller to exit the async generator.
+    if (!controller.hasListener) return true;
+    isSuspendedAtYieldStar = true;
+    var whenDoneAdding = controller.addStream(stream, cancelOnError: false);
+    whenDoneAdding.then((_) {
+      isSuspendedAtYieldStar = false;
+      scheduleGenerator();
+      if (!isScheduled) isSuspendedAtYield = true;
+    }, onError: handleError);
+    return false;
+  }
+
+  void addError(Object error, StackTrace stackTrace) {
+    if (cancellationCompleter != null && !cancellationCompleter.isCompleted) {
+      // If the stream has been cancelled, complete the cancellation future
+      // with the error.
+      cancellationCompleter.completeError(error, stackTrace);
+    } else if (controller.hasListener) {
+      controller.addError(error, stackTrace);
+    }
+    // No need to schedule the generator body here. This code is only
+    // called from the catch clause of the implicit try-catch-finally
+    // around the generator body. That is, we are on the error path out
+    // of the generator and do not need to run the generator again.
+    close();
+  }
+
+  void close() {
+    if (cancellationCompleter != null && !cancellationCompleter.isCompleted) {
+      // If the stream has been cancelled, complete the cancellation future
+      // with the error.
+      cancellationCompleter.complete();
+    }
+    controller.close();
+  }
+
+  onListen() {
+    assert(!onListenReceived);
+    onListenReceived = true;
+    scheduleGenerator();
+  }
+
+  onResume() {
+    if (isSuspendedAtYield) {
+      scheduleGenerator();
+    }
+  }
+
+  onCancel() {
+    if (controller.isClosed) {
+      return null;
+    }
+    if (cancellationCompleter == null) {
+      cancellationCompleter = Completer();
+      // Only resume the generator if it is suspended at a yield.
+      // Cancellation does not affect an async generator that is
+      // suspended at an await.
+      if (isSuspendedAtYield) {
+        scheduleGenerator();
+      }
+    }
+    return cancellationCompleter.future;
+  }
+
+  _fatal(String message) => throw StateError(message);
+}
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/patch/cli_patch.dart b/sdk_nnbd/lib/_internal/js_dev_runtime/patch/cli_patch.dart
new file mode 100644
index 0000000..b1c3841
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/patch/cli_patch.dart
@@ -0,0 +1,10 @@
+// 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:_js_helper' show patch;
+
+@patch
+void _waitForEvent(int timeoutMillis) {
+  throw UnsupportedError("waitForEvent");
+}
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/patch/collection_patch.dart b/sdk_nnbd/lib/_internal/js_dev_runtime/patch/collection_patch.dart
new file mode 100644
index 0000000..daa3bf8
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/patch/collection_patch.dart
@@ -0,0 +1,602 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Patch file for dart:collection classes.
+import 'dart:_foreign_helper' show JS, JSExportName;
+import 'dart:_runtime' as dart;
+import 'dart:_interceptors' show JSArray;
+import 'dart:_js_helper'
+    show
+        NoInline,
+        NoSideEffects,
+        NoThrows,
+        patch,
+        LinkedMap,
+        IdentityMap,
+        CustomHashMap,
+        CustomKeyHashMap,
+        DartIterator,
+        notNull,
+        putLinkedMapKey;
+
+@patch
+class HashMap<K, V> {
+  @patch
+  factory HashMap(
+      {bool equals(K key1, K key2),
+      int hashCode(K key),
+      bool isValidKey(Object potentialKey)}) {
+    if (isValidKey == null) {
+      if (hashCode == null) {
+        if (equals == null) {
+          if (identical(K, String) || identical(K, int)) {
+            return IdentityMap<K, V>();
+          }
+          return LinkedMap<K, V>();
+        }
+        hashCode = dart.hashCode;
+      } else if (identical(identityHashCode, hashCode) &&
+          identical(identical, equals)) {
+        return IdentityMap<K, V>();
+      }
+      return CustomHashMap<K, V>(equals ?? dart.equals, hashCode);
+    }
+    return CustomKeyHashMap<K, V>(
+        equals ?? dart.equals, hashCode ?? dart.hashCode, isValidKey);
+  }
+
+  @patch
+  factory HashMap.identity() = IdentityMap<K, V>;
+}
+
+@patch
+class LinkedHashMap<K, V> {
+  @patch
+  factory LinkedHashMap(
+      {bool equals(K key1, K key2),
+      int hashCode(K key),
+      bool isValidKey(Object potentialKey)}) {
+    if (isValidKey == null) {
+      if (hashCode == null) {
+        if (equals == null) {
+          if (identical(K, String) || identical(K, int)) {
+            return IdentityMap<K, V>();
+          }
+          return LinkedMap<K, V>();
+        }
+        hashCode = dart.hashCode;
+      } else if (identical(identityHashCode, hashCode) &&
+          identical(identical, equals)) {
+        return IdentityMap<K, V>();
+      }
+      return CustomHashMap<K, V>(equals ?? dart.equals, hashCode);
+    }
+    return CustomKeyHashMap<K, V>(
+        equals ?? dart.equals, hashCode ?? dart.hashCode, isValidKey);
+  }
+
+  @patch
+  factory LinkedHashMap.identity() = IdentityMap<K, V>;
+}
+
+@patch
+class HashSet<E> {
+  @patch
+  factory HashSet(
+      {bool equals(E e1, E e2),
+      int hashCode(E e),
+      bool isValidKey(Object potentialKey)}) {
+    if (isValidKey == null) {
+      if (hashCode == null) {
+        if (equals == null) {
+          if (identical(E, String) || identical(E, int)) {
+            return _IdentityHashSet<E>();
+          }
+          return _HashSet<E>();
+        }
+        hashCode = dart.hashCode;
+      } else if (identical(identityHashCode, hashCode) &&
+          identical(identical, equals)) {
+        return _IdentityHashSet<E>();
+      }
+      return _CustomHashSet<E>(
+          equals ?? dart.equals, hashCode ?? dart.hashCode);
+    }
+    return _CustomKeyHashSet<E>(
+        equals ?? dart.equals, hashCode ?? dart.hashCode, isValidKey);
+  }
+
+  @patch
+  factory HashSet.identity() = _IdentityHashSet<E>;
+}
+
+@patch
+class LinkedHashSet<E> {
+  @patch
+  factory LinkedHashSet(
+      {bool equals(E e1, E e2),
+      int hashCode(E e),
+      bool isValidKey(Object potentialKey)}) {
+    if (isValidKey == null) {
+      if (hashCode == null) {
+        if (equals == null) {
+          if (identical(E, String) || identical(E, int)) {
+            return _IdentityHashSet<E>();
+          }
+          return _HashSet<E>();
+        }
+        hashCode = dart.hashCode;
+      } else if (identical(identityHashCode, hashCode) &&
+          identical(identical, equals)) {
+        return _IdentityHashSet<E>();
+      }
+      return _CustomHashSet<E>(
+          equals ?? dart.equals, hashCode ?? dart.hashCode);
+    }
+    return _CustomKeyHashSet<E>(
+        equals ?? dart.equals, hashCode ?? dart.hashCode, isValidKey);
+  }
+
+  @patch
+  factory LinkedHashSet.identity() = _IdentityHashSet<E>;
+}
+
+class _HashSet<E> extends _InternalSet<E>
+    implements HashSet<E>, LinkedHashSet<E> {
+  /// The backing store for this set.
+  ///
+  /// Keys that use identity equality are stored directly. For other types of
+  /// keys, we first look them up (by hashCode) in the [_keyMap] map, then
+  /// we lookup the key in this map.
+  @notNull
+  final _map = JS('', 'new Set()');
+
+  /// Items that use custom equality semantics.
+  ///
+  /// This maps from the item's hashCode to the canonical key, which is then
+  /// used to lookup the item in [_map]. Keeping the data in our primary backing
+  /// map gives us the ordering semantics requred by [LinkedHashMap], while
+  /// also providing convenient access to keys/values.
+  @notNull
+  final _keyMap = JS('', 'new Map()');
+
+  // We track the number of modifications done to the key set of the
+  // hash map to be able to throw when the map is modified while being
+  // iterated over.
+  //
+  // Value cycles after 2^30 modifications so that modification counts are
+  // always unboxed (Smi) values. Modification detection will be missed if you
+  // make exactly some multiple of 2^30 modifications between advances of an
+  // iterator.
+  @notNull
+  int _modifications = 0;
+
+  _HashSet();
+
+  Set<E> _newSet() => _HashSet<E>();
+
+  Set<R> _newSimilarSet<R>() => _HashSet<R>();
+
+  bool contains(Object key) {
+    if (key == null) {
+      key = null;
+    } else if (JS<bool>('!', '#[#] !== #', key, dart.extensionSymbol('_equals'),
+        dart.identityEquals)) {
+      @notNull
+      var k = key;
+      var buckets = JS('', '#.get(# & 0x3ffffff)', _keyMap, k.hashCode);
+      if (buckets != null) {
+        for (int i = 0, n = JS('!', '#.length', buckets); i < n; i++) {
+          k = JS('', '#[#]', buckets, i);
+          if (k == key) return true;
+        }
+      }
+      return false;
+    }
+    return JS<bool>('!', '#.has(#)', _map, key);
+  }
+
+  E lookup(Object key) {
+    if (key == null) return null;
+    if (JS<bool>('!', '#[#] !== #', key, dart.extensionSymbol('_equals'),
+        dart.identityEquals)) {
+      @notNull
+      var k = key;
+      var buckets = JS('', '#.get(# & 0x3ffffff)', _keyMap, k.hashCode);
+      if (buckets != null) {
+        for (int i = 0, n = JS('!', '#.length', buckets); i < n; i++) {
+          k = JS('', '#[#]', buckets, i);
+          if (k == key) return JS('', '#', k);
+        }
+      }
+      return null;
+    }
+    return JS('', '#.has(#) ? # : null', _map, key, key);
+  }
+
+  bool add(E key) {
+    var map = _map;
+    if (key == null) {
+      if (JS('', '#.has(null)', map)) return false;
+      key = null;
+    } else if (JS<bool>('!', '#[#] !== #', key, dart.extensionSymbol('_equals'),
+        dart.identityEquals)) {
+      var keyMap = _keyMap;
+      @notNull
+      var k = key;
+      int hash = JS('!', '# & 0x3ffffff', k.hashCode);
+      var buckets = JS('', '#.get(#)', keyMap, hash);
+      if (buckets == null) {
+        JS('', '#.set(#, [#])', keyMap, hash, key);
+      } else {
+        for (int i = 0, n = JS('!', '#.length', buckets); i < n; i++) {
+          k = JS('', '#[#]', buckets, i);
+          if (k == key) return false;
+        }
+        JS('', '#.push(#)', buckets, key);
+      }
+    } else if (JS('', '#.has(#)', map, key)) {
+      return false;
+    }
+    JS('', '#.add(#)', map, key);
+    _modifications = (_modifications + 1) & 0x3ffffff;
+    return true;
+  }
+
+  void addAll(Iterable<E> objects) {
+    var map = _map;
+    int length = JS('', '#.size', map);
+    for (E key in objects) {
+      if (key == null) {
+        key = null; // converts undefined to null, if needed.
+      } else if (JS<bool>('!', '#[#] !== #', key,
+          dart.extensionSymbol('_equals'), dart.identityEquals)) {
+        key = putLinkedMapKey(key, _keyMap);
+      }
+      JS('', '#.add(#)', map, key);
+    }
+    if (length != JS<int>('!', '#.size', map)) {
+      _modifications = (_modifications + 1) & 0x3ffffff;
+    }
+  }
+
+  bool remove(Object key) {
+    if (key == null) {
+      key = null;
+    } else if (JS<bool>('!', '#[#] !== #', key, dart.extensionSymbol('_equals'),
+        dart.identityEquals)) {
+      @notNull
+      var k = key;
+      int hash = JS('!', '# & 0x3ffffff', k.hashCode);
+      var buckets = JS('', '#.get(#)', _keyMap, hash);
+      if (buckets == null) return false; // not found
+      for (int i = 0, n = JS('!', '#.length', buckets);;) {
+        k = JS('', '#[#]', buckets, i);
+        if (k == key) {
+          key = k;
+          if (n == 1) {
+            JS('', '#.delete(#)', _keyMap, hash);
+          } else {
+            JS('', '#.splice(#, 1)', buckets, i);
+          }
+          break;
+        }
+        if (++i >= n) return false; // not found
+      }
+    }
+    var map = _map;
+    if (JS<bool>('!', '#.delete(#)', map, key)) {
+      _modifications = (_modifications + 1) & 0x3ffffff;
+      return true;
+    }
+    return false;
+  }
+
+  void clear() {
+    var map = _map;
+    if (JS<int>('!', '#.size', map) > 0) {
+      JS('', '#.clear()', map);
+      JS('', '#.clear()', _keyMap);
+      _modifications = (_modifications + 1) & 0x3ffffff;
+    }
+  }
+}
+
+// Used for DDC const sets.
+class _ImmutableSet<E> extends _HashSet<E> {
+  _ImmutableSet.from(JSArray entries) {
+    var map = _map;
+    for (Object key in entries) {
+      if (key == null) {
+        key = null; // converts undefined to null, if needed.
+      } else if (JS<bool>('!', '#[#] !== #', key,
+          dart.extensionSymbol('_equals'), dart.identityEquals)) {
+        key = putLinkedMapKey(key, _keyMap);
+      }
+      JS('', '#.add(#)', map, key);
+    }
+  }
+
+  bool add(Object other) => throw _unsupported();
+  void addAll(Object other) => throw _unsupported();
+  void clear() => throw _unsupported();
+  bool remove(Object key) => throw _unsupported();
+
+  static Error _unsupported() =>
+      UnsupportedError("Cannot modify unmodifiable set");
+}
+
+class _IdentityHashSet<E> extends _InternalSet<E>
+    implements HashSet<E>, LinkedHashSet<E> {
+  /// The backing store for this set.
+  @notNull
+  final _map = JS('', 'new Set()');
+
+  @notNull
+  int _modifications = 0;
+
+  _IdentityHashSet();
+
+  Set<E> _newSet() => _IdentityHashSet<E>();
+
+  Set<R> _newSimilarSet<R>() => _IdentityHashSet<R>();
+
+  bool contains(Object element) {
+    return JS('', '#.has(#)', _map, element);
+  }
+
+  E lookup(Object element) {
+    return JS('', '#.has(#)', _map, element) ? element : null;
+  }
+
+  bool add(E element) {
+    var map = _map;
+    if (JS<bool>('!', '#.has(#)', map, element)) return false;
+    JS('', '#.add(#)', map, element);
+    _modifications = (_modifications + 1) & 0x3ffffff;
+    return true;
+  }
+
+  void addAll(Iterable<E> objects) {
+    var map = _map;
+    int length = JS('', '#.size', map);
+    for (E key in objects) {
+      JS('', '#.add(#)', map, key);
+    }
+    if (length != JS<int>('!', '#.size', map)) {
+      _modifications = (_modifications + 1) & 0x3ffffff;
+    }
+  }
+
+  bool remove(Object element) {
+    if (JS<bool>('!', '#.delete(#)', _map, element)) {
+      _modifications = (_modifications + 1) & 0x3ffffff;
+      return true;
+    }
+    return false;
+  }
+
+  void clear() {
+    var map = _map;
+    if (JS<int>('!', '#.size', map) > 0) {
+      JS('', '#.clear()', map);
+      _modifications = (_modifications + 1) & 0x3ffffff;
+    }
+  }
+}
+
+class _CustomKeyHashSet<E> extends _CustomHashSet<E> {
+  _Predicate<Object> _validKey;
+  _CustomKeyHashSet(_Equality<E> equals, _Hasher<E> hashCode, this._validKey)
+      : super(equals, hashCode);
+
+  Set<E> _newSet() => _CustomKeyHashSet<E>(_equals, _hashCode, _validKey);
+
+  Set<R> _newSimilarSet<R>() => _HashSet<R>();
+
+  bool contains(Object element) {
+    // TODO(jmesserly): there is a subtle difference here compared to Dart 1.
+    // See the comment on CustomKeyHashMap.containsKey for more information.
+    // Treatment of `null` is different due to strong mode's requirement to
+    // perform an `element is E` check before calling equals/hashCode.
+    if (!_validKey(element)) return false;
+    return super.contains(element);
+  }
+
+  E lookup(Object element) {
+    if (!_validKey(element)) return null;
+    return super.lookup(element);
+  }
+
+  bool remove(Object element) {
+    if (!_validKey(element)) return false;
+    return super.remove(element);
+  }
+}
+
+class _CustomHashSet<E> extends _InternalSet<E>
+    implements HashSet<E>, LinkedHashSet<E> {
+  _Equality<E> _equals;
+  _Hasher<E> _hashCode;
+
+  // We track the number of modifications done to the key set of the
+  // hash map to be able to throw when the map is modified while being
+  // iterated over.
+  //
+  // Value cycles after 2^30 modifications so that modification counts are
+  // always unboxed (Smi) values. Modification detection will be missed if you
+  // make exactly some multiple of 2^30 modifications between advances of an
+  // iterator.
+  @notNull
+  int _modifications = 0;
+
+  /// The backing store for this set, used to handle ordering.
+  // TODO(jmesserly): a non-linked custom hash set could skip this.
+  @notNull
+  final _map = JS('', 'new Set()');
+
+  /// Our map used to map keys onto the canonical key that is stored in [_map].
+  @notNull
+  final _keyMap = JS('', 'new Map()');
+
+  _CustomHashSet(this._equals, this._hashCode);
+
+  Set<E> _newSet() => _CustomHashSet<E>(_equals, _hashCode);
+  Set<R> _newSimilarSet<R>() => _HashSet<R>();
+
+  bool contains(Object key) {
+    if (key is E) {
+      var buckets = JS('', '#.get(# & 0x3ffffff)', _keyMap, _hashCode(key));
+      if (buckets != null) {
+        var equals = _equals;
+        for (int i = 0, n = JS('!', '#.length', buckets); i < n; i++) {
+          E k = JS('', '#[#]', buckets, i);
+          if (equals(k, key)) return true;
+        }
+      }
+    }
+    return false;
+  }
+
+  E lookup(Object key) {
+    if (key is E) {
+      var buckets = JS('', '#.get(# & 0x3ffffff)', _keyMap, _hashCode(key));
+      if (buckets != null) {
+        var equals = _equals;
+        for (int i = 0, n = JS('!', '#.length', buckets); i < n; i++) {
+          E k = JS('', '#[#]', buckets, i);
+          if (equals(k, key)) return k;
+        }
+      }
+    }
+    return null;
+  }
+
+  bool add(E key) {
+    var keyMap = _keyMap;
+    var hash = JS<int>('!', '# & 0x3ffffff', _hashCode(key));
+    var buckets = JS('', '#.get(#)', keyMap, hash);
+    if (buckets == null) {
+      JS('', '#.set(#, [#])', keyMap, hash, key);
+    } else {
+      var equals = _equals;
+      for (int i = 0, n = JS('!', '#.length', buckets); i < n; i++) {
+        E k = JS('', '#[#]', buckets, i);
+        if (equals(k, key)) return false;
+      }
+      JS('', '#.push(#)', buckets, key);
+    }
+    JS('', '#.add(#)', _map, key);
+    _modifications = (_modifications + 1) & 0x3ffffff;
+    return true;
+  }
+
+  void addAll(Iterable<E> objects) {
+    // TODO(jmesserly): it'd be nice to skip the covariance check here.
+    for (E element in objects) add(element);
+  }
+
+  bool remove(Object key) {
+    if (key is E) {
+      var hash = JS<int>('!', '# & 0x3ffffff', _hashCode(key));
+      var keyMap = _keyMap;
+      var buckets = JS('', '#.get(#)', keyMap, hash);
+      if (buckets == null) return false; // not found
+      var equals = _equals;
+      for (int i = 0, n = JS('!', '#.length', buckets); i < n; i++) {
+        E k = JS('', '#[#]', buckets, i);
+        if (equals(k, key)) {
+          if (n == 1) {
+            JS('', '#.delete(#)', keyMap, hash);
+          } else {
+            JS('', '#.splice(#, 1)', buckets, i);
+          }
+          JS('', '#.delete(#)', _map, k);
+          _modifications = (_modifications + 1) & 0x3ffffff;
+          return true;
+        }
+      }
+    }
+    return false;
+  }
+
+  void clear() {
+    var map = _map;
+    if (JS<int>('!', '#.size', map) > 0) {
+      JS('', '#.clear()', map);
+      JS('', '#.clear()', _keyMap);
+      _modifications = (_modifications + 1) & 0x3ffffff;
+    }
+  }
+}
+
+/// Base class for our internal [LinkedHashSet]/[HashSet] implementations.
+///
+/// This implements the common functionality.
+abstract class _InternalSet<E> extends _SetBase<E> {
+  @notNull
+  get _map;
+
+  @notNull
+  int get _modifications;
+
+  @notNull
+  int get length => JS<int>('!', '#.size', _map);
+
+  @notNull
+  bool get isEmpty => JS<bool>('!', '#.size == 0', _map);
+
+  @notNull
+  bool get isNotEmpty => JS<bool>('!', '#.size != 0', _map);
+
+  Iterator<E> get iterator => DartIterator<E>(_jsIterator());
+
+  @JSExportName('Symbol.iterator')
+  _jsIterator() {
+    var self = this;
+    var iterator = JS('', '#.values()', self._map);
+    int modifications = self._modifications;
+    return JS(
+        '',
+        '''{
+      next() {
+        if (# != #) {
+          throw #;
+        }
+        return #.next();
+      }
+    }''',
+        modifications,
+        self._modifications,
+        ConcurrentModificationError(self),
+        iterator);
+  }
+}
+
+@patch
+abstract class _SplayTree<K, Node extends _SplayTreeNode<K>> {
+  @patch
+  Node _splayMin(Node node) {
+    Node current = node;
+    while (current.left != null) {
+      Node left = current.left;
+      current.left = left.right;
+      left.right = current;
+      current = left;
+    }
+    return current;
+  }
+
+  @patch
+  Node _splayMax(Node node) {
+    Node current = node;
+    while (current.right != null) {
+      Node right = current.right;
+      current.right = right.left;
+      right.left = current;
+      current = right;
+    }
+    return current;
+  }
+}
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/patch/convert_patch.dart b/sdk_nnbd/lib/_internal/js_dev_runtime/patch/convert_patch.dart
new file mode 100644
index 0000000..486473b
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/patch/convert_patch.dart
@@ -0,0 +1,508 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Patch file for dart:convert library.
+
+import 'dart:_js_helper' show argumentErrorValue, patch;
+import 'dart:_foreign_helper' show JS;
+import 'dart:_interceptors' show JSExtendableArray;
+import 'dart:_internal' show MappedIterable, ListIterable;
+import 'dart:collection' show Maps, LinkedHashMap, MapBase;
+import 'dart:_native_typed_data' show NativeUint8List;
+
+/**
+ * Parses [json] and builds the corresponding parsed JSON value.
+ *
+ * Parsed JSON values Nare of the types [num], [String], [bool], [Null],
+ * [List]s of parsed JSON values or [Map]s from [String] to parsed
+ * JSON values.
+ *
+ * The optional [reviver] function, if provided, is called once for each object
+ * or list property parsed. The arguments are the property name ([String]) or
+ * list index ([int]), and the value is the parsed value.  The return value of
+ * the reviver will be used as the value of that property instead of the parsed
+ * value.  The top level value is passed to the reviver with the empty string as
+ * a key.
+ *
+ * Throws [FormatException] if the input is not valid JSON text.
+ */
+@patch
+_parseJson(String source, reviver(Object key, Object value)) {
+  if (source is! String) throw argumentErrorValue(source);
+
+  var parsed;
+  try {
+    parsed = JS('=Object|JSExtendableArray|Null|bool|num|String',
+        'JSON.parse(#)', source);
+  } catch (e) {
+    throw FormatException(JS<String>('!', 'String(#)', e));
+  }
+
+  if (reviver == null) {
+    return _convertJsonToDartLazy(parsed);
+  } else {
+    return _convertJsonToDart(parsed, reviver);
+  }
+}
+
+/**
+ * Walks the raw JavaScript value [json], replacing JavaScript Objects with
+ * Maps. [json] is expected to be freshly allocated so elements can be replaced
+ * in-place.
+ */
+_convertJsonToDart(json, reviver(Object key, Object value)) {
+  assert(reviver != null);
+  walk(e) {
+    // JavaScript null, string, number, bool are in the correct representation.
+    if (JS<bool>('!', '# == null', e) ||
+        JS<bool>('!', 'typeof # != "object"', e)) {
+      return e;
+    }
+
+    // This test is needed to avoid identifying '{"__proto__":[]}' as an Array.
+    // TODO(sra): Replace this test with cheaper '#.constructor === Array' when
+    // bug 621 below is fixed.
+    if (JS<bool>('!', 'Object.getPrototypeOf(#) === Array.prototype', e)) {
+      // In-place update of the elements since JS Array is a Dart List.
+      for (int i = 0; i < JS<int>('!', '#.length', e); i++) {
+        // Use JS indexing to avoid range checks.  We know this is the only
+        // reference to the list, but the compiler will likely never be able to
+        // tell that this instance of the list cannot have its length changed by
+        // the reviver even though it later will be passed to the reviver at the
+        // outer level.
+        var item = JS('', '#[#]', e, i);
+        JS('', '#[#]=#', e, i, reviver(i, walk(item)));
+      }
+      return e;
+    }
+
+    // Otherwise it is a plain object, so copy to a JSON map, so we process
+    // and revive all entries recursively.
+    _JsonMap map = _JsonMap(e);
+    var processed = map._processed;
+    List<String> keys = map._computeKeys();
+    for (int i = 0; i < keys.length; i++) {
+      String key = keys[i];
+      var revived = reviver(key, walk(JS('', '#[#]', e, key)));
+      JS('', '#[#]=#', processed, key, revived);
+    }
+
+    // Update the JSON map structure so future access is cheaper.
+    map._original = processed; // Don't keep two objects around.
+    return map;
+  }
+
+  return reviver(null, walk(json));
+}
+
+_convertJsonToDartLazy(object) {
+  // JavaScript null and undefined are represented as null.
+  if (object == null) return null;
+
+  // JavaScript string, number, bool already has the correct representation.
+  if (JS<bool>('!', 'typeof # != "object"', object)) {
+    return object;
+  }
+
+  // This test is needed to avoid identifying '{"__proto__":[]}' as an array.
+  // TODO(sra): Replace this test with cheaper '#.constructor === Array' when
+  // bug https://code.google.com/p/v8/issues/detail?id=621 is fixed.
+  if (JS<bool>('!', 'Object.getPrototypeOf(#) !== Array.prototype', object)) {
+    return _JsonMap(object);
+  }
+
+  // Update the elements in place since JS arrays are Dart lists.
+  for (int i = 0; i < JS<int>('!', '#.length', object); i++) {
+    // Use JS indexing to avoid range checks.  We know this is the only
+    // reference to the list, but the compiler will likely never be able to
+    // tell that this instance of the list cannot have its length changed by
+    // the reviver even though it later will be passed to the reviver at the
+    // outer level.
+    var item = JS('', '#[#]', object, i);
+    JS('', '#[#]=#', object, i, _convertJsonToDartLazy(item));
+  }
+  return object;
+}
+
+class _JsonMap extends MapBase<String, dynamic> {
+  // The original JavaScript object remains unchanged until
+  // the map is eventually upgraded, in which case we null it
+  // out to reclaim the memory used by it.
+  var _original;
+
+  // We keep track of the map entries that we have already
+  // processed by adding them to a separate JavaScript object.
+  var _processed = _newJavaScriptObject();
+
+  // If the data slot isn't null, it represents either the list
+  // of keys (for non-upgraded JSON maps) or the upgraded map.
+  var _data = null;
+
+  _JsonMap(this._original);
+
+  operator [](key) {
+    if (_isUpgraded) {
+      return _upgradedMap[key];
+    } else if (key is! String) {
+      return null;
+    } else {
+      var result = _getProperty(_processed, key);
+      if (_isUnprocessed(result)) result = _process(key);
+      return result;
+    }
+  }
+
+  int get length => _isUpgraded ? _upgradedMap.length : _computeKeys().length;
+
+  bool get isEmpty => length == 0;
+  bool get isNotEmpty => length > 0;
+
+  Iterable<String> get keys {
+    if (_isUpgraded) return _upgradedMap.keys;
+    return _JsonMapKeyIterable(this);
+  }
+
+  Iterable get values {
+    if (_isUpgraded) return _upgradedMap.values;
+    return MappedIterable(_computeKeys(), (each) => this[each]);
+  }
+
+  operator []=(key, value) {
+    if (_isUpgraded) {
+      _upgradedMap[key] = value;
+    } else if (containsKey(key)) {
+      var processed = _processed;
+      _setProperty(processed, key, value);
+      var original = _original;
+      if (!identical(original, processed)) {
+        _setProperty(original, key, null); // Reclaim memory.
+      }
+    } else {
+      _upgrade()[key] = value;
+    }
+  }
+
+  void addAll(Map<String, dynamic> other) {
+    other.forEach((key, value) {
+      this[key] = value;
+    });
+  }
+
+  bool containsValue(value) {
+    if (_isUpgraded) return _upgradedMap.containsValue(value);
+    List<String> keys = _computeKeys();
+    for (int i = 0; i < keys.length; i++) {
+      String key = keys[i];
+      if (this[key] == value) return true;
+    }
+    return false;
+  }
+
+  bool containsKey(key) {
+    if (_isUpgraded) return _upgradedMap.containsKey(key);
+    if (key is! String) return false;
+    return _hasProperty(_original, key);
+  }
+
+  putIfAbsent(key, ifAbsent()) {
+    if (containsKey(key)) return this[key];
+    var value = ifAbsent();
+    this[key] = value;
+    return value;
+  }
+
+  remove(Object key) {
+    if (!_isUpgraded && !containsKey(key)) return null;
+    return _upgrade().remove(key);
+  }
+
+  void clear() {
+    if (_isUpgraded) {
+      _upgradedMap.clear();
+    } else {
+      if (_data != null) {
+        // Clear the list of keys to make sure we force
+        // a concurrent modification error if anyone is
+        // currently iterating over it.
+        _data.clear();
+      }
+      _original = _processed = null;
+      _data = {};
+    }
+  }
+
+  void forEach(void f(String key, value)) {
+    if (_isUpgraded) return _upgradedMap.forEach(f);
+    List<String> keys = _computeKeys();
+    for (int i = 0; i < keys.length; i++) {
+      String key = keys[i];
+
+      // Compute the value under the assumption that the property
+      // is present but potentially not processed.
+      var value = _getProperty(_processed, key);
+      if (_isUnprocessed(value)) {
+        value = _convertJsonToDartLazy(_getProperty(_original, key));
+        _setProperty(_processed, key, value);
+      }
+
+      // Do the callback.
+      f(key, value);
+
+      // Check if invoking the callback function changed
+      // the key set. If so, throw an exception.
+      if (!identical(keys, _data)) {
+        throw ConcurrentModificationError(this);
+      }
+    }
+  }
+
+  // ------------------------------------------
+  // Private helper methods.
+  // ------------------------------------------
+
+  bool get _isUpgraded => _processed == null;
+
+  Map<String, dynamic> get _upgradedMap {
+    assert(_isUpgraded);
+    // 'cast' the union type to LinkedHashMap.  It would be even better if we
+    // could 'cast' to the implementation type, since LinkedHashMap includes
+    // _JsonMap.
+    return JS('LinkedHashMap', '#', _data);
+  }
+
+  List<String> _computeKeys() {
+    assert(!_isUpgraded);
+    List keys = _data;
+    if (keys == null) {
+      keys = _data = _getPropertyNames(_original);
+    }
+    return JS('JSExtendableArray', '#', keys);
+  }
+
+  Map<String, dynamic> _upgrade() {
+    if (_isUpgraded) return _upgradedMap;
+
+    // Copy all the (key, value) pairs to a freshly allocated
+    // linked hash map thus preserving the ordering.
+    var result = <String, dynamic>{};
+    List<String> keys = _computeKeys();
+    for (int i = 0; i < keys.length; i++) {
+      String key = keys[i];
+      result[key] = this[key];
+    }
+
+    // We only upgrade when we need to extend the map, so we can
+    // safely force a concurrent modification error in case
+    // someone is iterating over the map here.
+    if (keys.isEmpty) {
+      keys.add(null);
+    } else {
+      keys.clear();
+    }
+
+    // Clear out the associated JavaScript objects and mark the
+    // map as having been upgraded.
+    _original = _processed = null;
+    _data = result;
+    assert(_isUpgraded);
+    return result;
+  }
+
+  _process(String key) {
+    if (!_hasProperty(_original, key)) return null;
+    var result = _convertJsonToDartLazy(_getProperty(_original, key));
+    return _setProperty(_processed, key, result);
+  }
+
+  // ------------------------------------------
+  // Private JavaScript helper methods.
+  // ------------------------------------------
+
+  static bool _hasProperty(object, String key) =>
+      JS<bool>('!', 'Object.prototype.hasOwnProperty.call(#,#)', object, key);
+  static _getProperty(object, String key) => JS('', '#[#]', object, key);
+  static _setProperty(object, String key, value) =>
+      JS('', '#[#]=#', object, key, value);
+  static List _getPropertyNames(object) =>
+      JS('JSExtendableArray', 'Object.keys(#)', object);
+  static bool _isUnprocessed(object) =>
+      JS<bool>('!', 'typeof(#)=="undefined"', object);
+  static _newJavaScriptObject() => JS('=Object', 'Object.create(null)');
+}
+
+class _JsonMapKeyIterable extends ListIterable<String> {
+  final _JsonMap _parent;
+
+  _JsonMapKeyIterable(this._parent);
+
+  int get length => _parent.length;
+
+  String elementAt(int index) {
+    return _parent._isUpgraded
+        ? _parent.keys.elementAt(index)
+        : _parent._computeKeys()[index];
+  }
+
+  /// Although [ListIterable] defines its own iterator, we return the iterator
+  /// of the underlying list [_keys] in order to propagate
+  /// [ConcurrentModificationError]s.
+  Iterator<String> get iterator {
+    return _parent._isUpgraded
+        ? _parent.keys.iterator
+        : _parent._computeKeys().iterator;
+  }
+
+  /// Delegate to [parent.containsKey] to ensure the performance expected
+  /// from [Map.keys.containsKey].
+  bool contains(Object key) => _parent.containsKey(key);
+}
+
+@patch
+class JsonDecoder {
+  @patch
+  StringConversionSink startChunkedConversion(Sink<Object> sink) {
+    return _JsonDecoderSink(_reviver, sink);
+  }
+}
+
+/**
+ * Implements the chunked conversion from a JSON string to its corresponding
+ * object.
+ *
+ * The sink only creates one object, but its input can be chunked.
+ */
+// TODO(floitsch): don't accumulate everything before starting to decode.
+class _JsonDecoderSink extends _StringSinkConversionSink {
+  final Function(Object key, Object value) _reviver;
+  final Sink<Object> _sink;
+
+  _JsonDecoderSink(this._reviver, this._sink) : super(StringBuffer(''));
+
+  void close() {
+    super.close();
+    StringBuffer buffer = _stringSink;
+    String accumulated = buffer.toString();
+    buffer.clear();
+    Object decoded = _parseJson(accumulated, _reviver);
+    _sink.add(decoded);
+    _sink.close();
+  }
+}
+
+@patch
+class Utf8Decoder {
+  @patch
+  Converter<List<int>, T> fuse<T>(Converter<String, T> next) {
+    return super.fuse(next);
+  }
+
+  // Currently not intercepting UTF8 decoding.
+  @patch
+  static String _convertIntercepted(
+      bool allowMalformed, List<int> codeUnits, int start, int end) {
+    // Test `codeUnits is NativeUint8List`. Dart's NativeUint8List is
+    // implemented by JavaScript's Uint8Array.
+    if (JS<bool>('!', '# instanceof Uint8Array', codeUnits)) {
+      // JS 'cast' to avoid a downcast equivalent to the is-check we hand-coded.
+      NativeUint8List casted = JS<NativeUint8List>('!', '#', codeUnits);
+      return _convertInterceptedUint8List(allowMalformed, casted, start, end);
+    }
+  }
+
+  static String _convertInterceptedUint8List(
+      bool allowMalformed, NativeUint8List codeUnits, int start, int end) {
+    if (allowMalformed) {
+      // TextDecoder with option {fatal: false} does not produce the same result
+      // as [Utf8Decoder]. It disagrees on the number of `U+FFFD` (REPLACEMENT
+      // CHARACTER) generated for some malformed sequences. We could use
+      // TextDecoder with option {fatal: true}, catch the error, and re-try
+      // without acceleration. That turns out to be extremely slow (the Error
+      // captures a stack trace).
+      // TODO(31370): Bring Utf8Decoder into alignment with TextDecoder.
+      // TODO(sra): If we can't do that, can we detect valid input fast enough
+      // to use a check like the [_unsafe] check below?
+      return null;
+    }
+
+    var decoder = _decoder;
+    if (decoder == null) return null;
+    if (0 == start && end == null) {
+      return _useTextDecoderChecked(decoder, codeUnits);
+    }
+
+    int length = codeUnits.length;
+    end = RangeError.checkValidRange(start, end, length);
+
+    if (0 == start && end == codeUnits.length) {
+      return _useTextDecoderChecked(decoder, codeUnits);
+    }
+
+    return _useTextDecoderChecked(decoder,
+        JS<NativeUint8List>('!', '#.subarray(#, #)', codeUnits, start, end));
+  }
+
+  static String _useTextDecoderChecked(decoder, NativeUint8List codeUnits) {
+    if (_unsafe(codeUnits)) return null;
+    return _useTextDecoderUnchecked(decoder, codeUnits);
+  }
+
+  static String _useTextDecoderUnchecked(decoder, NativeUint8List codeUnits) {
+    // If the input is malformed, catch the exception and return `null` to fall
+    // back on unintercepted decoder. The fallback will either succeed in
+    // decoding, or report the problem better than TextDecoder.
+    try {
+      return JS<String>('!', '#.decode(#)', decoder, codeUnits);
+    } catch (e) {}
+    return null;
+  }
+
+  /// Returns `true` if [codeUnits] contains problematic encodings.
+  ///
+  /// TextDecoder behaves differently to [Utf8Encoder] when the input encodes a
+  /// surrogate (U+D800 through U+DFFF). TextDecoder considers the surrogate to
+  /// be an encoding error and, depending on the `fatal` option, either throws
+  /// and Error or encodes the surrogate as U+FFFD. [Utf8Decoder] does not
+  /// consider the surrogate to be an error and returns the code unit encoded by
+  /// the surrogate.
+  ///
+  /// Throwing an `Error` captures the stack, whoch makes it so expensive that
+  /// it is worth checking the input for surrogates and avoiding TextDecoder in
+  /// this case.
+  static bool _unsafe(NativeUint8List codeUnits) {
+    // Surrogates encode as (hex) ED Ax xx or ED Bx xx.
+    int limit = codeUnits.length - 2;
+    for (int i = 0; i < limit; i++) {
+      int unit1 = codeUnits[i];
+      if (unit1 == 0xED) {
+        int unit2 = JS('!', '#', codeUnits[i + 1]);
+        if ((unit2 & 0xE0) == 0xA0) return true;
+      }
+    }
+    return false;
+  }
+
+  //// TextDecoder is not defined on some browsers and on the stand-alone d8 and
+  /// jsshell engines. Use a lazy initializer to do feature detection once.
+  static final _decoder = () {
+    try {
+      // Use `{fatal: true}`. 'fatal' does not correspond exactly to
+      // `!allowMalformed`: TextDecoder rejects unpaired surrogates which
+      // [Utf8Decoder] accepts.  In non-fatal mode, TextDecoder translates
+      // unpaired surrogates to REPLACEMENT CHARACTER (U+FFFD) whereas
+      // [Utf8Decoder] leaves the surrogate intact.
+      return JS('', 'new TextDecoder("utf-8", {fatal: true})');
+    } catch (e) {}
+    return null;
+  }();
+}
+
+@patch
+int _scanOneByteCharacters(List<int> units, int from, int endIndex) {
+  final to = endIndex;
+  for (var i = from; i < to; i++) {
+    final unit = units[i];
+    if ((unit & _ONE_BYTE_LIMIT) != unit) return i - from;
+  }
+  return to - from;
+}
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/patch/core_patch.dart b/sdk_nnbd/lib/_internal/js_dev_runtime/patch/core_patch.dart
new file mode 100644
index 0000000..746ac61
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/patch/core_patch.dart
@@ -0,0 +1,2910 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Patch file for dart:core classes.
+import "dart:_internal" as _symbol_dev;
+import 'dart:_interceptors';
+import 'dart:_js_helper'
+    show
+        patch,
+        checkInt,
+        getRuntimeType,
+        LinkedMap,
+        JSSyntaxRegExp,
+        NoInline,
+        notNull,
+        nullCheck,
+        Primitives,
+        PrivateSymbol,
+        quoteStringForRegExp,
+        undefined;
+import 'dart:_runtime' as dart;
+import 'dart:_foreign_helper' show JS;
+import 'dart:_native_typed_data' show NativeUint8List;
+import 'dart:collection' show UnmodifiableMapView;
+import 'dart:convert' show Encoding, utf8;
+import 'dart:typed_data' show Endian, Uint8List, Uint16List;
+
+String _symbolToString(Symbol symbol) => symbol is PrivateSymbol
+    ? PrivateSymbol.getName(symbol)
+    : _symbol_dev.Symbol.getName(symbol);
+
+@patch
+int identityHashCode(Object object) {
+  if (object == null) return 0;
+  // Note: this works for primitives because we define the `identityHashCode`
+  // for them to be equivalent to their computed hashCode function.
+  int hash = JS('int|Null', r'#[#]', object, dart.identityHashCode_);
+  if (hash == null) {
+    hash = JS<int>('!', '(Math.random() * 0x3fffffff) | 0');
+    JS('void', r'#[#] = #', object, dart.identityHashCode_, hash);
+  }
+  return JS<int>('!', '#', hash);
+}
+
+// Patch for Object implementation.
+@patch
+class Object {
+  @patch
+  bool operator ==(other) => identical(this, other);
+
+  @patch
+  int get hashCode => identityHashCode(this);
+
+  @patch
+  String toString() =>
+      "Instance of '${dart.typeName(dart.getReifiedType(this))}'";
+
+  @patch
+  noSuchMethod(Invocation invocation) {
+    return dart.defaultNoSuchMethod(this, invocation);
+  }
+
+  @patch
+  Type get runtimeType => dart.wrapType(dart.getReifiedType(this));
+}
+
+@patch
+class Null {
+  @patch
+  int get hashCode => super.hashCode;
+}
+
+// Patch for Function implementation.
+@patch
+class Function {
+  @patch
+  static apply(Function f, List positionalArguments,
+      [Map<Symbol, dynamic> namedArguments]) {
+    positionalArguments ??= [];
+    // dcall expects the namedArguments as a JS map in the last slot.
+    if (namedArguments != null && namedArguments.isNotEmpty) {
+      var map = JS('', '{}');
+      namedArguments.forEach((symbol, arg) {
+        JS('', '#[#] = #', map, _symbolToString(symbol), arg);
+      });
+      return dart.dcall(f, positionalArguments, map);
+    }
+    return dart.dcall(f, positionalArguments);
+  }
+
+  static Map<String, dynamic> _toMangledNames(
+      Map<Symbol, dynamic> namedArguments) {
+    Map<String, dynamic> result = {};
+    namedArguments.forEach((symbol, value) {
+      result[_symbolToString(symbol)] = value;
+    });
+    return result;
+  }
+}
+
+// TODO(jmesserly): switch to WeakMap
+// Patch for Expando implementation.
+@patch
+class Expando<T> {
+  @patch
+  Expando([String name]) : this.name = name;
+
+  @patch
+  T operator [](Object object) {
+    var values = Primitives.getProperty(object, _EXPANDO_PROPERTY_NAME);
+    return (values == null) ? null : Primitives.getProperty(values, _getKey());
+  }
+
+  @patch
+  void operator []=(Object object, T value) {
+    var values = Primitives.getProperty(object, _EXPANDO_PROPERTY_NAME);
+    if (values == null) {
+      values = Object();
+      Primitives.setProperty(object, _EXPANDO_PROPERTY_NAME, values);
+    }
+    Primitives.setProperty(values, _getKey(), value);
+  }
+
+  String _getKey() {
+    String key = Primitives.getProperty(this, _KEY_PROPERTY_NAME);
+    if (key == null) {
+      key = "expando\$key\$${_keyCount++}";
+      Primitives.setProperty(this, _KEY_PROPERTY_NAME, key);
+    }
+    return key;
+  }
+
+  static const String _KEY_PROPERTY_NAME = 'expando\$key';
+  static const String _EXPANDO_PROPERTY_NAME = 'expando\$values';
+  static int _keyCount = 0;
+}
+
+Null _kNull(_) => null;
+
+@patch
+class int {
+  @patch
+  static int parse(String source,
+      {int radix, @deprecated int onError(String source)}) {
+    return Primitives.parseInt(source, radix, onError);
+  }
+
+  @patch
+  static int tryParse(String source, {int radix}) {
+    return Primitives.parseInt(source, radix, _kNull);
+  }
+
+  @patch
+  factory int.fromEnvironment(String name, {int defaultValue}) {
+    // ignore: const_constructor_throws_exception
+    throw UnsupportedError(
+        'int.fromEnvironment can only be used as a const constructor');
+  }
+}
+
+@patch
+class double {
+  @patch
+  static double parse(String source,
+      [@deprecated double onError(String source)]) {
+    return Primitives.parseDouble(source, onError);
+  }
+
+  @patch
+  static double tryParse(String source) {
+    return Primitives.parseDouble(source, _kNull);
+  }
+}
+
+@patch
+class BigInt implements Comparable<BigInt> {
+  @patch
+  static BigInt get zero => _BigIntImpl.zero;
+  @patch
+  static BigInt get one => _BigIntImpl.one;
+  @patch
+  static BigInt get two => _BigIntImpl.two;
+
+  @patch
+  static BigInt parse(String source, {int radix}) =>
+      _BigIntImpl.parse(source, radix: radix);
+
+  @patch
+  static BigInt tryParse(String source, {int radix}) =>
+      _BigIntImpl._tryParse(source, radix: radix);
+
+  @patch
+  factory BigInt.from(num value) = _BigIntImpl.from;
+}
+
+@patch
+class Error {
+  @patch
+  static String _objectToString(Object object) {
+    return "Instance of '${dart.typeName(dart.getReifiedType(object))}'";
+  }
+
+  @patch
+  static String _stringToSafeString(String string) {
+    return JS("String", "JSON.stringify(#)", string);
+  }
+
+  @patch
+  StackTrace get stackTrace => dart.stackTraceForError(this);
+}
+
+@patch
+class FallThroughError {
+  @patch
+  FallThroughError._create(String url, int line);
+
+  @patch
+  String toString() => super.toString();
+}
+
+@patch
+class AbstractClassInstantiationError {
+  @patch
+  String toString() => "Cannot instantiate abstract class: '$_className'";
+}
+
+// Patch for DateTime implementation.
+@patch
+class DateTime {
+  @patch
+  DateTime.fromMillisecondsSinceEpoch(int millisecondsSinceEpoch,
+      {bool isUtc = false})
+      : this._withValue(millisecondsSinceEpoch, isUtc: isUtc);
+
+  @patch
+  DateTime.fromMicrosecondsSinceEpoch(int microsecondsSinceEpoch,
+      {bool isUtc = false})
+      : this._withValue(
+            _microsecondInRoundedMilliseconds(microsecondsSinceEpoch),
+            isUtc: isUtc);
+
+  @patch
+  DateTime._internal(int year, int month, int day, int hour, int minute,
+      int second, int millisecond, int microsecond, bool isUtc)
+      // checkBool is manually inlined here because dart2js doesn't inline it
+      // and [isUtc] is usually a constant.
+      : this.isUtc =
+            isUtc is bool ? isUtc : throw ArgumentError.value(isUtc, 'isUtc'),
+        _value = checkInt(Primitives.valueFromDecomposedDate(
+            year,
+            month,
+            day,
+            hour,
+            minute,
+            second,
+            millisecond + _microsecondInRoundedMilliseconds(microsecond),
+            isUtc));
+
+  @patch
+  DateTime._now()
+      : isUtc = false,
+        _value = Primitives.dateNow();
+
+  /// Rounds the given [microsecond] to the nearest milliseconds value.
+  ///
+  /// For example, invoked with argument `2600` returns `3`.
+  static int _microsecondInRoundedMilliseconds(int microsecond) {
+    return (microsecond / 1000).round();
+  }
+
+  @patch
+  static int _brokenDownDateToValue(int year, int month, int day, int hour,
+      int minute, int second, int millisecond, int microsecond, bool isUtc) {
+    return Primitives.valueFromDecomposedDate(
+        year,
+        month,
+        day,
+        hour,
+        minute,
+        second,
+        millisecond + _microsecondInRoundedMilliseconds(microsecond),
+        isUtc);
+  }
+
+  @patch
+  String get timeZoneName {
+    if (isUtc) return "UTC";
+    return Primitives.getTimeZoneName(this);
+  }
+
+  @patch
+  Duration get timeZoneOffset {
+    if (isUtc) return Duration();
+    return Duration(minutes: Primitives.getTimeZoneOffsetInMinutes(this));
+  }
+
+  @patch
+  DateTime add(Duration duration) {
+    return DateTime._withValue(_value + duration.inMilliseconds, isUtc: isUtc);
+  }
+
+  @patch
+  DateTime subtract(Duration duration) {
+    return DateTime._withValue(_value - duration.inMilliseconds, isUtc: isUtc);
+  }
+
+  @patch
+  Duration difference(DateTime other) {
+    return Duration(milliseconds: _value - other._value);
+  }
+
+  @patch
+  int get millisecondsSinceEpoch => _value;
+
+  @patch
+  int get microsecondsSinceEpoch => _value * 1000;
+
+  @patch
+  int get year => Primitives.getYear(this);
+
+  @patch
+  int get month => Primitives.getMonth(this);
+
+  @patch
+  int get day => Primitives.getDay(this);
+
+  @patch
+  int get hour => Primitives.getHours(this);
+
+  @patch
+  int get minute => Primitives.getMinutes(this);
+
+  @patch
+  int get second => Primitives.getSeconds(this);
+
+  @patch
+  int get millisecond => Primitives.getMilliseconds(this);
+
+  @patch
+  int get microsecond => 0;
+
+  @patch
+  int get weekday => Primitives.getWeekday(this);
+
+  @patch
+  bool operator ==(dynamic other) =>
+      other is DateTime &&
+      _value == other.millisecondsSinceEpoch &&
+      isUtc == other.isUtc;
+
+  @patch
+  bool isBefore(DateTime other) => _value < other.millisecondsSinceEpoch;
+
+  @patch
+  bool isAfter(DateTime other) => _value > other.millisecondsSinceEpoch;
+
+  @patch
+  bool isAtSameMomentAs(DateTime other) =>
+      _value == other.millisecondsSinceEpoch;
+
+  @patch
+  int compareTo(DateTime other) =>
+      _value.compareTo(other.millisecondsSinceEpoch);
+}
+
+// Patch for Stopwatch implementation.
+@patch
+class Stopwatch {
+  @patch
+  static void _initTicker() {
+    Primitives.initTicker();
+    _frequency = Primitives.timerFrequency;
+  }
+
+  @patch
+  static int _now() => Primitives.timerTicks();
+
+  @patch
+  int get elapsedMicroseconds {
+    int ticks = elapsedTicks;
+    if (_frequency == 1000000) return ticks;
+    assert(_frequency == 1000);
+    return ticks * 1000;
+  }
+
+  @patch
+  int get elapsedMilliseconds {
+    int ticks = elapsedTicks;
+    if (_frequency == 1000) return ticks;
+    assert(_frequency == 1000000);
+    return ticks ~/ 1000;
+  }
+}
+
+// Patch for List implementation.
+@patch
+class List<E> {
+  @patch
+  factory List([@undefined int _length]) {
+    dynamic list;
+    if (JS<bool>('!', '# === void 0', _length)) {
+      list = JS('', '[]');
+    } else {
+      int length = JS('!', '#', _length);
+      if (_length == null || length < 0) {
+        throw ArgumentError("Length must be a non-negative integer: $_length");
+      }
+      list = JS('', 'new Array(#)', length);
+      JS('', '#.fill(null)', list);
+      JSArray.markFixedList(list);
+    }
+    return JSArray<E>.of(list);
+  }
+
+  @patch
+  factory List.filled(@nullCheck int length, E fill, {bool growable = false}) {
+    var list = JSArray<E>.of(JS('', 'new Array(#)', length));
+    JS('', '#.fill(#)', list, fill);
+    if (!growable) JSArray.markFixedList(list);
+    return list;
+  }
+
+  @patch
+  factory List.from(Iterable elements, {bool growable = true}) {
+    var list = JSArray<E>.of(JS('', '[]'));
+    // Specialize the copy loop for the case that doesn't need a
+    // runtime check.
+    if (elements is Iterable<E>) {
+      for (var e in elements) {
+        list.add(e);
+      }
+    } else {
+      for (var e in elements) {
+        list.add(e as E);
+      }
+    }
+    if (!growable) JSArray.markFixedList(list);
+    return list;
+  }
+
+  @patch
+  factory List.unmodifiable(Iterable elements) {
+    var list = List<E>.from(elements);
+    JSArray.markUnmodifiableList(list);
+    return list;
+  }
+}
+
+@patch
+class Map<K, V> {
+  @patch
+  factory Map.unmodifiable(Map other) {
+    return UnmodifiableMapView<K, V>(Map<K, V>.from(other));
+  }
+
+  @patch
+  factory Map() = LinkedMap<K, V>;
+}
+
+@patch
+class String {
+  @patch
+  factory String.fromCharCodes(Iterable<int> charCodes,
+      [int start = 0, int end]) {
+    if (charCodes is JSArray) {
+      return _stringFromJSArray(charCodes, start, end);
+    }
+    if (charCodes is NativeUint8List) {
+      return _stringFromUint8List(charCodes, start, end);
+    }
+    return _stringFromIterable(charCodes, start, end);
+  }
+
+  @patch
+  factory String.fromCharCode(int charCode) {
+    return Primitives.stringFromCharCode(charCode);
+  }
+
+  @patch
+  factory String.fromEnvironment(String name, {String defaultValue}) {
+    // ignore: const_constructor_throws_exception
+    throw UnsupportedError(
+        'String.fromEnvironment can only be used as a const constructor');
+  }
+
+  static String _stringFromJSArray(
+      /*=JSArray<int>*/ list,
+      int start,
+      int endOrNull) {
+    int len = list.length;
+    int end = RangeError.checkValidRange(start, endOrNull, len);
+    if (start > 0 || end < len) {
+      list = list.sublist(start, end);
+    }
+    return Primitives.stringFromCharCodes(list);
+  }
+
+  static String _stringFromUint8List(
+      NativeUint8List charCodes, int start, int endOrNull) {
+    int len = charCodes.length;
+    int end = RangeError.checkValidRange(start, endOrNull, len);
+    return Primitives.stringFromNativeUint8List(charCodes, start, end);
+  }
+
+  static String _stringFromIterable(
+      Iterable<int> charCodes, int start, int end) {
+    if (start < 0) throw RangeError.range(start, 0, charCodes.length);
+    if (end != null && end < start) {
+      throw RangeError.range(end, start, charCodes.length);
+    }
+    var it = charCodes.iterator;
+    for (int i = 0; i < start; i++) {
+      if (!it.moveNext()) {
+        throw RangeError.range(start, 0, i);
+      }
+    }
+    var list = <int>[];
+    if (end == null) {
+      while (it.moveNext()) list.add(it.current);
+    } else {
+      for (int i = start; i < end; i++) {
+        if (!it.moveNext()) {
+          throw RangeError.range(end, start, i);
+        }
+        list.add(it.current);
+      }
+    }
+    return Primitives.stringFromCharCodes(list);
+  }
+}
+
+@patch
+class bool {
+  @patch
+  factory bool.fromEnvironment(String name, {bool defaultValue = false}) {
+    // ignore: const_constructor_throws_exception
+    throw UnsupportedError(
+        'bool.fromEnvironment can only be used as a const constructor');
+  }
+
+  @patch
+  int get hashCode => super.hashCode;
+}
+
+@patch
+class RegExp {
+  @patch
+  factory RegExp(String source,
+          {bool multiLine = false,
+          bool caseSensitive = true,
+          bool unicode = false,
+          bool dotAll = false}) =>
+      JSSyntaxRegExp(source,
+          multiLine: multiLine,
+          caseSensitive: caseSensitive,
+          unicode: unicode,
+          dotAll: dotAll);
+
+  @patch
+  static String escape(String text) => quoteStringForRegExp(text);
+}
+
+// Patch for 'identical' function.
+@patch
+bool identical(Object a, Object b) {
+  return JS<bool>('!', '(# == null ? # == null : # === #)', a, b, a, b);
+}
+
+@patch
+class StringBuffer {
+  String _contents;
+
+  @patch
+  StringBuffer([Object content = ""]) : _contents = '$content';
+
+  @patch
+  int get length => _contents.length;
+
+  @patch
+  void write(Object obj) {
+    _writeString('$obj');
+  }
+
+  @patch
+  void writeCharCode(int charCode) {
+    _writeString(String.fromCharCode(charCode));
+  }
+
+  @patch
+  void writeAll(Iterable objects, [String separator = ""]) {
+    _contents = _writeAll(_contents, objects, separator);
+  }
+
+  @patch
+  void writeln([Object obj = ""]) {
+    _writeString('$obj\n');
+  }
+
+  @patch
+  void clear() {
+    _contents = "";
+  }
+
+  @patch
+  String toString() => Primitives.flattenString(_contents);
+
+  void _writeString(str) {
+    _contents = Primitives.stringConcatUnchecked(_contents, str);
+  }
+
+  static String _writeAll(String string, Iterable objects, String separator) {
+    Iterator iterator = objects.iterator;
+    if (!iterator.moveNext()) return string;
+    if (separator.isEmpty) {
+      do {
+        string = _writeOne(string, iterator.current);
+      } while (iterator.moveNext());
+    } else {
+      string = _writeOne(string, iterator.current);
+      while (iterator.moveNext()) {
+        string = _writeOne(string, separator);
+        string = _writeOne(string, iterator.current);
+      }
+    }
+    return string;
+  }
+
+  static String _writeOne(String string, Object obj) {
+    return Primitives.stringConcatUnchecked(string, '$obj');
+  }
+}
+
+// TODO(jmesserly): kernel expects to find this in our SDK.
+class _CompileTimeError extends Error {
+  final String _errorMsg;
+  _CompileTimeError(this._errorMsg);
+  String toString() => _errorMsg;
+}
+
+@patch
+class NoSuchMethodError {
+  final Object _receiver;
+  final Symbol _memberName;
+  final List _arguments;
+  final Map<Symbol, dynamic> _namedArguments;
+  final List _existingArgumentNames;
+  final Invocation _invocation;
+
+  @patch
+  NoSuchMethodError(Object receiver, Symbol memberName,
+      List positionalArguments, Map<Symbol, dynamic> namedArguments,
+      [List existingArgumentNames = null])
+      : _receiver = receiver,
+        _memberName = memberName,
+        _arguments = positionalArguments,
+        _namedArguments = namedArguments,
+        _existingArgumentNames = existingArgumentNames,
+        _invocation = null;
+
+  @patch
+  NoSuchMethodError.withInvocation(Object receiver, Invocation invocation)
+      : _receiver = receiver,
+        _memberName = invocation.memberName,
+        _arguments = invocation.positionalArguments,
+        _namedArguments = invocation.namedArguments,
+        _existingArgumentNames = null,
+        _invocation = invocation;
+
+  @patch
+  String toString() {
+    StringBuffer sb = StringBuffer('');
+    String comma = '';
+    if (_arguments != null) {
+      for (var argument in _arguments) {
+        sb.write(comma);
+        sb.write(Error.safeToString(argument));
+        comma = ', ';
+      }
+    }
+    if (_namedArguments != null) {
+      _namedArguments.forEach((Symbol key, var value) {
+        sb.write(comma);
+        sb.write(_symbolToString(key));
+        sb.write(": ");
+        sb.write(Error.safeToString(value));
+        comma = ', ';
+      });
+    }
+    String memberName = _symbolToString(_memberName);
+    String receiverText = Error.safeToString(_receiver);
+    String actualParameters = '$sb';
+    var failureMessage = (_invocation is dart.InvocationImpl)
+        ? (_invocation as dart.InvocationImpl).failureMessage
+        : 'method not found';
+    if (_existingArgumentNames == null) {
+      return "NoSuchMethodError: '$memberName'\n"
+          "$failureMessage\n"
+          "Receiver: ${receiverText}\n"
+          "Arguments: [$actualParameters]";
+    } else {
+      String formalParameters = _existingArgumentNames.join(', ');
+      return "NoSuchMethodError: incorrect number of arguments passed to "
+          "method named '$memberName'\n"
+          "Receiver: ${receiverText}\n"
+          "Tried calling: $memberName($actualParameters)\n"
+          "Found: $memberName($formalParameters)";
+    }
+  }
+}
+
+@patch
+class Uri {
+  @patch
+  static Uri get base {
+    String uri = Primitives.currentUri();
+    if (uri != null) return Uri.parse(uri);
+    throw UnsupportedError("'Uri.base' is not supported");
+  }
+}
+
+@patch
+class _Uri {
+  @patch
+  static bool get _isWindows => _isWindowsCached;
+
+  static final bool _isWindowsCached = JS(
+      'bool',
+      'typeof process != "undefined" && '
+          'Object.prototype.toString.call(process) == "[object process]" && '
+          'process.platform == "win32"');
+
+  // Matches a String that _uriEncodes to itself regardless of the kind of
+  // component.  This corresponds to [_unreservedTable], i.e. characters that
+  // are not encoded by any encoding table.
+  static final RegExp _needsNoEncoding = RegExp(r'^[\-\.0-9A-Z_a-z~]*$');
+
+  /**
+   * This is the internal implementation of JavaScript's encodeURI function.
+   * It encodes all characters in the string [text] except for those
+   * that appear in [canonicalTable], and returns the escaped string.
+   */
+  @patch
+  static String _uriEncode(List<int> canonicalTable, String text,
+      Encoding encoding, bool spaceToPlus) {
+    if (identical(encoding, utf8) && _needsNoEncoding.hasMatch(text)) {
+      return text;
+    }
+
+    // Encode the string into bytes then generate an ASCII only string
+    // by percent encoding selected bytes.
+    StringBuffer result = StringBuffer('');
+    var bytes = encoding.encode(text);
+    for (int i = 0; i < bytes.length; i++) {
+      int byte = bytes[i];
+      if (byte < 128 &&
+          ((canonicalTable[byte >> 4] & (1 << (byte & 0x0f))) != 0)) {
+        result.writeCharCode(byte);
+      } else if (spaceToPlus && byte == _SPACE) {
+        result.write('+');
+      } else {
+        const String hexDigits = '0123456789ABCDEF';
+        result.write('%');
+        result.write(hexDigits[(byte >> 4) & 0x0f]);
+        result.write(hexDigits[byte & 0x0f]);
+      }
+    }
+    return result.toString();
+  }
+}
+
+@patch
+class StackTrace {
+  @patch
+  @NoInline()
+  static StackTrace get current {
+    return dart.stackTrace(JS('', 'Error()'));
+  }
+}
+
+// TODO(jmesserly): this class is supposed to be obsolete in Strong Mode, but
+// the front-end crashes without it
+class _DuplicatedFieldInitializerError {
+  final String _name;
+
+  _DuplicatedFieldInitializerError(this._name);
+
+  toString() => "Error: field '$_name' is already initialized.";
+}
+
+// TODO(jmesserly): The rest of this core_patch.dart source should reside in an
+// included part file instead of being inlined. However, part files are not
+// properly supported here.
+
+// 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.
+
+// part of dart.core;
+
+int _max(int a, int b) => a > b ? a : b;
+int _min(int a, int b) => a < b ? a : b;
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+ * Copyright (c) 2003-2005  Tom Wu
+ * Copyright (c) 2012 Adam Singer (adam@solvr.io)
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL TOM WU BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF
+ * THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * In addition, the following condition applies:
+ *
+ * All redistributions must retain an intact copy of this copyright notice
+ * and disclaimer.
+ */
+
+/**
+ * An implementation for the arbitrarily large integer.
+ *
+ * The integer number is represented by a sign, an array of 16-bit unsigned
+ * integers in little endian format, and a number of used digits in that array.
+ */
+class _BigIntImpl implements BigInt {
+  // Bits per digit.
+  static const int _digitBits = 16;
+  static const int _digitBase = 1 << _digitBits;
+  static const int _digitMask = (1 << _digitBits) - 1;
+
+  static final _BigIntImpl zero = _BigIntImpl._fromInt(0);
+  static final _BigIntImpl one = _BigIntImpl._fromInt(1);
+  static final _BigIntImpl two = _BigIntImpl._fromInt(2);
+
+  static final _BigIntImpl _minusOne = -one;
+  static final _BigIntImpl _bigInt10000 = _BigIntImpl._fromInt(10000);
+
+  // Result cache for last _divRem call.
+  // Result cache for last _divRem call.
+  static Uint16List _lastDividendDigits;
+  static int _lastDividendUsed;
+  static Uint16List _lastDivisorDigits;
+  static int _lastDivisorUsed;
+  static Uint16List _lastQuoRemDigits;
+  static int _lastQuoRemUsed;
+  static int _lastRemUsed;
+  static int _lastRem_nsh;
+
+  /// Whether this bigint is negative.
+  final bool _isNegative;
+
+  /// The unsigned digits of this bigint.
+  ///
+  /// The least significant digit is in slot 0.
+  /// The list may have more digits than needed. That is, `_digits.length` may
+  /// be strictly greater than `_used`.
+  final Uint16List _digits;
+
+  /// The number of used entries in [_digits].
+  ///
+  /// To avoid reallocating [Uint16List]s, lists that are too big are not
+  /// replaced.
+  final int _used;
+
+  /**
+   * Parses [source] as a, possibly signed, integer literal and returns its
+   * value.
+   *
+   * The [source] must be a non-empty sequence of base-[radix] digits,
+   * optionally prefixed with a minus or plus sign ('-' or '+').
+   *
+   * The [radix] must be in the range 2..36. The digits used are
+   * first the decimal digits 0..9, and then the letters 'a'..'z' with
+   * values 10 through 35. Also accepts upper-case letters with the same
+   * values as the lower-case ones.
+   *
+   * If no [radix] is given then it defaults to 10. In this case, the [source]
+   * digits may also start with `0x`, in which case the number is interpreted
+   * as a hexadecimal literal, which effectively means that the `0x` is ignored
+   * and the radix is instead set to 16.
+   *
+   * For any int `n` and radix `r`, it is guaranteed that
+   * `n == int.parse(n.toRadixString(r), radix: r)`.
+   *
+   * Throws a [FormatException] if the [source] is not a valid integer literal,
+   * optionally prefixed by a sign.
+   */
+  static _BigIntImpl parse(String source, {int radix}) {
+    var result = _tryParse(source, radix: radix);
+    if (result == null) {
+      throw FormatException("Could not parse BigInt", source);
+    }
+    return result;
+  }
+
+  /// Parses a decimal bigint literal.
+  ///
+  /// The [source] must not contain leading or trailing whitespace.
+  static _BigIntImpl _parseDecimal(String source, bool isNegative) {
+    const _0 = 48;
+
+    int part = 0;
+    _BigIntImpl result = zero;
+    // Read in the source 4 digits at a time.
+    // The first part may have a few leading virtual '0's to make the remaining
+    // parts all have exactly 4 digits.
+    int digitInPartCount = 4 - source.length.remainder(4);
+    if (digitInPartCount == 4) digitInPartCount = 0;
+    for (int i = 0; i < source.length; i++) {
+      part = part * 10 + source.codeUnitAt(i) - _0;
+      if (++digitInPartCount == 4) {
+        result = result * _bigInt10000 + _BigIntImpl._fromInt(part);
+        part = 0;
+        digitInPartCount = 0;
+      }
+    }
+    if (isNegative) return -result;
+    return result;
+  }
+
+  /// Returns the value of a given source digit.
+  ///
+  /// Source digits between "0" and "9" (inclusive) return their decimal value.
+  ///
+  /// Source digits between "a" and "z", or "A" and "Z" (inclusive) return
+  /// 10 + their position in the ASCII alphabet.
+  ///
+  /// The incoming [codeUnit] must be an ASCII code-unit.
+  static int _codeUnitToRadixValue(int codeUnit) {
+    // We know that the characters must be ASCII as otherwise the
+    // regexp wouldn't have matched. Lowercasing by doing `| 0x20` is thus
+    // guaranteed to be a safe operation, since it preserves digits
+    // and lower-cases ASCII letters.
+    const int _0 = 48;
+    const int _9 = 57;
+    const int _a = 97;
+    if (_0 <= codeUnit && codeUnit <= _9) return codeUnit - _0;
+    codeUnit |= 0x20;
+    var result = codeUnit - _a + 10;
+    return result;
+  }
+
+  /// Parses the given [source] string, starting at [startPos], as a hex
+  /// literal.
+  ///
+  /// If [isNegative] is true, negates the result before returning it.
+  ///
+  /// The [source] (substring) must be a valid hex literal.
+  static _BigIntImpl _parseHex(String source, int startPos, bool isNegative) {
+    int hexDigitsPerChunk = _digitBits ~/ 4;
+    int sourceLength = source.length - startPos;
+    int chunkCount = (sourceLength / hexDigitsPerChunk).ceil();
+    var digits = Uint16List(chunkCount);
+
+    int lastDigitLength = sourceLength - (chunkCount - 1) * hexDigitsPerChunk;
+    int digitIndex = digits.length - 1;
+    int i = startPos;
+    int chunk = 0;
+    for (int j = 0; j < lastDigitLength; j++) {
+      var digitValue = _codeUnitToRadixValue(source.codeUnitAt(i++));
+      if (digitValue >= 16) return null;
+      chunk = chunk * 16 + digitValue;
+    }
+    digits[digitIndex--] = chunk;
+
+    while (i < source.length) {
+      chunk = 0;
+      for (int j = 0; j < hexDigitsPerChunk; j++) {
+        var digitValue = _codeUnitToRadixValue(source.codeUnitAt(i++));
+        if (digitValue >= 16) return null;
+        chunk = chunk * 16 + digitValue;
+      }
+      digits[digitIndex--] = chunk;
+    }
+    if (digits.length == 1 && digits[0] == 0) return zero;
+    return _BigIntImpl._(isNegative, digits.length, digits);
+  }
+
+  /// Parses the given [source] as a [radix] literal.
+  ///
+  /// The [source] will be checked for invalid characters. If it is invalid,
+  /// this function returns `null`.
+  static _BigIntImpl _parseRadix(String source, int radix, bool isNegative) {
+    var result = zero;
+    var base = _BigIntImpl._fromInt(radix);
+    for (int i = 0; i < source.length; i++) {
+      var digitValue = _codeUnitToRadixValue(source.codeUnitAt(i));
+      if (digitValue >= radix) return null;
+      result = result * base + _BigIntImpl._fromInt(digitValue);
+    }
+    if (isNegative) return -result;
+    return result;
+  }
+
+  /// Tries to parse the given [source] as a [radix] literal.
+  ///
+  /// Returns the parsed big integer, or `null` if it failed.
+  ///
+  /// If the [radix] is `null` accepts decimal literals or `0x` hex literals.
+  static _BigIntImpl _tryParse(String source, {int radix}) {
+    if (source == "") return null;
+
+    var re = RegExp(r'^\s*([+-]?)((0x[a-f0-9]+)|(\d+)|([a-z0-9]+))\s*$',
+        caseSensitive: false);
+    var match = re.firstMatch(source);
+    int signIndex = 1;
+    int hexIndex = 3;
+    int decimalIndex = 4;
+    int nonDecimalHexIndex = 5;
+    if (match == null) return null;
+
+    bool isNegative = match[signIndex] == "-";
+
+    String decimalMatch = match[decimalIndex];
+    String hexMatch = match[hexIndex];
+    String nonDecimalMatch = match[nonDecimalHexIndex];
+
+    if (radix == null) {
+      if (decimalMatch != null) {
+        // Cannot fail because we know that the digits are all decimal.
+        return _parseDecimal(decimalMatch, isNegative);
+      }
+      if (hexMatch != null) {
+        // Cannot fail because we know that the digits are all hex.
+        return _parseHex(hexMatch, 2, isNegative);
+      }
+      return null;
+    }
+
+    if (radix is! int) {
+      throw ArgumentError.value(radix, 'radix', 'is not an integer');
+    }
+    if (radix < 2 || radix > 36) {
+      throw RangeError.range(radix, 2, 36, 'radix');
+    }
+    if (radix == 10 && decimalMatch != null) {
+      return _parseDecimal(decimalMatch, isNegative);
+    }
+    if (radix == 16 && (decimalMatch != null || nonDecimalMatch != null)) {
+      return _parseHex(decimalMatch ?? nonDecimalMatch, 0, isNegative);
+    }
+
+    return _parseRadix(
+        decimalMatch ?? nonDecimalMatch ?? hexMatch, radix, isNegative);
+  }
+
+  /// Finds the amount significant digits in the provided [digits] array.
+  static int _normalize(int used, Uint16List digits) {
+    while (used > 0 && digits[used - 1] == 0) used--;
+    return used;
+  }
+
+  /// Factory returning an instance initialized with the given field values.
+  /// If the [digits] array contains leading 0s, the [used] value is adjusted
+  /// accordingly. The [digits] array is not modified.
+  _BigIntImpl._(bool isNegative, int used, Uint16List digits)
+      : this._normalized(isNegative, _normalize(used, digits), digits);
+
+  _BigIntImpl._normalized(bool isNegative, this._used, this._digits)
+      : _isNegative = _used == 0 ? false : isNegative;
+
+  /// Whether this big integer is zero.
+  bool get _isZero => _used == 0;
+
+  /// Allocates an array of the given [length] and copies the [digits] in the
+  /// range [from] to [to-1], starting at index 0, followed by leading zero
+  /// digits.
+  static Uint16List _cloneDigits(
+      Uint16List digits, int from, int to, int length) {
+    var resultDigits = Uint16List(length);
+    var n = to - from;
+    for (var i = 0; i < n; i++) {
+      resultDigits[i] = digits[from + i];
+    }
+    return resultDigits;
+  }
+
+  /// Allocates a big integer from the provided [value] number.
+  factory _BigIntImpl.from(num value) {
+    if (value == 0) return zero;
+    if (value == 1) return one;
+    if (value == 2) return two;
+
+    // Given this order dart2js will use the `_fromInt` for smaller value and
+    // then use the bit-manipulating `_fromDouble` for all other values.
+    if (value.abs() < 0x100000000) return _BigIntImpl._fromInt(value.toInt());
+    if (value is double) return _BigIntImpl._fromDouble(value);
+    return _BigIntImpl._fromInt(value);
+  }
+
+  factory _BigIntImpl._fromInt(int value) {
+    bool isNegative = value < 0;
+    assert(_digitBits == 16);
+    if (isNegative) {
+      // Handle the min 64-bit value differently, since its negation is not
+      // positive.
+      const int minInt64 = -0x80000000 * 0x100000000;
+      if (value == minInt64) {
+        var digits = Uint16List(4);
+        digits[3] = 0x8000;
+        return _BigIntImpl._(true, 4, digits);
+      }
+      value = -value;
+    }
+    if (value < _digitBase) {
+      var digits = Uint16List(1);
+      digits[0] = value;
+      return _BigIntImpl._(isNegative, 1, digits);
+    }
+    if (value <= 0xFFFFFFFF) {
+      var digits = Uint16List(2);
+      digits[0] = value & _digitMask;
+      digits[1] = value >> _digitBits;
+      return _BigIntImpl._(isNegative, 2, digits);
+    }
+
+    var bits = value.bitLength;
+    var digits = Uint16List((bits - 1) ~/ _digitBits + 1);
+    var i = 0;
+    while (value != 0) {
+      digits[i++] = value & _digitMask;
+      value = value ~/ _digitBase;
+    }
+    return _BigIntImpl._(isNegative, digits.length, digits);
+  }
+
+  /// An 8-byte Uint8List we can reuse for [_fromDouble] to avoid generating
+  /// garbage.
+  static final Uint8List _bitsForFromDouble = Uint8List(8);
+
+  factory _BigIntImpl._fromDouble(double value) {
+    const int exponentBias = 1075;
+
+    if (value.isNaN || value.isInfinite) {
+      throw ArgumentError("Value must be finite: $value");
+    }
+    bool isNegative = value < 0;
+    if (isNegative) value = -value;
+
+    value = value.floorToDouble();
+    if (value == 0) return zero;
+
+    var bits = _bitsForFromDouble;
+    for (int i = 0; i < 8; i++) {
+      bits[i] = 0;
+    }
+    bits.buffer.asByteData().setFloat64(0, value, Endian.little);
+    // The exponent is in bits 53..63.
+    var biasedExponent = (bits[7] << 4) + (bits[6] >> 4);
+    var exponent = biasedExponent - exponentBias;
+
+    assert(_digitBits == 16);
+    // The significant bits are in 0 .. 52.
+    var unshiftedDigits = Uint16List(4);
+    unshiftedDigits[0] = (bits[1] << 8) + bits[0];
+    unshiftedDigits[1] = (bits[3] << 8) + bits[2];
+    unshiftedDigits[2] = (bits[5] << 8) + bits[4];
+    // Don't forget to add the hidden bit.
+    unshiftedDigits[3] = 0x10 | (bits[6] & 0xF);
+
+    var unshiftedBig = _BigIntImpl._normalized(false, 4, unshiftedDigits);
+    _BigIntImpl absResult = unshiftedBig;
+    if (exponent < 0) {
+      absResult = unshiftedBig >> -exponent;
+    } else if (exponent > 0) {
+      absResult = unshiftedBig << exponent;
+    }
+    if (isNegative) return -absResult;
+    return absResult;
+  }
+
+  /**
+   * Return the negative value of this integer.
+   *
+   * The result of negating an integer always has the opposite sign, except
+   * for zero, which is its own negation.
+   */
+  _BigIntImpl operator -() {
+    if (_used == 0) return this;
+    return _BigIntImpl._(!_isNegative, _used, _digits);
+  }
+
+  /**
+   * Returns the absolute value of this integer.
+   *
+   * For any integer `x`, the result is the same as `x < 0 ? -x : x`.
+   */
+  _BigIntImpl abs() => _isNegative ? -this : this;
+
+  /// Returns this << n *_DIGIT_BITS.
+  _BigIntImpl _dlShift(int n) {
+    final used = _used;
+    if (used == 0) {
+      return zero;
+    }
+    final resultUsed = used + n;
+    final digits = _digits;
+    final resultDigits = Uint16List(resultUsed);
+    for (int i = used - 1; i >= 0; i--) {
+      resultDigits[i + n] = digits[i];
+    }
+    return _BigIntImpl._(_isNegative, resultUsed, resultDigits);
+  }
+
+  /// Same as [_dlShift] but works on the decomposed big integers.
+  ///
+  /// Returns `resultUsed`.
+  ///
+  /// `resultDigits[0..resultUsed-1] = xDigits[0..xUsed-1] << n*_DIGIT_BITS`.
+  static int _dlShiftDigits(
+      Uint16List xDigits, int xUsed, int n, Uint16List resultDigits) {
+    if (xUsed == 0) {
+      return 0;
+    }
+    if (n == 0 && identical(resultDigits, xDigits)) {
+      return xUsed;
+    }
+    final resultUsed = xUsed + n;
+    for (int i = xUsed - 1; i >= 0; i--) {
+      resultDigits[i + n] = xDigits[i];
+    }
+    for (int i = n - 1; i >= 0; i--) {
+      resultDigits[i] = 0;
+    }
+    return resultUsed;
+  }
+
+  /// Returns `this >> n*_DIGIT_BITS`.
+  _BigIntImpl _drShift(int n) {
+    final used = _used;
+    if (used == 0) {
+      return zero;
+    }
+    final resultUsed = used - n;
+    if (resultUsed <= 0) {
+      return _isNegative ? _minusOne : zero;
+    }
+    final digits = _digits;
+    final resultDigits = Uint16List(resultUsed);
+    for (var i = n; i < used; i++) {
+      resultDigits[i - n] = digits[i];
+    }
+    final result = _BigIntImpl._(_isNegative, resultUsed, resultDigits);
+    if (_isNegative) {
+      // Round down if any bit was shifted out.
+      for (var i = 0; i < n; i++) {
+        if (digits[i] != 0) {
+          return result - one;
+        }
+      }
+    }
+    return result;
+  }
+
+  /// Shifts the digits of [xDigits] into the right place in [resultDigits].
+  ///
+  /// `resultDigits[ds..xUsed+ds] = xDigits[0..xUsed-1] << (n % _DIGIT_BITS)`
+  ///   where `ds = n ~/ _DIGIT_BITS`
+  ///
+  /// Does *not* clear digits below ds.
+  static void _lsh(
+      Uint16List xDigits, int xUsed, int n, Uint16List resultDigits) {
+    assert(xUsed > 0);
+    final digitShift = n ~/ _digitBits;
+    final bitShift = n % _digitBits;
+    final carryBitShift = _digitBits - bitShift;
+    final bitMask = (1 << carryBitShift) - 1;
+    var carry = 0;
+    for (int i = xUsed - 1; i >= 0; i--) {
+      final digit = xDigits[i];
+      resultDigits[i + digitShift + 1] = (digit >> carryBitShift) | carry;
+      carry = (digit & bitMask) << bitShift;
+    }
+    resultDigits[digitShift] = carry;
+  }
+
+  /**
+   * Shift the bits of this integer to the left by [shiftAmount].
+   *
+   * Shifting to the left makes the number larger, effectively multiplying
+   * the number by `pow(2, shiftIndex)`.
+   *
+   * There is no limit on the size of the result. It may be relevant to
+   * limit intermediate values by using the "and" operator with a suitable
+   * mask.
+   *
+   * It is an error if [shiftAmount] is negative.
+   */
+  _BigIntImpl operator <<(int shiftAmount) {
+    if (shiftAmount < 0) {
+      throw ArgumentError("shift-amount must be posititve $shiftAmount");
+    }
+    if (_isZero) return this;
+    final digitShift = shiftAmount ~/ _digitBits;
+    final bitShift = shiftAmount % _digitBits;
+    if (bitShift == 0) {
+      return _dlShift(digitShift);
+    }
+    var resultUsed = _used + digitShift + 1;
+    var resultDigits = Uint16List(resultUsed);
+    _lsh(_digits, _used, shiftAmount, resultDigits);
+    return _BigIntImpl._(_isNegative, resultUsed, resultDigits);
+  }
+
+  // resultDigits[0..resultUsed-1] = xDigits[0..xUsed-1] << n.
+  // Returns resultUsed.
+  static int _lShiftDigits(
+      Uint16List xDigits, int xUsed, int n, Uint16List resultDigits) {
+    final digitsShift = n ~/ _digitBits;
+    final bitShift = n % _digitBits;
+    if (bitShift == 0) {
+      return _dlShiftDigits(xDigits, xUsed, digitsShift, resultDigits);
+    }
+    var resultUsed = xUsed + digitsShift + 1;
+    _lsh(xDigits, xUsed, n, resultDigits);
+    var i = digitsShift;
+    while (--i >= 0) {
+      resultDigits[i] = 0;
+    }
+    if (resultDigits[resultUsed - 1] == 0) {
+      resultUsed--; // Clamp result.
+    }
+    return resultUsed;
+  }
+
+  // resultDigits[0..resultUsed-1] = xDigits[0..xUsed-1] >> n.
+  static void _rsh(
+      Uint16List xDigits, int xUsed, int n, Uint16List resultDigits) {
+    assert(xUsed > 0);
+    final digitsShift = n ~/ _digitBits;
+    final bitShift = n % _digitBits;
+    final carryBitShift = _digitBits - bitShift;
+    final bitMask = (1 << bitShift) - 1;
+    var carry = xDigits[digitsShift] >> bitShift;
+    final last = xUsed - digitsShift - 1;
+    for (var i = 0; i < last; i++) {
+      final digit = xDigits[i + digitsShift + 1];
+      resultDigits[i] = ((digit & bitMask) << carryBitShift) | carry;
+      carry = digit >> bitShift;
+    }
+    resultDigits[last] = carry;
+  }
+
+  /**
+   * Shift the bits of this integer to the right by [shiftAmount].
+   *
+   * Shifting to the right makes the number smaller and drops the least
+   * significant bits, effectively doing an integer division by
+   *`pow(2, shiftIndex)`.
+   *
+   * It is an error if [shiftAmount] is negative.
+   */
+  _BigIntImpl operator >>(int shiftAmount) {
+    if (shiftAmount < 0) {
+      throw ArgumentError("shift-amount must be posititve $shiftAmount");
+    }
+    if (_isZero) return this;
+    final digitShift = shiftAmount ~/ _digitBits;
+    final bitShift = shiftAmount % _digitBits;
+    if (bitShift == 0) {
+      return _drShift(digitShift);
+    }
+    final used = _used;
+    final resultUsed = used - digitShift;
+    if (resultUsed <= 0) {
+      return _isNegative ? _minusOne : zero;
+    }
+    final digits = _digits;
+    final resultDigits = Uint16List(resultUsed);
+    _rsh(digits, used, shiftAmount, resultDigits);
+    final result = _BigIntImpl._(_isNegative, resultUsed, resultDigits);
+    if (_isNegative) {
+      // Round down if any bit was shifted out.
+      if ((digits[digitShift] & ((1 << bitShift) - 1)) != 0) {
+        return result - one;
+      }
+      for (var i = 0; i < digitShift; i++) {
+        if (digits[i] != 0) {
+          return result - one;
+        }
+      }
+    }
+    return result;
+  }
+
+  /// Compares this to [other] taking the absolute value of both operands.
+  ///
+  /// Returns 0 if abs(this) == abs(other); a positive number if
+  /// abs(this) > abs(other); and a negative number if abs(this) < abs(other).
+  int _absCompare(BigInt bigInt) {
+    _BigIntImpl other = bigInt;
+    return _compareDigits(_digits, _used, other._digits, other._used);
+  }
+
+  /**
+   * Compares this to `other`.
+   *
+   * Returns a negative number if `this` is less than `other`, zero if they are
+   * equal, and a positive number if `this` is greater than `other`.
+   */
+  int compareTo(BigInt bigInt) {
+    _BigIntImpl other = bigInt;
+    if (_isNegative == other._isNegative) {
+      var result = _absCompare(other);
+      // Use 0 - result to avoid negative zero in JavaScript.
+      return _isNegative ? 0 - result : result;
+    }
+    return _isNegative ? -1 : 1;
+  }
+
+  /// Compares `digits[0..used-1]` with `otherDigits[0..otherUsed-1]`.
+  ///
+  /// Returns 0 if equal; a positive number if larger;
+  /// and a negative number if smaller.
+  static int _compareDigits(
+      Uint16List digits, int used, Uint16List otherDigits, int otherUsed) {
+    var result = used - otherUsed;
+    if (result == 0) {
+      for (int i = used - 1; i >= 0; i--) {
+        result = digits[i] - otherDigits[i];
+        if (result != 0) return result;
+      }
+    }
+    return result;
+  }
+
+  // resultDigits[0..used] = digits[0..used-1] + otherDigits[0..otherUsed-1].
+  // used >= otherUsed > 0.
+  static void _absAdd(Uint16List digits, int used, Uint16List otherDigits,
+      int otherUsed, Uint16List resultDigits) {
+    assert(used >= otherUsed && otherUsed > 0);
+    var carry = 0;
+    for (var i = 0; i < otherUsed; i++) {
+      carry += digits[i] + otherDigits[i];
+      resultDigits[i] = carry & _digitMask;
+      carry >>= _digitBits;
+    }
+    for (var i = otherUsed; i < used; i++) {
+      carry += digits[i];
+      resultDigits[i] = carry & _digitMask;
+      carry >>= _digitBits;
+    }
+    resultDigits[used] = carry;
+  }
+
+  // resultDigits[0..used-1] = digits[0..used-1] - otherDigits[0..otherUsed-1].
+  // used >= otherUsed > 0.
+  static void _absSub(Uint16List digits, int used, Uint16List otherDigits,
+      int otherUsed, Uint16List resultDigits) {
+    assert(used >= otherUsed && otherUsed > 0);
+
+    var carry = 0;
+    for (var i = 0; i < otherUsed; i++) {
+      carry += digits[i] - otherDigits[i];
+      resultDigits[i] = carry & _digitMask;
+      // Dart2js only supports unsigned shifts.
+      // Since the carry can only be -1 or 0 use this hack.
+      carry = 0 - ((carry >> _digitBits) & 1);
+    }
+    for (var i = otherUsed; i < used; i++) {
+      carry += digits[i];
+      resultDigits[i] = carry & _digitMask;
+      // Dart2js only supports unsigned shifts.
+      // Since the carry can only be -1 or 0 use this hack.
+      carry = 0 - ((carry >> _digitBits) & 1);
+    }
+  }
+
+  /// Returns `abs(this) + abs(other)` with sign set according to [isNegative].
+  _BigIntImpl _absAddSetSign(_BigIntImpl other, bool isNegative) {
+    var used = _used;
+    var otherUsed = other._used;
+    if (used < otherUsed) {
+      return other._absAddSetSign(this, isNegative);
+    }
+    if (used == 0) {
+      assert(!isNegative);
+      return zero;
+    }
+    if (otherUsed == 0) {
+      return _isNegative == isNegative ? this : -this;
+    }
+    var resultUsed = used + 1;
+    var resultDigits = Uint16List(resultUsed);
+    _absAdd(_digits, used, other._digits, otherUsed, resultDigits);
+    return _BigIntImpl._(isNegative, resultUsed, resultDigits);
+  }
+
+  /// Returns `abs(this) - abs(other)` with sign set according to [isNegative].
+  ///
+  /// Requirement: `abs(this) >= abs(other)`.
+  _BigIntImpl _absSubSetSign(_BigIntImpl other, bool isNegative) {
+    assert(_absCompare(other) >= 0);
+    var used = _used;
+    if (used == 0) {
+      assert(!isNegative);
+      return zero;
+    }
+    var otherUsed = other._used;
+    if (otherUsed == 0) {
+      return _isNegative == isNegative ? this : -this;
+    }
+    var resultDigits = Uint16List(used);
+    _absSub(_digits, used, other._digits, otherUsed, resultDigits);
+    return _BigIntImpl._(isNegative, used, resultDigits);
+  }
+
+  /// Returns `abs(this) & abs(other)` with sign set according to [isNegative].
+  _BigIntImpl _absAndSetSign(_BigIntImpl other, bool isNegative) {
+    var resultUsed = _min(_used, other._used);
+    var digits = _digits;
+    var otherDigits = other._digits;
+    var resultDigits = Uint16List(resultUsed);
+    for (var i = 0; i < resultUsed; i++) {
+      resultDigits[i] = digits[i] & otherDigits[i];
+    }
+    return _BigIntImpl._(isNegative, resultUsed, resultDigits);
+  }
+
+  /// Returns `abs(this) &~ abs(other)` with sign set according to [isNegative].
+  _BigIntImpl _absAndNotSetSign(_BigIntImpl other, bool isNegative) {
+    var resultUsed = _used;
+    var digits = _digits;
+    var otherDigits = other._digits;
+    var resultDigits = Uint16List(resultUsed);
+    var m = _min(resultUsed, other._used);
+    for (var i = 0; i < m; i++) {
+      resultDigits[i] = digits[i] & ~otherDigits[i];
+    }
+    for (var i = m; i < resultUsed; i++) {
+      resultDigits[i] = digits[i];
+    }
+    return _BigIntImpl._(isNegative, resultUsed, resultDigits);
+  }
+
+  /// Returns `abs(this) | abs(other)` with sign set according to [isNegative].
+  _BigIntImpl _absOrSetSign(_BigIntImpl other, bool isNegative) {
+    var used = _used;
+    var otherUsed = other._used;
+    var resultUsed = _max(used, otherUsed);
+    var digits = _digits;
+    var otherDigits = other._digits;
+    var resultDigits = Uint16List(resultUsed);
+    var l, m;
+    if (used < otherUsed) {
+      l = other;
+      m = used;
+    } else {
+      l = this;
+      m = otherUsed;
+    }
+    for (var i = 0; i < m; i++) {
+      resultDigits[i] = digits[i] | otherDigits[i];
+    }
+    var lDigits = l._digits;
+    for (var i = m; i < resultUsed; i++) {
+      resultDigits[i] = lDigits[i];
+    }
+    return _BigIntImpl._(isNegative, resultUsed, resultDigits);
+  }
+
+  /// Returns `abs(this) ^ abs(other)` with sign set according to [isNegative].
+  _BigIntImpl _absXorSetSign(_BigIntImpl other, bool isNegative) {
+    var used = _used;
+    var otherUsed = other._used;
+    var resultUsed = _max(used, otherUsed);
+    var digits = _digits;
+    var otherDigits = other._digits;
+    var resultDigits = Uint16List(resultUsed);
+    var l, m;
+    if (used < otherUsed) {
+      l = other;
+      m = used;
+    } else {
+      l = this;
+      m = otherUsed;
+    }
+    for (var i = 0; i < m; i++) {
+      resultDigits[i] = digits[i] ^ otherDigits[i];
+    }
+    var lDigits = l._digits;
+    for (var i = m; i < resultUsed; i++) {
+      resultDigits[i] = lDigits[i];
+    }
+    return _BigIntImpl._(isNegative, resultUsed, resultDigits);
+  }
+
+  /**
+   * Bit-wise and operator.
+   *
+   * Treating both `this` and [other] as sufficiently large two's component
+   * integers, the result is a number with only the bits set that are set in
+   * both `this` and [other]
+   *
+   * Of both operands are negative, the result is negative, otherwise
+   * the result is non-negative.
+   */
+  _BigIntImpl operator &(BigInt bigInt) {
+    _BigIntImpl other = bigInt;
+    if (_isZero || other._isZero) return zero;
+    if (_isNegative == other._isNegative) {
+      if (_isNegative) {
+        // (-this) & (-other) == ~(this-1) & ~(other-1)
+        //                    == ~((this-1) | (other-1))
+        //                    == -(((this-1) | (other-1)) + 1)
+        _BigIntImpl this1 = _absSubSetSign(one, true);
+        _BigIntImpl other1 = other._absSubSetSign(one, true);
+        // Result cannot be zero if this and other are negative.
+        return this1._absOrSetSign(other1, true)._absAddSetSign(one, true);
+      }
+      return _absAndSetSign(other, false);
+    }
+    // _isNegative != other._isNegative
+    var p, n;
+    if (_isNegative) {
+      p = other;
+      n = this;
+    } else {
+      // & is symmetric.
+      p = this;
+      n = other;
+    }
+    // p & (-n) == p & ~(n-1) == p &~ (n-1)
+    var n1 = n._absSubSetSign(one, false);
+    return p._absAndNotSetSign(n1, false);
+  }
+
+  /**
+   * Bit-wise or operator.
+   *
+   * Treating both `this` and [other] as sufficiently large two's component
+   * integers, the result is a number with the bits set that are set in either
+   * of `this` and [other]
+   *
+   * If both operands are non-negative, the result is non-negative,
+   * otherwise the result us negative.
+   */
+  _BigIntImpl operator |(BigInt bigInt) {
+    _BigIntImpl other = bigInt;
+    if (_isZero) return other;
+    if (other._isZero) return this;
+    if (_isNegative == other._isNegative) {
+      if (_isNegative) {
+        // (-this) | (-other) == ~(this-1) | ~(other-1)
+        //                    == ~((this-1) & (other-1))
+        //                    == -(((this-1) & (other-1)) + 1)
+        var this1 = _absSubSetSign(one, true);
+        var other1 = other._absSubSetSign(one, true);
+        // Result cannot be zero if this and a are negative.
+        return this1._absAndSetSign(other1, true)._absAddSetSign(one, true);
+      }
+      return _absOrSetSign(other, false);
+    }
+    // _neg != a._neg
+    var p, n;
+    if (_isNegative) {
+      p = other;
+      n = this;
+    } else {
+      // | is symmetric.
+      p = this;
+      n = other;
+    }
+    // p | (-n) == p | ~(n-1) == ~((n-1) &~ p) == -(~((n-1) &~ p) + 1)
+    var n1 = n._absSubSetSign(one, true);
+    // Result cannot be zero if only one of this or a is negative.
+    return n1._absAndNotSetSign(p, true)._absAddSetSign(one, true);
+  }
+
+  /**
+   * Bit-wise exclusive-or operator.
+   *
+   * Treating both `this` and [other] as sufficiently large two's component
+   * integers, the result is a number with the bits set that are set in one,
+   * but not both, of `this` and [other]
+   *
+   * If the operands have the same sign, the result is non-negative,
+   * otherwise the result is negative.
+   */
+  _BigIntImpl operator ^(BigInt bigInt) {
+    _BigIntImpl other = bigInt;
+    if (_isZero) return other;
+    if (other._isZero) return this;
+    if (_isNegative == other._isNegative) {
+      if (_isNegative) {
+        // (-this) ^ (-other) == ~(this-1) ^ ~(other-1) == (this-1) ^ (other-1)
+        var this1 = _absSubSetSign(one, true);
+        var other1 = other._absSubSetSign(one, true);
+        return this1._absXorSetSign(other1, false);
+      }
+      return _absXorSetSign(other, false);
+    }
+    // _isNegative != a._isNegative
+    var p, n;
+    if (_isNegative) {
+      p = other;
+      n = this;
+    } else {
+      // ^ is symmetric.
+      p = this;
+      n = other;
+    }
+    // p ^ (-n) == p ^ ~(n-1) == ~(p ^ (n-1)) == -((p ^ (n-1)) + 1)
+    var n1 = n._absSubSetSign(one, true);
+    // Result cannot be zero if only one of this or a is negative.
+    return p._absXorSetSign(n1, true)._absAddSetSign(one, true);
+  }
+
+  /**
+   * The bit-wise negate operator.
+   *
+   * Treating `this` as a sufficiently large two's component integer,
+   * the result is a number with the opposite bits set.
+   *
+   * This maps any integer `x` to `-x - 1`.
+   */
+  _BigIntImpl operator ~() {
+    if (_isZero) return _minusOne;
+    if (_isNegative) {
+      // ~(-this) == ~(~(this-1)) == this-1
+      return _absSubSetSign(one, false);
+    }
+    // ~this == -this-1 == -(this+1)
+    // Result cannot be zero if this is positive.
+    return _absAddSetSign(one, true);
+  }
+
+  /// Addition operator.
+  _BigIntImpl operator +(BigInt bigInt) {
+    _BigIntImpl other = bigInt;
+    if (_isZero) return other;
+    if (other._isZero) return this;
+    var isNegative = _isNegative;
+    if (isNegative == other._isNegative) {
+      // this + other == this + other
+      // (-this) + (-other) == -(this + other)
+      return _absAddSetSign(other, isNegative);
+    }
+    // this + (-other) == this - other == -(this - other)
+    // (-this) + other == other - this == -(this - other)
+    if (_absCompare(other) >= 0) {
+      return _absSubSetSign(other, isNegative);
+    }
+    return other._absSubSetSign(this, !isNegative);
+  }
+
+  /// Subtraction operator.
+  _BigIntImpl operator -(BigInt bigInt) {
+    _BigIntImpl other = bigInt;
+    if (_isZero) return -other;
+    if (other._isZero) return this;
+    var isNegative = _isNegative;
+    if (isNegative != other._isNegative) {
+      // this - (-other) == this + other
+      // (-this) - other == -(this + other)
+      return _absAddSetSign(other, isNegative);
+    }
+    // this - other == this - a == -(this - other)
+    // (-this) - (-other) == other - this == -(this - other)
+    if (_absCompare(other) >= 0) {
+      return _absSubSetSign(other, isNegative);
+    }
+    return other._absSubSetSign(this, !isNegative);
+  }
+
+  /// Multiplies [x] with [multiplicandDigits] and adds the result to
+  /// [accumulatorDigits].
+  ///
+  /// The [multiplicandDigits] in the range [i] to [i]+[n]-1 are the
+  /// multiplicand digits.
+  ///
+  /// The [acculumatorDigits] in the range [j] to [j]+[n]-1 are the accumulator
+  /// digits.
+  ///
+  /// Adds the result of the multiplicand-digits * [x] to the accumulator.
+  ///
+  /// Concretely: `accumulatorDigits[j..j+n] += x * m_digits[i..i+n-1]`.
+  static void _mulAdd(int x, Uint16List multiplicandDigits, int i,
+      Uint16List accumulatorDigits, int j, int n) {
+    if (x == 0) {
+      // No-op if x is 0.
+      return;
+    }
+    int c = 0;
+    while (--n >= 0) {
+      int product = x * multiplicandDigits[i++];
+      int combined = product + accumulatorDigits[j] + c;
+      accumulatorDigits[j++] = combined & _digitMask;
+      // Note that this works with 53 bits, as the division will not lose
+      // bits.
+      c = combined ~/ _digitBase;
+    }
+    while (c != 0) {
+      int l = accumulatorDigits[j] + c;
+      accumulatorDigits[j++] = l & _digitMask;
+      c = l ~/ _digitBase;
+    }
+  }
+
+  /// Multiplication operator.
+  _BigIntImpl operator *(BigInt bigInt) {
+    _BigIntImpl other = bigInt;
+    var used = _used;
+    var otherUsed = other._used;
+    if (used == 0 || otherUsed == 0) {
+      return zero;
+    }
+    var resultUsed = used + otherUsed;
+    var digits = _digits;
+    var otherDigits = other._digits;
+    var resultDigits = Uint16List(resultUsed);
+    var i = 0;
+    while (i < otherUsed) {
+      _mulAdd(otherDigits[i], digits, 0, resultDigits, i, used);
+      i++;
+    }
+    return _BigIntImpl._(
+        _isNegative != other._isNegative, resultUsed, resultDigits);
+  }
+
+  // r_digits[0..rUsed-1] = xDigits[0..xUsed-1]*otherDigits[0..otherUsed-1].
+  // Return resultUsed = xUsed + otherUsed.
+  static int _mulDigits(Uint16List xDigits, int xUsed, Uint16List otherDigits,
+      int otherUsed, Uint16List resultDigits) {
+    var resultUsed = xUsed + otherUsed;
+    var i = resultUsed;
+    assert(resultDigits.length >= i);
+    while (--i >= 0) {
+      resultDigits[i] = 0;
+    }
+    i = 0;
+    while (i < otherUsed) {
+      _mulAdd(otherDigits[i], xDigits, 0, resultDigits, i, xUsed);
+      i++;
+    }
+    return resultUsed;
+  }
+
+  /// Returns an estimate of `digits[i-1..i] ~/ topDigitDivisor`.
+  static int _estimateQuotientDigit(
+      int topDigitDivisor, Uint16List digits, int i) {
+    if (digits[i] == topDigitDivisor) return _digitMask;
+    var quotientDigit =
+        (digits[i] << _digitBits | digits[i - 1]) ~/ topDigitDivisor;
+    if (quotientDigit > _digitMask) return _digitMask;
+    return quotientDigit;
+  }
+
+  /// Returns `trunc(this / other)`, with `other != 0`.
+  _BigIntImpl _div(BigInt bigInt) {
+    _BigIntImpl other = bigInt;
+    assert(other._used > 0);
+    if (_used < other._used) {
+      return zero;
+    }
+    _divRem(other);
+    // Return quotient, i.e.
+    // _lastQuoRem_digits[_lastRem_used.._lastQuoRem_used-1] with proper sign.
+    var lastQuo_used = _lastQuoRemUsed - _lastRemUsed;
+    var quo_digits = _cloneDigits(
+        _lastQuoRemDigits, _lastRemUsed, _lastQuoRemUsed, lastQuo_used);
+    var quo = _BigIntImpl._(false, lastQuo_used, quo_digits);
+    if ((_isNegative != other._isNegative) && (quo._used > 0)) {
+      quo = -quo;
+    }
+    return quo;
+  }
+
+  /// Returns `this - other * trunc(this / other)`, with `other != 0`.
+  _BigIntImpl _rem(BigInt bigInt) {
+    _BigIntImpl other = bigInt;
+    assert(other._used > 0);
+    if (_used < other._used) {
+      return this;
+    }
+    _divRem(other);
+    // Return remainder, i.e.
+    // denormalized _lastQuoRem_digits[0.._lastRem_used-1] with proper sign.
+    var remDigits =
+        _cloneDigits(_lastQuoRemDigits, 0, _lastRemUsed, _lastRemUsed);
+    var rem = _BigIntImpl._(false, _lastRemUsed, remDigits);
+    if (_lastRem_nsh > 0) {
+      rem = rem >> _lastRem_nsh; // Denormalize remainder.
+    }
+    if (_isNegative && (rem._used > 0)) {
+      rem = -rem;
+    }
+    return rem;
+  }
+
+  /// Computes this ~/ other and this.remainder(other).
+  ///
+  /// Stores the result in [_lastQuoRemDigits], [_lastQuoRemUsed] and
+  /// [_lastRemUsed]. The [_lastQuoRemDigits] contains the digits of *both*, the
+  /// quotient and the remainder.
+  ///
+  /// Caches the input to avoid doing the work again when users write
+  /// `a ~/ b` followed by a `a % b`.
+  void _divRem(_BigIntImpl other) {
+    // Check if result is already cached.
+    if ((this._used == _lastDividendUsed) &&
+        (other._used == _lastDivisorUsed) &&
+        identical(this._digits, _lastDividendDigits) &&
+        identical(other._digits, _lastDivisorDigits)) {
+      return;
+    }
+    assert(_used >= other._used);
+
+    var nsh = _digitBits - other._digits[other._used - 1].bitLength;
+    // Concatenated positive quotient and normalized positive remainder.
+    // The resultDigits can have at most one more digit than the dividend.
+    Uint16List resultDigits;
+    int resultUsed;
+    // Normalized positive divisor.
+    // The normalized divisor has the most-significant bit of its most
+    // significant digit set.
+    // This makes estimating the quotient easier.
+    Uint16List yDigits;
+    int yUsed;
+    if (nsh > 0) {
+      yDigits = Uint16List(other._used + 5);
+      yUsed = _lShiftDigits(other._digits, other._used, nsh, yDigits);
+      resultDigits = Uint16List(_used + 5);
+      resultUsed = _lShiftDigits(_digits, _used, nsh, resultDigits);
+    } else {
+      yDigits = other._digits;
+      yUsed = other._used;
+      resultDigits = _cloneDigits(_digits, 0, _used, _used + 2);
+      resultUsed = _used;
+    }
+    var topDigitDivisor = yDigits[yUsed - 1];
+    var i = resultUsed;
+    var j = i - yUsed;
+    // tmpDigits is a temporary array of i (resultUsed) digits.
+    var tmpDigits = Uint16List(i);
+    var tmpUsed = _dlShiftDigits(yDigits, yUsed, j, tmpDigits);
+    // Explicit first division step in case normalized dividend is larger or
+    // equal to shifted normalized divisor.
+    if (_compareDigits(resultDigits, resultUsed, tmpDigits, tmpUsed) >= 0) {
+      assert(i == resultUsed);
+      resultDigits[resultUsed++] = 1; // Quotient = 1.
+      // Subtract divisor from remainder.
+      _absSub(resultDigits, resultUsed, tmpDigits, tmpUsed, resultDigits);
+    } else {
+      // Account for possible carry in _mulAdd step.
+      resultDigits[resultUsed++] = 0;
+    }
+
+    // Negate y so we can later use _mulAdd instead of non-existent _mulSub.
+    var nyDigits = Uint16List(yUsed + 2);
+    nyDigits[yUsed] = 1;
+    _absSub(nyDigits, yUsed + 1, yDigits, yUsed, nyDigits);
+    // nyDigits is read-only and has yUsed digits (possibly including several
+    // leading zeros).
+    // resultDigits is modified during iteration.
+    // resultDigits[0..yUsed-1] is the current remainder.
+    // resultDigits[yUsed..resultUsed-1] is the current quotient.
+    --i;
+
+    while (j > 0) {
+      var estimatedQuotientDigit =
+          _estimateQuotientDigit(topDigitDivisor, resultDigits, i);
+      j--;
+      _mulAdd(estimatedQuotientDigit, nyDigits, 0, resultDigits, j, yUsed);
+      if (resultDigits[i] < estimatedQuotientDigit) {
+        // Reusing the already existing tmpDigits array.
+        var tmpUsed = _dlShiftDigits(nyDigits, yUsed, j, tmpDigits);
+        _absSub(resultDigits, resultUsed, tmpDigits, tmpUsed, resultDigits);
+        while (resultDigits[i] < --estimatedQuotientDigit) {
+          _absSub(resultDigits, resultUsed, tmpDigits, tmpUsed, resultDigits);
+        }
+      }
+      i--;
+    }
+    // Cache result.
+    _lastDividendDigits = _digits;
+    _lastDividendUsed = _used;
+    _lastDivisorDigits = other._digits;
+    _lastDivisorUsed = other._used;
+    _lastQuoRemDigits = resultDigits;
+    _lastQuoRemUsed = resultUsed;
+    _lastRemUsed = yUsed;
+    _lastRem_nsh = nsh;
+  }
+
+  int get hashCode {
+    // This is the [Jenkins hash function][1] but using masking to keep
+    // values in SMI range.
+    //
+    // [1]: http://en.wikipedia.org/wiki/Jenkins_hash_function
+
+    int combine(int hash, int value) {
+      hash = 0x1fffffff & (hash + value);
+      hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10));
+      return hash ^ (hash >> 6);
+    }
+
+    int finish(int hash) {
+      hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3));
+      hash = hash ^ (hash >> 11);
+      return 0x1fffffff & (hash + ((0x00003fff & hash) << 15));
+    }
+
+    if (_isZero) return 6707; // Just a random number.
+    var hash = _isNegative ? 83585 : 429689; // Also random.
+    for (int i = 0; i < _used; i++) {
+      hash = combine(hash, _digits[i]);
+    }
+    return finish(hash);
+  }
+
+  /**
+   * Test whether this value is numerically equal to `other`.
+   *
+   * If [other] is a [_BigIntImpl] returns whether the two operands have the same
+   * value.
+   *
+   * Returns false if `other` is not a [_BigIntImpl].
+   */
+  bool operator ==(Object other) =>
+      other is _BigIntImpl && compareTo(other) == 0;
+
+  /**
+   * Returns the minimum number of bits required to store this big integer.
+   *
+   * The number of bits excludes the sign bit, which gives the natural length
+   * for non-negative (unsigned) values.  Negative values are complemented to
+   * return the bit position of the first bit that differs from the sign bit.
+   *
+   * To find the number of bits needed to store the value as a signed value,
+   * add one, i.e. use `x.bitLength + 1`.
+   *
+   * ```
+   * x.bitLength == (-x-1).bitLength
+   *
+   * new BigInt.from(3).bitLength == 2;   // 00000011
+   * new BigInt.from(2).bitLength == 2;   // 00000010
+   * new BigInt.from(1).bitLength == 1;   // 00000001
+   * new BigInt.from(0).bitLength == 0;   // 00000000
+   * new BigInt.from(-1).bitLength == 0;  // 11111111
+   * new BigInt.from(-2).bitLength == 1;  // 11111110
+   * new BigInt.from(-3).bitLength == 2;  // 11111101
+   * new BigInt.from(-4).bitLength == 2;  // 11111100
+   * ```
+   */
+  int get bitLength {
+    if (_used == 0) return 0;
+    if (_isNegative) return (~this).bitLength;
+    return _digitBits * (_used - 1) + _digits[_used - 1].bitLength;
+  }
+
+  /**
+   * Truncating division operator.
+   *
+   * Performs a truncating integer division, where the remainder is discarded.
+   *
+   * The remainder can be computed using the [remainder] method.
+   *
+   * Examples:
+   * ```
+   * var seven = new BigInt.from(7);
+   * var three = new BigInt.from(3);
+   * seven ~/ three;    // => 2
+   * (-seven) ~/ three; // => -2
+   * seven ~/ -three;   // => -2
+   * seven.remainder(three);    // => 1
+   * (-seven).remainder(three); // => -1
+   * seven.remainder(-three);   // => 1
+   * ```
+   */
+  _BigIntImpl operator ~/(BigInt bigInt) {
+    _BigIntImpl other = bigInt;
+    if (other._used == 0) {
+      throw const IntegerDivisionByZeroException();
+    }
+    return _div(other);
+  }
+
+  /**
+   * Returns the remainder of the truncating division of `this` by [other].
+   *
+   * The result `r` of this operation satisfies:
+   * `this == (this ~/ other) * other + r`.
+   * As a consequence the remainder `r` has the same sign as the divider `this`.
+   */
+  _BigIntImpl remainder(BigInt bigInt) {
+    _BigIntImpl other = bigInt;
+    if (other._used == 0) {
+      throw const IntegerDivisionByZeroException();
+    }
+    return _rem(other);
+  }
+
+  /// Division operator.
+  double operator /(BigInt other) => this.toDouble() / other.toDouble();
+
+  /** Relational less than operator. */
+  bool operator <(BigInt other) => compareTo(other) < 0;
+
+  /** Relational less than or equal operator. */
+  bool operator <=(BigInt other) => compareTo(other) <= 0;
+
+  /** Relational greater than operator. */
+  bool operator >(BigInt other) => compareTo(other) > 0;
+
+  /** Relational greater than or equal operator. */
+  bool operator >=(BigInt other) => compareTo(other) >= 0;
+
+  /**
+   * Euclidean modulo operator.
+   *
+   * Returns the remainder of the Euclidean division. The Euclidean division of
+   * two integers `a` and `b` yields two integers `q` and `r` such that
+   * `a == b * q + r` and `0 <= r < b.abs()`.
+   *
+   * The sign of the returned value `r` is always positive.
+   *
+   * See [remainder] for the remainder of the truncating division.
+   */
+  _BigIntImpl operator %(BigInt bigInt) {
+    _BigIntImpl other = bigInt;
+    if (other._used == 0) {
+      throw const IntegerDivisionByZeroException();
+    }
+    var result = _rem(other);
+    if (result._isNegative) {
+      if (other._isNegative) {
+        result = result - other;
+      } else {
+        result = result + other;
+      }
+    }
+    return result;
+  }
+
+  /**
+   * Returns the sign of this big integer.
+   *
+   * Returns 0 for zero, -1 for values less than zero and
+   * +1 for values greater than zero.
+   */
+  int get sign {
+    if (_used == 0) return 0;
+    return _isNegative ? -1 : 1;
+  }
+
+  /// Whether this big integer is even.
+  bool get isEven => _used == 0 || (_digits[0] & 1) == 0;
+
+  /// Whether this big integer is odd.
+  bool get isOdd => !isEven;
+
+  /// Whether this number is negative.
+  bool get isNegative => _isNegative;
+
+  _BigIntImpl pow(int exponent) {
+    if (exponent < 0) {
+      throw ArgumentError("Exponent must not be negative: $exponent");
+    }
+    if (exponent == 0) return one;
+
+    // Exponentiation by squaring.
+    var result = one;
+    var base = this;
+    while (exponent != 0) {
+      if ((exponent & 1) == 1) {
+        result *= base;
+      }
+      exponent >>= 1;
+      // Skip unnecessary operation.
+      if (exponent != 0) {
+        base *= base;
+      }
+    }
+    return result;
+  }
+
+  /**
+   * Returns this integer to the power of [exponent] modulo [modulus].
+   *
+   * The [exponent] must be non-negative and [modulus] must be
+   * positive.
+   */
+  _BigIntImpl modPow(BigInt bigExponent, BigInt bigModulus) {
+    _BigIntImpl exponent = bigExponent;
+    _BigIntImpl modulus = bigModulus;
+    if (exponent._isNegative) {
+      throw ArgumentError("exponent must be positive: $exponent");
+    }
+    if (modulus <= zero) {
+      throw ArgumentError("modulus must be strictly positive: $modulus");
+    }
+    if (exponent._isZero) return one;
+
+    final modulusUsed = modulus._used;
+    final modulusUsed2p4 = 2 * modulusUsed + 4;
+    final exponentBitlen = exponent.bitLength;
+    if (exponentBitlen <= 0) return one;
+    _BigIntReduction z = _BigIntClassic(modulus);
+    var resultDigits = Uint16List(modulusUsed2p4);
+    var result2Digits = Uint16List(modulusUsed2p4);
+    var gDigits = Uint16List(modulusUsed);
+    var gUsed = z.convert(this, gDigits);
+    // Initialize result with g.
+    // Copy leading zero if any.
+    for (int j = gUsed - 1; j >= 0; j--) {
+      resultDigits[j] = gDigits[j];
+    }
+    var resultUsed = gUsed;
+    var result2Used;
+    for (int i = exponentBitlen - 2; i >= 0; i--) {
+      result2Used = z.sqr(resultDigits, resultUsed, result2Digits);
+      if (!(exponent & (one << i))._isZero) {
+        resultUsed =
+            z.mul(result2Digits, result2Used, gDigits, gUsed, resultDigits);
+      } else {
+        // Swap result and result2.
+        var tmpDigits = resultDigits;
+        var tmpUsed = resultUsed;
+        resultDigits = result2Digits;
+        resultUsed = result2Used;
+        result2Digits = tmpDigits;
+        result2Used = tmpUsed;
+      }
+    }
+    return z.revert(resultDigits, resultUsed);
+  }
+
+  // If inv is false, returns gcd(x, y).
+  // If inv is true and gcd(x, y) = 1, returns d, so that c*x + d*y = 1.
+  // If inv is true and gcd(x, y) != 1, throws Exception("Not coprime").
+  static _BigIntImpl _binaryGcd(_BigIntImpl x, _BigIntImpl y, bool inv) {
+    var xDigits = x._digits;
+    var yDigits = y._digits;
+    var xUsed = x._used;
+    var yUsed = y._used;
+    var maxUsed = xUsed > yUsed ? xUsed : yUsed;
+    var unshiftedMaxUsed = maxUsed; // Keep
+    xDigits = _cloneDigits(xDigits, 0, xUsed, maxUsed);
+    yDigits = _cloneDigits(yDigits, 0, yUsed, maxUsed);
+    int shiftAmount = 0;
+    if (inv) {
+      if ((yUsed == 1) && (yDigits[0] == 1)) return one;
+      if ((yUsed == 0) || (yDigits[0].isEven && xDigits[0].isEven)) {
+        throw Exception("Not coprime");
+      }
+    } else {
+      if (x._isZero) {
+        throw ArgumentError.value(0, "this", "must not be zero");
+      }
+      if (y._isZero) {
+        throw ArgumentError.value(0, "other", "must not be zero");
+      }
+      if (((xUsed == 1) && (xDigits[0] == 1)) ||
+          ((yUsed == 1) && (yDigits[0] == 1))) return one;
+      while (((xDigits[0] & 1) == 0) && ((yDigits[0] & 1) == 0)) {
+        _rsh(xDigits, xUsed, 1, xDigits);
+        _rsh(yDigits, yUsed, 1, yDigits);
+        shiftAmount++;
+      }
+      if (shiftAmount >= _digitBits) {
+        var digitShiftAmount = shiftAmount ~/ _digitBits;
+        xUsed -= digitShiftAmount;
+        yUsed -= digitShiftAmount;
+        maxUsed -= digitShiftAmount;
+      }
+      if ((yDigits[0] & 1) == 1) {
+        // Swap x and y.
+        var tmpDigits = xDigits;
+        var tmpUsed = xUsed;
+        xDigits = yDigits;
+        xUsed = yUsed;
+        yDigits = tmpDigits;
+        yUsed = tmpUsed;
+      }
+    }
+    var uDigits = _cloneDigits(xDigits, 0, xUsed, unshiftedMaxUsed);
+    var vDigits =
+        _cloneDigits(yDigits, 0, yUsed, unshiftedMaxUsed + 2); // +2 for lsh.
+    final bool ac = (xDigits[0] & 1) == 0;
+
+    // Variables a, b, c, and d require one more digit.
+    final abcdUsed = maxUsed + 1;
+    final abcdLen = abcdUsed + 2; // +2 to satisfy _absAdd.
+    var aDigits, bDigits, cDigits, dDigits;
+    bool aIsNegative, bIsNegative, cIsNegative, dIsNegative;
+    if (ac) {
+      aDigits = Uint16List(abcdLen);
+      aIsNegative = false;
+      aDigits[0] = 1;
+      cDigits = Uint16List(abcdLen);
+      cIsNegative = false;
+    }
+    bDigits = Uint16List(abcdLen);
+    bIsNegative = false;
+    dDigits = Uint16List(abcdLen);
+    dIsNegative = false;
+    dDigits[0] = 1;
+
+    while (true) {
+      while ((uDigits[0] & 1) == 0) {
+        _rsh(uDigits, maxUsed, 1, uDigits);
+        if (ac) {
+          if (((aDigits[0] & 1) == 1) || ((bDigits[0] & 1) == 1)) {
+            // a += y
+            if (aIsNegative) {
+              if ((aDigits[maxUsed] != 0) ||
+                  (_compareDigits(aDigits, maxUsed, yDigits, maxUsed)) > 0) {
+                _absSub(aDigits, abcdUsed, yDigits, maxUsed, aDigits);
+              } else {
+                _absSub(yDigits, maxUsed, aDigits, maxUsed, aDigits);
+                aIsNegative = false;
+              }
+            } else {
+              _absAdd(aDigits, abcdUsed, yDigits, maxUsed, aDigits);
+            }
+            // b -= x
+            if (bIsNegative) {
+              _absAdd(bDigits, abcdUsed, xDigits, maxUsed, bDigits);
+            } else if ((bDigits[maxUsed] != 0) ||
+                (_compareDigits(bDigits, maxUsed, xDigits, maxUsed) > 0)) {
+              _absSub(bDigits, abcdUsed, xDigits, maxUsed, bDigits);
+            } else {
+              _absSub(xDigits, maxUsed, bDigits, maxUsed, bDigits);
+              bIsNegative = true;
+            }
+          }
+          _rsh(aDigits, abcdUsed, 1, aDigits);
+        } else if ((bDigits[0] & 1) == 1) {
+          // b -= x
+          if (bIsNegative) {
+            _absAdd(bDigits, abcdUsed, xDigits, maxUsed, bDigits);
+          } else if ((bDigits[maxUsed] != 0) ||
+              (_compareDigits(bDigits, maxUsed, xDigits, maxUsed) > 0)) {
+            _absSub(bDigits, abcdUsed, xDigits, maxUsed, bDigits);
+          } else {
+            _absSub(xDigits, maxUsed, bDigits, maxUsed, bDigits);
+            bIsNegative = true;
+          }
+        }
+        _rsh(bDigits, abcdUsed, 1, bDigits);
+      }
+      while ((vDigits[0] & 1) == 0) {
+        _rsh(vDigits, maxUsed, 1, vDigits);
+        if (ac) {
+          if (((cDigits[0] & 1) == 1) || ((dDigits[0] & 1) == 1)) {
+            // c += y
+            if (cIsNegative) {
+              if ((cDigits[maxUsed] != 0) ||
+                  (_compareDigits(cDigits, maxUsed, yDigits, maxUsed) > 0)) {
+                _absSub(cDigits, abcdUsed, yDigits, maxUsed, cDigits);
+              } else {
+                _absSub(yDigits, maxUsed, cDigits, maxUsed, cDigits);
+                cIsNegative = false;
+              }
+            } else {
+              _absAdd(cDigits, abcdUsed, yDigits, maxUsed, cDigits);
+            }
+            // d -= x
+            if (dIsNegative) {
+              _absAdd(dDigits, abcdUsed, xDigits, maxUsed, dDigits);
+            } else if ((dDigits[maxUsed] != 0) ||
+                (_compareDigits(dDigits, maxUsed, xDigits, maxUsed) > 0)) {
+              _absSub(dDigits, abcdUsed, xDigits, maxUsed, dDigits);
+            } else {
+              _absSub(xDigits, maxUsed, dDigits, maxUsed, dDigits);
+              dIsNegative = true;
+            }
+          }
+          _rsh(cDigits, abcdUsed, 1, cDigits);
+        } else if ((dDigits[0] & 1) == 1) {
+          // d -= x
+          if (dIsNegative) {
+            _absAdd(dDigits, abcdUsed, xDigits, maxUsed, dDigits);
+          } else if ((dDigits[maxUsed] != 0) ||
+              (_compareDigits(dDigits, maxUsed, xDigits, maxUsed) > 0)) {
+            _absSub(dDigits, abcdUsed, xDigits, maxUsed, dDigits);
+          } else {
+            _absSub(xDigits, maxUsed, dDigits, maxUsed, dDigits);
+            dIsNegative = true;
+          }
+        }
+        _rsh(dDigits, abcdUsed, 1, dDigits);
+      }
+      if (_compareDigits(uDigits, maxUsed, vDigits, maxUsed) >= 0) {
+        // u -= v
+        _absSub(uDigits, maxUsed, vDigits, maxUsed, uDigits);
+        if (ac) {
+          // a -= c
+          if (aIsNegative == cIsNegative) {
+            var a_cmp_c = _compareDigits(aDigits, abcdUsed, cDigits, abcdUsed);
+            if (a_cmp_c > 0) {
+              _absSub(aDigits, abcdUsed, cDigits, abcdUsed, aDigits);
+            } else {
+              _absSub(cDigits, abcdUsed, aDigits, abcdUsed, aDigits);
+              aIsNegative = !aIsNegative && (a_cmp_c != 0);
+            }
+          } else {
+            _absAdd(aDigits, abcdUsed, cDigits, abcdUsed, aDigits);
+          }
+        }
+        // b -= d
+        if (bIsNegative == dIsNegative) {
+          var b_cmp_d = _compareDigits(bDigits, abcdUsed, dDigits, abcdUsed);
+          if (b_cmp_d > 0) {
+            _absSub(bDigits, abcdUsed, dDigits, abcdUsed, bDigits);
+          } else {
+            _absSub(dDigits, abcdUsed, bDigits, abcdUsed, bDigits);
+            bIsNegative = !bIsNegative && (b_cmp_d != 0);
+          }
+        } else {
+          _absAdd(bDigits, abcdUsed, dDigits, abcdUsed, bDigits);
+        }
+      } else {
+        // v -= u
+        _absSub(vDigits, maxUsed, uDigits, maxUsed, vDigits);
+        if (ac) {
+          // c -= a
+          if (cIsNegative == aIsNegative) {
+            var c_cmp_a = _compareDigits(cDigits, abcdUsed, aDigits, abcdUsed);
+            if (c_cmp_a > 0) {
+              _absSub(cDigits, abcdUsed, aDigits, abcdUsed, cDigits);
+            } else {
+              _absSub(aDigits, abcdUsed, cDigits, abcdUsed, cDigits);
+              cIsNegative = !cIsNegative && (c_cmp_a != 0);
+            }
+          } else {
+            _absAdd(cDigits, abcdUsed, aDigits, abcdUsed, cDigits);
+          }
+        }
+        // d -= b
+        if (dIsNegative == bIsNegative) {
+          var d_cmp_b = _compareDigits(dDigits, abcdUsed, bDigits, abcdUsed);
+          if (d_cmp_b > 0) {
+            _absSub(dDigits, abcdUsed, bDigits, abcdUsed, dDigits);
+          } else {
+            _absSub(bDigits, abcdUsed, dDigits, abcdUsed, dDigits);
+            dIsNegative = !dIsNegative && (d_cmp_b != 0);
+          }
+        } else {
+          _absAdd(dDigits, abcdUsed, bDigits, abcdUsed, dDigits);
+        }
+      }
+      // Exit loop if u == 0.
+      var i = maxUsed;
+      while ((i > 0) && (uDigits[i - 1] == 0)) --i;
+      if (i == 0) break;
+    }
+    if (!inv) {
+      if (shiftAmount > 0) {
+        maxUsed = _lShiftDigits(vDigits, maxUsed, shiftAmount, vDigits);
+      }
+      return _BigIntImpl._(false, maxUsed, vDigits);
+    }
+    // No inverse if v != 1.
+    var i = maxUsed - 1;
+    while ((i > 0) && (vDigits[i] == 0)) --i;
+    if ((i != 0) || (vDigits[0] != 1)) {
+      throw Exception("Not coprime");
+    }
+
+    if (dIsNegative) {
+      while ((dDigits[maxUsed] != 0) ||
+          (_compareDigits(dDigits, maxUsed, xDigits, maxUsed) > 0)) {
+        // d += x, d still negative
+        _absSub(dDigits, abcdUsed, xDigits, maxUsed, dDigits);
+      }
+      // d += x
+      _absSub(xDigits, maxUsed, dDigits, maxUsed, dDigits);
+      dIsNegative = false;
+    } else {
+      while ((dDigits[maxUsed] != 0) ||
+          (_compareDigits(dDigits, maxUsed, xDigits, maxUsed) >= 0)) {
+        // d -= x
+        _absSub(dDigits, abcdUsed, xDigits, maxUsed, dDigits);
+      }
+    }
+    return _BigIntImpl._(false, maxUsed, dDigits);
+  }
+
+  /**
+   * Returns the modular multiplicative inverse of this big integer
+   * modulo [modulus].
+   *
+   * The [modulus] must be positive.
+   *
+   * It is an error if no modular inverse exists.
+   */
+  // Returns 1/this % modulus, with modulus > 0.
+  _BigIntImpl modInverse(BigInt bigInt) {
+    _BigIntImpl modulus = bigInt;
+    if (modulus <= zero) {
+      throw ArgumentError("Modulus must be strictly positive: $modulus");
+    }
+    if (modulus == one) return zero;
+    var tmp = this;
+    if (tmp._isNegative || (tmp._absCompare(modulus) >= 0)) {
+      tmp %= modulus;
+    }
+    return _binaryGcd(modulus, tmp, true);
+  }
+
+  /**
+   * Returns the greatest common divisor of this big integer and [other].
+   *
+   * If either number is non-zero, the result is the numerically greatest
+   * integer dividing both `this` and `other`.
+   *
+   * The greatest common divisor is independent of the order,
+   * so `x.gcd(y)` is  always the same as `y.gcd(x)`.
+   *
+   * For any integer `x`, `x.gcd(x)` is `x.abs()`.
+   *
+   * If both `this` and `other` is zero, the result is also zero.
+   */
+  _BigIntImpl gcd(BigInt bigInt) {
+    _BigIntImpl other = bigInt;
+    if (_isZero) return other.abs();
+    if (other._isZero) return this.abs();
+    return _binaryGcd(this, other, false);
+  }
+
+  /**
+   * Returns the least significant [width] bits of this big integer as a
+   * non-negative number (i.e. unsigned representation).  The returned value has
+   * zeros in all bit positions higher than [width].
+   *
+   * ```
+   * new BigInt.from(-1).toUnsigned(5) == 31   // 11111111  ->  00011111
+   * ```
+   *
+   * This operation can be used to simulate arithmetic from low level languages.
+   * For example, to increment an 8 bit quantity:
+   *
+   * ```
+   * q = (q + 1).toUnsigned(8);
+   * ```
+   *
+   * `q` will count from `0` up to `255` and then wrap around to `0`.
+   *
+   * If the input fits in [width] bits without truncation, the result is the
+   * same as the input.  The minimum width needed to avoid truncation of `x` is
+   * given by `x.bitLength`, i.e.
+   *
+   * ```
+   * x == x.toUnsigned(x.bitLength);
+   * ```
+   */
+  _BigIntImpl toUnsigned(int width) {
+    return this & ((one << width) - one);
+  }
+
+  /**
+   * Returns the least significant [width] bits of this integer, extending the
+   * highest retained bit to the sign.  This is the same as truncating the value
+   * to fit in [width] bits using an signed 2-s complement representation.  The
+   * returned value has the same bit value in all positions higher than [width].
+   *
+   * ```
+   * var big15 = new BigInt.from(15);
+   * var big16 = new BigInt.from(16);
+   * var big239 = new BigInt.from(239);
+   *                                      V--sign bit-V
+   * big16.toSigned(5) == -big16   //  00010000 -> 11110000
+   * big239.toSigned(5) == big15   //  11101111 -> 00001111
+   *                                      ^           ^
+   * ```
+   *
+   * This operation can be used to simulate arithmetic from low level languages.
+   * For example, to increment an 8 bit signed quantity:
+   *
+   * ```
+   * q = (q + 1).toSigned(8);
+   * ```
+   *
+   * `q` will count from `0` up to `127`, wrap to `-128` and count back up to
+   * `127`.
+   *
+   * If the input value fits in [width] bits without truncation, the result is
+   * the same as the input.  The minimum width needed to avoid truncation of `x`
+   * is `x.bitLength + 1`, i.e.
+   *
+   * ```
+   * x == x.toSigned(x.bitLength + 1);
+   * ```
+   */
+  _BigIntImpl toSigned(int width) {
+    // The value of binary number weights each bit by a power of two.  The
+    // twos-complement value weights the sign bit negatively.  We compute the
+    // value of the negative weighting by isolating the sign bit with the
+    // correct power of two weighting and subtracting it from the value of the
+    // lower bits.
+    var signMask = one << (width - 1);
+    return (this & (signMask - one)) - (this & signMask);
+  }
+
+  // Maximum number of digits that always fit in mantissa.
+  static const _simpleValidIntDigits = 53 ~/ _digitBits;
+
+  bool get isValidInt {
+    if (_used <= _simpleValidIntDigits) return true;
+    var asInt = toInt();
+    if (!asInt.toDouble().isFinite) return false;
+    return this == _BigIntImpl._fromInt(asInt);
+  }
+
+  int toInt() {
+    var result = 0;
+    for (int i = _used - 1; i >= 0; i--) {
+      result = result * _digitBase + _digits[i];
+    }
+    return _isNegative ? -result : result;
+  }
+
+  /**
+   * Returns this [_BigIntImpl] as a [double].
+   *
+   * If the number is not representable as a [double], an
+   * approximation is returned. For numerically large integers, the
+   * approximation may be infinite.
+   */
+  double toDouble() {
+    const int exponentBias = 1075;
+    // There are 11 bits for the exponent.
+    // 2047 (all bits set to 1) is reserved for infinity and NaN.
+    // When storing the exponent in the 11 bits, it is biased by exponentBias
+    // to support negative exponents.
+    const int maxDoubleExponent = 2046 - exponentBias;
+    if (_isZero) return 0.0;
+
+    // We fill the 53 bits little-endian.
+    var resultBits = Uint8List(8);
+
+    var length = _digitBits * (_used - 1) + _digits[_used - 1].bitLength;
+    if (length > maxDoubleExponent + 53) {
+      return _isNegative ? double.negativeInfinity : double.infinity;
+    }
+
+    // The most significant bit is for the sign.
+    if (_isNegative) resultBits[7] = 0x80;
+
+    // Write the exponent into bits 1..12:
+    var biasedExponent = length - 53 + exponentBias;
+    resultBits[6] = (biasedExponent & 0xF) << 4;
+    resultBits[7] |= biasedExponent >> 4;
+
+    int cachedBits = 0;
+    int cachedBitsLength = 0;
+    int digitIndex = _used - 1;
+    int readBits(int n) {
+      // Ensure that we have enough bits in [cachedBits].
+      while (cachedBitsLength < n) {
+        int nextDigit;
+        int nextDigitLength = _digitBits; // May get updated.
+        if (digitIndex < 0) {
+          nextDigit = 0;
+          digitIndex--;
+        } else {
+          nextDigit = _digits[digitIndex];
+          if (digitIndex == _used - 1) nextDigitLength = nextDigit.bitLength;
+          digitIndex--;
+        }
+        cachedBits = (cachedBits << nextDigitLength) + nextDigit;
+        cachedBitsLength += nextDigitLength;
+      }
+      // Read the top [n] bits.
+      var result = cachedBits >> (cachedBitsLength - n);
+      // Remove the bits from the cache.
+      cachedBits -= result << (cachedBitsLength - n);
+      cachedBitsLength -= n;
+      return result;
+    }
+
+    // The first leading 1 bit is implicit in the double-representation and can
+    // be discarded.
+    var leadingBits = readBits(5) & 0xF;
+    resultBits[6] |= leadingBits;
+
+    for (int i = 5; i >= 0; i--) {
+      // Get the remaining 48 bits.
+      resultBits[i] = readBits(8);
+    }
+
+    void roundUp() {
+      // Simply consists of adding 1 to the whole 64 bit "number".
+      // It will update the exponent, if necessary.
+      // It might even round up to infinity (which is what we want).
+      var carry = 1;
+      for (int i = 0; i < 8; i++) {
+        if (carry == 0) break;
+        var sum = resultBits[i] + carry;
+        resultBits[i] = sum & 0xFF;
+        carry = sum >> 8;
+      }
+    }
+
+    if (readBits(1) == 1) {
+      if (resultBits[0].isOdd) {
+        // Rounds to even all the time.
+        roundUp();
+      } else {
+        // Round up, if there is at least one other digit that is not 0.
+        if (cachedBits != 0) {
+          // There is already one in the cachedBits.
+          roundUp();
+        } else {
+          for (int i = digitIndex; digitIndex >= 0; i--) {
+            if (_digits[i] != 0) {
+              roundUp();
+              break;
+            }
+          }
+        }
+      }
+    }
+    return resultBits.buffer.asByteData().getFloat64(0, Endian.little);
+  }
+
+  /**
+   * Returns a String-representation of this integer.
+   *
+   * The returned string is parsable by [parse].
+   * For any `_BigIntImpl` `i`, it is guaranteed that
+   * `i == _BigIntImpl.parse(i.toString())`.
+   */
+  String toString() {
+    if (_used == 0) return "0";
+    if (_used == 1) {
+      if (_isNegative) return (-_digits[0]).toString();
+      return _digits[0].toString();
+    }
+
+    // Generate in chunks of 4 digits.
+    // The chunks are in reversed order.
+    var decimalDigitChunks = <String>[];
+    var rest = isNegative ? -this : this;
+    while (rest._used > 1) {
+      var digits4 = rest.remainder(_bigInt10000).toString();
+      decimalDigitChunks.add(digits4);
+      if (digits4.length == 1) decimalDigitChunks.add("000");
+      if (digits4.length == 2) decimalDigitChunks.add("00");
+      if (digits4.length == 3) decimalDigitChunks.add("0");
+      rest = rest ~/ _bigInt10000;
+    }
+    decimalDigitChunks.add(rest._digits[0].toString());
+    if (_isNegative) decimalDigitChunks.add("-");
+    return decimalDigitChunks.reversed.join();
+  }
+
+  int _toRadixCodeUnit(int digit) {
+    const int _0 = 48;
+    const int _a = 97;
+    if (digit < 10) return _0 + digit;
+    return _a + digit - 10;
+  }
+
+  /**
+   * Converts [this] to a string representation in the given [radix].
+   *
+   * In the string representation, lower-case letters are used for digits above
+   * '9', with 'a' being 10 an 'z' being 35.
+   *
+   * The [radix] argument must be an integer in the range 2 to 36.
+   */
+  String toRadixString(int radix) {
+    if (radix > 36) throw RangeError.range(radix, 2, 36);
+
+    if (_used == 0) return "0";
+
+    if (_used == 1) {
+      var digitString = _digits[0].toRadixString(radix);
+      if (_isNegative) return "-" + digitString;
+      return digitString;
+    }
+
+    if (radix == 16) return _toHexString();
+
+    var base = _BigIntImpl._fromInt(radix);
+    var reversedDigitCodeUnits = <int>[];
+    var rest = this.abs();
+    while (!rest._isZero) {
+      var digit = rest.remainder(base).toInt();
+      rest = rest ~/ base;
+      reversedDigitCodeUnits.add(_toRadixCodeUnit(digit));
+    }
+    var digitString = String.fromCharCodes(reversedDigitCodeUnits.reversed);
+    if (_isNegative) return "-" + digitString;
+    return digitString;
+  }
+
+  String _toHexString() {
+    var chars = <int>[];
+    for (int i = 0; i < _used - 1; i++) {
+      int chunk = _digits[i];
+      for (int j = 0; j < (_digitBits ~/ 4); j++) {
+        chars.add(_toRadixCodeUnit(chunk & 0xF));
+        chunk >>= 4;
+      }
+    }
+    var msbChunk = _digits[_used - 1];
+    while (msbChunk != 0) {
+      chars.add(_toRadixCodeUnit(msbChunk & 0xF));
+      msbChunk >>= 4;
+    }
+    if (_isNegative) {
+      const _dash = 45;
+      chars.add(_dash);
+    }
+    return String.fromCharCodes(chars.reversed);
+  }
+}
+
+// Interface for modular reduction.
+abstract class _BigIntReduction {
+  // Return the number of digits used by r_digits.
+  int convert(_BigIntImpl x, Uint16List r_digits);
+  int mul(Uint16List xDigits, int xUsed, Uint16List yDigits, int yUsed,
+      Uint16List resultDigits);
+  int sqr(Uint16List xDigits, int xUsed, Uint16List resultDigits);
+
+  // Return x reverted to _BigIntImpl.
+  _BigIntImpl revert(Uint16List xDigits, int xUsed);
+}
+
+// Modular reduction using "classic" algorithm.
+class _BigIntClassic implements _BigIntReduction {
+  final _BigIntImpl _modulus; // Modulus.
+  final _BigIntImpl _normalizedModulus; // Normalized _modulus.
+
+  _BigIntClassic(this._modulus)
+      : _normalizedModulus = _modulus <<
+            (_BigIntImpl._digitBits -
+                _modulus._digits[_modulus._used - 1].bitLength);
+
+  int convert(_BigIntImpl x, Uint16List resultDigits) {
+    var digits;
+    var used;
+    if (x._isNegative || x._absCompare(_modulus) >= 0) {
+      var remainder = x._rem(_modulus);
+      if (x._isNegative && remainder._used > 0) {
+        assert(remainder._isNegative);
+        remainder += _modulus;
+      }
+      assert(!remainder._isNegative);
+      used = remainder._used;
+      digits = remainder._digits;
+    } else {
+      used = x._used;
+      digits = x._digits;
+    }
+    var i = used; // Copy leading zero if any.
+    while (--i >= 0) {
+      resultDigits[i] = digits[i];
+    }
+    return used;
+  }
+
+  _BigIntImpl revert(Uint16List xDigits, int xUsed) {
+    return _BigIntImpl._(false, xUsed, xDigits);
+  }
+
+  int _reduce(Uint16List xDigits, int xUsed) {
+    if (xUsed < _modulus._used) {
+      return xUsed;
+    }
+    var reverted = revert(xDigits, xUsed);
+    var rem = reverted._rem(_normalizedModulus);
+    return convert(rem, xDigits);
+  }
+
+  int sqr(Uint16List xDigits, int xUsed, Uint16List resultDigits) {
+    var b = _BigIntImpl._(false, xUsed, xDigits);
+    var b2 = b * b;
+    for (int i = 0; i < b2._used; i++) {
+      resultDigits[i] = b2._digits[i];
+    }
+    for (int i = b2._used; i < 2 * xUsed; i++) {
+      resultDigits[i] = 0;
+    }
+    return _reduce(resultDigits, 2 * xUsed);
+  }
+
+  int mul(Uint16List xDigits, int xUsed, Uint16List yDigits, int yUsed,
+      Uint16List resultDigits) {
+    var resultUsed =
+        _BigIntImpl._mulDigits(xDigits, xUsed, yDigits, yUsed, resultDigits);
+    return _reduce(resultDigits, resultUsed);
+  }
+}
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/patch/developer_patch.dart b/sdk_nnbd/lib/_internal/js_dev_runtime/patch/developer_patch.dart
new file mode 100644
index 0000000..7f5e4fe
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/patch/developer_patch.dart
@@ -0,0 +1,216 @@
+// Copyright (c) 2015, 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.
+
+// Patch file for dart:developer library.
+
+import 'dart:_js_helper' show patch, ForceInline, ReifyFunctionTypes;
+import 'dart:_foreign_helper' show JS, JSExportName;
+import 'dart:_runtime' as dart;
+import 'dart:async';
+import 'dart:convert' show json;
+import 'dart:isolate';
+
+@patch
+@ForceInline()
+bool debugger({bool when = true, String message}) {
+  if (when) {
+    JS('', 'debugger');
+  }
+  return when;
+}
+
+@patch
+Object inspect(Object object) {
+  // Note: this log level does not show up by default in Chrome.
+  // This is used for communication with the debugger service.
+  JS('', 'console.debug("dart.developer.inspect", #)', object);
+  return object;
+}
+
+@patch
+void log(String message,
+    {DateTime time,
+    int sequenceNumber,
+    int level = 0,
+    String name = '',
+    Zone zone,
+    Object error,
+    StackTrace stackTrace}) {
+  Object items =
+      JS('!', '{ message: #, name: #, level: # }', message, name, level);
+  if (time != null) JS('', '#.time = #', items, time);
+  if (sequenceNumber != null) {
+    JS('', '#.sequenceNumber = #', items, sequenceNumber);
+  }
+  if (zone != null) JS('', '#.zone = #', items, zone);
+  if (error != null) JS('', '#.error = #', items, error);
+  if (stackTrace != null) JS('', '#.stackTrace = #', items, stackTrace);
+
+  JS('', 'console.debug("dart.developer.log", #)', items);
+}
+
+final _extensions = Map<String, ServiceExtensionHandler>();
+
+@patch
+ServiceExtensionHandler _lookupExtension(String method) {
+  return _extensions[method];
+}
+
+@patch
+_registerExtension(String method, ServiceExtensionHandler handler) {
+  _extensions[method] = handler;
+  JS('', 'console.debug("dart.developer.registerExtension", #)', method);
+}
+
+/// Returns a JS `Promise` that resolves with the result of invoking
+/// [methodName] with an [encodedJson] map as its parameters.
+///
+/// This is used by the VM Service Prototcol to invoke extensions registered
+/// with [registerExtension]. For example, in JS:
+///
+///     await sdk.developer.invokeExtension(
+/// .         "ext.flutter.inspector.getRootWidget", '{"objectGroup":""}');
+///
+@JSExportName('invokeExtension')
+@ReifyFunctionTypes(false)
+_invokeExtension(String methodName, String encodedJson) {
+  // TODO(vsm): We should factor this out as future<->promise.
+  return JS('', 'new #.Promise(#)', dart.global_,
+      (Function(Object) resolve, Function(Object) reject) async {
+    try {
+      var method = _lookupExtension(methodName);
+      var parameters = (json.decode(encodedJson) as Map).cast<String, String>();
+      var result = await method(methodName, parameters);
+      resolve(result._toString());
+    } catch (e) {
+      // TODO(vsm): Reject or encode in result?
+      reject('$e');
+    }
+  });
+}
+
+@patch
+void _postEvent(String eventKind, String eventData) {
+  JS('', 'console.debug("dart.developer.postEvent", #, #)', eventKind,
+      eventData);
+}
+
+@patch
+bool _isDartStreamEnabled() {
+  return false;
+}
+
+@patch
+int _getTraceClock() {
+  // TODO.
+  return _clockValue++;
+}
+
+int _clockValue = 0;
+
+@patch
+int _getThreadCpuClock() {
+  return -1;
+}
+
+@patch
+void _reportCompleteEvent(int start, int startCpu, String category, String name,
+    String argumentsAsJson) {
+  // TODO.
+}
+
+@patch
+void _reportFlowEvent(int start, int startCpu, String category, String name,
+    int type, int id, String argumentsAsJson) {
+  // TODO.
+}
+
+@patch
+void _reportInstantEvent(
+    int start, String category, String name, String argumentsAsJson) {
+  // TODO.
+}
+
+@patch
+int _getNextAsyncId() {
+  return 0;
+}
+
+@patch
+void _reportTaskEvent(int start, int taskId, String phase, String category,
+    String name, String argumentsAsJson) {
+  // TODO.
+}
+
+@patch
+int _getServiceMajorVersion() {
+  return 0;
+}
+
+@patch
+int _getServiceMinorVersion() {
+  return 0;
+}
+
+@patch
+void _getServerInfo(SendPort sendPort) {
+  sendPort.send(null);
+}
+
+@patch
+void _webServerControl(SendPort sendPort, bool enable) {
+  sendPort.send(null);
+}
+
+@patch
+String _getIsolateIDFromSendPort(SendPort sendPort) {
+  return null;
+}
+
+@patch
+class UserTag {
+  @patch
+  factory UserTag(String label) = _FakeUserTag;
+
+  @patch
+  static UserTag get defaultTag => _FakeUserTag._defaultTag;
+}
+
+class _FakeUserTag implements UserTag {
+  static Map _instances = {};
+
+  _FakeUserTag.real(this.label);
+
+  factory _FakeUserTag(String label) {
+    // Canonicalize by name.
+    var existingTag = _instances[label];
+    if (existingTag != null) {
+      return existingTag;
+    }
+    // Throw an exception if we've reached the maximum number of user tags.
+    if (_instances.length == UserTag.MAX_USER_TAGS) {
+      throw UnsupportedError(
+          'UserTag instance limit (${UserTag.MAX_USER_TAGS}) reached.');
+    }
+    // Create a new instance and add it to the instance map.
+    var instance = _FakeUserTag.real(label);
+    _instances[label] = instance;
+    return instance;
+  }
+
+  final String label;
+
+  UserTag makeCurrent() {
+    var old = _currentTag;
+    _currentTag = this;
+    return old;
+  }
+
+  static final UserTag _defaultTag = _FakeUserTag('Default');
+}
+
+var _currentTag = _FakeUserTag._defaultTag;
+
+@patch
+UserTag getCurrentTag() => _currentTag;
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/patch/internal_patch.dart b/sdk_nnbd/lib/_internal/js_dev_runtime/patch/internal_patch.dart
new file mode 100644
index 0000000..5e850bb
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/patch/internal_patch.dart
@@ -0,0 +1,54 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:core' hide Symbol;
+import 'dart:core' as core show Symbol;
+import 'dart:_js_primitives' show printString;
+import 'dart:_js_helper' show patch;
+import 'dart:_interceptors' show JSArray;
+import 'dart:_foreign_helper' show JS;
+import 'dart:_runtime' as dart;
+
+@patch
+class Symbol implements core.Symbol {
+  @patch
+  const Symbol(String name) : this._name = name;
+
+  @patch
+  int get hashCode {
+    int hash = JS('int|Null', '#._hashCode', this);
+    if (hash != null) return hash;
+    const arbitraryPrime = 664597;
+    hash = 0x1fffffff & (arbitraryPrime * _name.hashCode);
+    JS('', '#._hashCode = #', this, hash);
+    return hash;
+  }
+
+  @patch
+  toString() => 'Symbol("$_name")';
+
+  @patch
+  static String computeUnmangledName(Symbol symbol) => symbol._name;
+}
+
+@patch
+void printToConsole(String line) {
+  printString('$line');
+}
+
+@patch
+List<E> makeListFixedLength<E>(List<E> growableList) {
+  JSArray.markFixedList(growableList);
+  return growableList;
+}
+
+@patch
+List<E> makeFixedListUnmodifiable<E>(List<E> fixedLengthList) {
+  JSArray.markUnmodifiableList(fixedLengthList);
+  return fixedLengthList;
+}
+
+@patch
+Object extractTypeArguments<T>(T instance, Function extract) =>
+    dart.extractTypeArguments<T>(instance, extract);
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/patch/io_patch.dart b/sdk_nnbd/lib/_internal/js_dev_runtime/patch/io_patch.dart
new file mode 100644
index 0000000..61d031a
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/patch/io_patch.dart
@@ -0,0 +1,690 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:_js_helper' show patch;
+import 'dart:async';
+import 'dart:convert';
+import 'dart:isolate' show SendPort;
+import 'dart:typed_data';
+
+@patch
+class _Directory {
+  @patch
+  static _current(_Namespace namespace) {
+    throw UnsupportedError("Directory._current");
+  }
+
+  @patch
+  static _setCurrent(_Namespace namespace, Uint8List rawPath) {
+    throw UnsupportedError("Directory_SetCurrent");
+  }
+
+  @patch
+  static _createTemp(_Namespace namespace, Uint8List rawPath) {
+    throw UnsupportedError("Directory._createTemp");
+  }
+
+  @patch
+  static String _systemTemp(_Namespace namespace) {
+    throw UnsupportedError("Directory._systemTemp");
+  }
+
+  @patch
+  static _exists(_Namespace namespace, Uint8List rawPath) {
+    throw UnsupportedError("Directory._exists");
+  }
+
+  @patch
+  static _create(_Namespace namespace, Uint8List rawPath) {
+    throw UnsupportedError("Directory._create");
+  }
+
+  @patch
+  static _deleteNative(
+      _Namespace namespace, Uint8List rawPath, bool recursive) {
+    throw UnsupportedError("Directory._deleteNative");
+  }
+
+  @patch
+  static _rename(_Namespace namespace, Uint8List rawPath, String newPath) {
+    throw UnsupportedError("Directory._rename");
+  }
+
+  @patch
+  static void _fillWithDirectoryListing(
+      _Namespace namespace,
+      List<FileSystemEntity> list,
+      Uint8List rawPath,
+      bool recursive,
+      bool followLinks) {
+    throw UnsupportedError("Directory._fillWithDirectoryListing");
+  }
+}
+
+@patch
+class _AsyncDirectoryListerOps {
+  @patch
+  factory _AsyncDirectoryListerOps(int pointer) {
+    throw UnsupportedError("Directory._list");
+  }
+}
+
+@patch
+class _EventHandler {
+  @patch
+  static void _sendData(Object sender, SendPort sendPort, int data) {
+    throw UnsupportedError("EventHandler._sendData");
+  }
+}
+
+@patch
+class FileStat {
+  @patch
+  static _statSync(_Namespace namespace, String path) {
+    throw UnsupportedError("FileStat.stat");
+  }
+}
+
+@patch
+class FileSystemEntity {
+  @patch
+  static _getTypeNative(
+      _Namespace namespace, Uint8List rawPath, bool followLinks) {
+    throw UnsupportedError("FileSystemEntity._getType");
+  }
+
+  @patch
+  static _identicalNative(_Namespace namespace, String path1, String path2) {
+    throw UnsupportedError("FileSystemEntity._identical");
+  }
+
+  @patch
+  static _resolveSymbolicLinks(_Namespace namespace, Uint8List rawPath) {
+    throw UnsupportedError("FileSystemEntity._resolveSymbolicLinks");
+  }
+}
+
+@patch
+class _File {
+  @patch
+  static _exists(_Namespace namespace, Uint8List rawPath) {
+    throw UnsupportedError("File._exists");
+  }
+
+  @patch
+  static _create(_Namespace namespace, Uint8List rawPath) {
+    throw UnsupportedError("File._create");
+  }
+
+  @patch
+  static _createLink(_Namespace namespace, Uint8List rawPath, String target) {
+    throw UnsupportedError("File._createLink");
+  }
+
+  @patch
+  static _linkTarget(_Namespace namespace, Uint8List rawPath) {
+    throw UnsupportedError("File._linkTarget");
+  }
+
+  @patch
+  static _deleteNative(_Namespace namespace, Uint8List rawPath) {
+    throw UnsupportedError("File._deleteNative");
+  }
+
+  @patch
+  static _deleteLinkNative(_Namespace namespace, Uint8List rawPath) {
+    throw UnsupportedError("File._deleteLinkNative");
+  }
+
+  @patch
+  static _rename(_Namespace namespace, Uint8List oldPath, String newPath) {
+    throw UnsupportedError("File._rename");
+  }
+
+  @patch
+  static _renameLink(_Namespace namespace, Uint8List oldPath, String newPath) {
+    throw UnsupportedError("File._renameLink");
+  }
+
+  @patch
+  static _copy(_Namespace namespace, Uint8List oldPath, String newPath) {
+    throw UnsupportedError("File._copy");
+  }
+
+  @patch
+  static _lengthFromPath(_Namespace namespace, Uint8List rawPath) {
+    throw UnsupportedError("File._lengthFromPath");
+  }
+
+  @patch
+  static _lastModified(_Namespace namespace, Uint8List rawPath) {
+    throw UnsupportedError("File._lastModified");
+  }
+
+  @patch
+  static _lastAccessed(_Namespace namespace, Uint8List rawPath) {
+    throw UnsupportedError("File._lastAccessed");
+  }
+
+  @patch
+  static _setLastModified(_Namespace namespace, Uint8List rawPath, int millis) {
+    throw UnsupportedError("File._setLastModified");
+  }
+
+  @patch
+  static _setLastAccessed(_Namespace namespace, Uint8List rawPath, int millis) {
+    throw UnsupportedError("File._setLastAccessed");
+  }
+
+  @patch
+  static _open(_Namespace namespace, Uint8List rawPath, int mode) {
+    throw UnsupportedError("File._open");
+  }
+
+  @patch
+  static int _openStdio(int fd) {
+    throw UnsupportedError("File._openStdio");
+  }
+}
+
+@patch
+class _Namespace {
+  @patch
+  static void _setupNamespace(var namespace) {
+    throw UnsupportedError("_Namespace");
+  }
+
+  @patch
+  static _Namespace get _namespace {
+    throw UnsupportedError("_Namespace");
+  }
+
+  @patch
+  static int get _namespacePointer {
+    throw UnsupportedError("_Namespace");
+  }
+}
+
+@patch
+class _RandomAccessFileOps {
+  @patch
+  factory _RandomAccessFileOps(int pointer) {
+    throw UnsupportedError("RandomAccessFile");
+  }
+}
+
+@patch
+class _IOCrypto {
+  @patch
+  static Uint8List getRandomBytes(int count) {
+    throw UnsupportedError("_IOCrypto.getRandomBytes");
+  }
+}
+
+@patch
+class _Platform {
+  @patch
+  static int _numberOfProcessors() {
+    throw UnsupportedError("Platform._numberOfProcessors");
+  }
+
+  @patch
+  static String _pathSeparator() {
+    throw UnsupportedError("Platform._pathSeparator");
+  }
+
+  @patch
+  static String _operatingSystem() {
+    throw UnsupportedError("Platform._operatingSystem");
+  }
+
+  @patch
+  static _operatingSystemVersion() {
+    throw UnsupportedError("Platform._operatingSystemVersion");
+  }
+
+  @patch
+  static _localHostname() {
+    throw UnsupportedError("Platform._localHostname");
+  }
+
+  @patch
+  static _executable() {
+    throw UnsupportedError("Platform._executable");
+  }
+
+  @patch
+  static _resolvedExecutable() {
+    throw UnsupportedError("Platform._resolvedExecutable");
+  }
+
+  @patch
+  static List<String> _executableArguments() {
+    throw UnsupportedError("Platform._executableArguments");
+  }
+
+  @patch
+  static String _packageRoot() {
+    throw UnsupportedError("Platform._packageRoot");
+  }
+
+  @patch
+  static String _packageConfig() {
+    throw UnsupportedError("Platform._packageConfig");
+  }
+
+  @patch
+  static _environment() {
+    throw UnsupportedError("Platform._environment");
+  }
+
+  @patch
+  static String _version() {
+    throw UnsupportedError("Platform._version");
+  }
+
+  @patch
+  static String _localeName() {
+    throw UnsupportedError("Platform._localeName");
+  }
+
+  @patch
+  static Uri _script() {
+    throw UnsupportedError("Platform._script");
+  }
+}
+
+@patch
+class _ProcessUtils {
+  @patch
+  static void _exit(int status) {
+    throw UnsupportedError("ProcessUtils._exit");
+  }
+
+  @patch
+  static void _setExitCode(int status) {
+    throw UnsupportedError("ProcessUtils._setExitCode");
+  }
+
+  @patch
+  static int _getExitCode() {
+    throw UnsupportedError("ProcessUtils._getExitCode");
+  }
+
+  @patch
+  static void _sleep(int millis) {
+    throw UnsupportedError("ProcessUtils._sleep");
+  }
+
+  @patch
+  static int _pid(Process process) {
+    throw UnsupportedError("ProcessUtils._pid");
+  }
+
+  @patch
+  static Stream<ProcessSignal> _watchSignal(ProcessSignal signal) {
+    throw UnsupportedError("ProcessUtils._watchSignal");
+  }
+}
+
+@patch
+class ProcessInfo {
+  @patch
+  static int get currentRss {
+    throw UnsupportedError("ProcessInfo.currentRss");
+  }
+
+  @patch
+  static int get maxRss {
+    throw UnsupportedError("ProcessInfo.maxRss");
+  }
+}
+
+@patch
+class Process {
+  @patch
+  static Future<Process> start(String executable, List<String> arguments,
+      {String workingDirectory,
+      Map<String, String> environment,
+      bool includeParentEnvironment = true,
+      bool runInShell = false,
+      ProcessStartMode mode = ProcessStartMode.normal}) {
+    throw UnsupportedError("Process.start");
+  }
+
+  @patch
+  static Future<ProcessResult> run(String executable, List<String> arguments,
+      {String workingDirectory,
+      Map<String, String> environment,
+      bool includeParentEnvironment = true,
+      bool runInShell = false,
+      Encoding stdoutEncoding = systemEncoding,
+      Encoding stderrEncoding = systemEncoding}) {
+    throw UnsupportedError("Process.run");
+  }
+
+  @patch
+  static ProcessResult runSync(String executable, List<String> arguments,
+      {String workingDirectory,
+      Map<String, String> environment,
+      bool includeParentEnvironment = true,
+      bool runInShell = false,
+      Encoding stdoutEncoding = systemEncoding,
+      Encoding stderrEncoding = systemEncoding}) {
+    throw UnsupportedError("Process.runSync");
+  }
+
+  @patch
+  static bool killPid(int pid, [ProcessSignal signal = ProcessSignal.sigterm]) {
+    throw UnsupportedError("Process.killPid");
+  }
+}
+
+@patch
+class InternetAddress {
+  @patch
+  static InternetAddress get LOOPBACK_IP_V4 {
+    throw UnsupportedError("InternetAddress.LOOPBACK_IP_V4");
+  }
+
+  @patch
+  static InternetAddress get LOOPBACK_IP_V6 {
+    throw UnsupportedError("InternetAddress.LOOPBACK_IP_V6");
+  }
+
+  @patch
+  static InternetAddress get ANY_IP_V4 {
+    throw UnsupportedError("InternetAddress.ANY_IP_V4");
+  }
+
+  @patch
+  static InternetAddress get ANY_IP_V6 {
+    throw UnsupportedError("InternetAddress.ANY_IP_V6");
+  }
+
+  @patch
+  factory InternetAddress(String address) {
+    throw UnsupportedError("InternetAddress");
+  }
+  @patch
+  static Future<List<InternetAddress>> lookup(String host,
+      {InternetAddressType type = InternetAddressType.any}) {
+    throw UnsupportedError("InternetAddress.lookup");
+  }
+
+  @patch
+  static InternetAddress _cloneWithNewHost(
+      InternetAddress address, String host) {
+    throw UnsupportedError("InternetAddress._cloneWithNewHost");
+  }
+}
+
+@patch
+class NetworkInterface {
+  @patch
+  static bool get listSupported {
+    throw UnsupportedError("NetworkInterface.listSupported");
+  }
+
+  @patch
+  static Future<List<NetworkInterface>> list(
+      {bool includeLoopback = false,
+      bool includeLinkLocal = false,
+      InternetAddressType type = InternetAddressType.any}) {
+    throw UnsupportedError("NetworkInterface.list");
+  }
+}
+
+@patch
+class RawServerSocket {
+  @patch
+  static Future<RawServerSocket> bind(address, int port,
+      {int backlog = 0, bool v6Only = false, bool shared = false}) {
+    throw UnsupportedError("RawServerSocket.bind");
+  }
+}
+
+@patch
+class ServerSocket {
+  @patch
+  static Future<ServerSocket> bind(address, int port,
+      {int backlog = 0, bool v6Only = false, bool shared = false}) {
+    throw UnsupportedError("ServerSocket.bind");
+  }
+}
+
+@patch
+class RawSocket {
+  @patch
+  static Future<RawSocket> connect(host, int port,
+      {sourceAddress, Duration timeout}) {
+    throw UnsupportedError("RawSocket constructor");
+  }
+
+  @patch
+  static Future<ConnectionTask<RawSocket>> startConnect(host, int port,
+      {sourceAddress}) {
+    throw UnsupportedError("RawSocket constructor");
+  }
+}
+
+@patch
+class Socket {
+  @patch
+  static Future<Socket> _connect(host, int port,
+      {sourceAddress, Duration timeout}) {
+    throw UnsupportedError("Socket constructor");
+  }
+
+  @patch
+  static Future<ConnectionTask<Socket>> _startConnect(host, int port,
+      {sourceAddress}) {
+    throw UnsupportedError("Socket constructor");
+  }
+}
+
+@patch
+class SecureSocket {
+  @patch
+  factory SecureSocket._(RawSecureSocket rawSocket) {
+    throw UnsupportedError("SecureSocket constructor");
+  }
+}
+
+@patch
+class RawSynchronousSocket {
+  @patch
+  static RawSynchronousSocket connectSync(host, int port) {
+    throw UnsupportedError("RawSynchronousSocket.connectSync");
+  }
+}
+
+@patch
+class RawSocketOption {
+  @patch
+  static int _getOptionValue(int key) {
+    throw UnsupportedError("RawSocketOption._getOptionValue");
+  }
+}
+
+@patch
+class SecurityContext {
+  @patch
+  factory SecurityContext({bool withTrustedRoots = false}) {
+    throw UnsupportedError("SecurityContext constructor");
+  }
+
+  @patch
+  static SecurityContext get defaultContext {
+    throw UnsupportedError("default SecurityContext getter");
+  }
+
+  @patch
+  static bool get alpnSupported {
+    throw UnsupportedError("SecurityContext alpnSupported getter");
+  }
+}
+
+@patch
+class X509Certificate {
+  @patch
+  factory X509Certificate._() {
+    throw UnsupportedError("X509Certificate constructor");
+  }
+}
+
+@patch
+class RawDatagramSocket {
+  @patch
+  static Future<RawDatagramSocket> bind(host, int port,
+      {bool reuseAddress = true, bool reusePort = false, int ttl = 1}) {
+    throw UnsupportedError("RawDatagramSocket.bind");
+  }
+}
+
+@patch
+class _SecureFilter {
+  @patch
+  factory _SecureFilter._() {
+    throw UnsupportedError("_SecureFilter._SecureFilter");
+  }
+}
+
+@patch
+class _StdIOUtils {
+  @patch
+  static Stdin _getStdioInputStream(int fd) {
+    throw UnsupportedError("StdIOUtils._getStdioInputStream");
+  }
+
+  @patch
+  static _getStdioOutputStream(int fd) {
+    throw UnsupportedError("StdIOUtils._getStdioOutputStream");
+  }
+
+  @patch
+  static int _socketType(Socket socket) {
+    throw UnsupportedError("StdIOUtils._socketType");
+  }
+
+  @patch
+  static _getStdioHandleType(int fd) {
+    throw UnsupportedError("StdIOUtils._getStdioHandleType");
+  }
+}
+
+@patch
+class _WindowsCodePageDecoder {
+  @patch
+  static String _decodeBytes(List<int> bytes) {
+    throw UnsupportedError("_WindowsCodePageDecoder._decodeBytes");
+  }
+}
+
+@patch
+class _WindowsCodePageEncoder {
+  @patch
+  static List<int> _encodeString(String string) {
+    throw UnsupportedError("_WindowsCodePageEncoder._encodeString");
+  }
+}
+
+@patch
+class RawZLibFilter {
+  @patch
+  static RawZLibFilter _makeZLibDeflateFilter(
+      bool gzip,
+      int level,
+      int windowBits,
+      int memLevel,
+      int strategy,
+      List<int> dictionary,
+      bool raw) {
+    throw UnsupportedError("_newZLibDeflateFilter");
+  }
+
+  @patch
+  static RawZLibFilter _makeZLibInflateFilter(
+      int windowBits, List<int> dictionary, bool raw) {
+    throw UnsupportedError("_newZLibInflateFilter");
+  }
+}
+
+@patch
+class Stdin {
+  @patch
+  int readByteSync() {
+    throw UnsupportedError("Stdin.readByteSync");
+  }
+
+  @patch
+  bool get echoMode {
+    throw UnsupportedError("Stdin.echoMode");
+  }
+
+  @patch
+  void set echoMode(bool enabled) {
+    throw UnsupportedError("Stdin.echoMode");
+  }
+
+  @patch
+  bool get lineMode {
+    throw UnsupportedError("Stdin.lineMode");
+  }
+
+  @patch
+  void set lineMode(bool enabled) {
+    throw UnsupportedError("Stdin.lineMode");
+  }
+
+  @patch
+  bool get supportsAnsiEscapes {
+    throw UnsupportedError("Stdin.supportsAnsiEscapes");
+  }
+}
+
+@patch
+class Stdout {
+  @patch
+  bool _hasTerminal(int fd) {
+    throw UnsupportedError("Stdout.hasTerminal");
+  }
+
+  @patch
+  int _terminalColumns(int fd) {
+    throw UnsupportedError("Stdout.terminalColumns");
+  }
+
+  @patch
+  int _terminalLines(int fd) {
+    throw UnsupportedError("Stdout.terminalLines");
+  }
+
+  @patch
+  static bool _supportsAnsiEscapes(int fd) {
+    throw UnsupportedError("Stdout.supportsAnsiEscapes");
+  }
+}
+
+@patch
+class _FileSystemWatcher {
+  @patch
+  static Stream<FileSystemEvent> _watch(
+      String path, int events, bool recursive) {
+    throw UnsupportedError("_FileSystemWatcher.watch");
+  }
+
+  @patch
+  static bool get isSupported {
+    throw UnsupportedError("_FileSystemWatcher.isSupported");
+  }
+}
+
+@patch
+class _IOService {
+  @patch
+  static Future _dispatch(int request, List data) {
+    throw UnsupportedError("_IOService._dispatch");
+  }
+}
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/patch/isolate_patch.dart b/sdk_nnbd/lib/_internal/js_dev_runtime/patch/isolate_patch.dart
new file mode 100644
index 0000000..f6aa73bb
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/patch/isolate_patch.dart
@@ -0,0 +1,125 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Patch file for the dart:isolate library.
+
+import 'dart:_js_helper' show patch, NoReifyGeneric;
+import 'dart:async';
+import "dart:typed_data" show TypedData;
+
+@patch
+class Isolate {
+  // `current` must be a getter, not just a final field,
+  // to match the external declaration.
+  @patch
+  static Isolate get current => _unsupported();
+
+  @patch
+  String get debugName => _unsupported();
+
+  @patch
+  static Future<Uri> get packageRoot => _unsupported();
+
+  @patch
+  static Future<Uri> get packageConfig => _unsupported();
+
+  @patch
+  static Future<Uri> resolvePackageUri(Uri packageUri) => _unsupported();
+
+  @patch
+  static Future<Isolate> spawn<T>(void entryPoint(T message), T message,
+          {bool paused = false,
+          bool errorsAreFatal,
+          SendPort onExit,
+          SendPort onError}) =>
+      _unsupported();
+
+  @patch
+  static Future<Isolate> spawnUri(Uri uri, List<String> args, var message,
+          {bool paused = false,
+          SendPort onExit,
+          SendPort onError,
+          bool errorsAreFatal,
+          bool checked,
+          Map<String, String> environment,
+          Uri packageRoot,
+          Uri packageConfig,
+          bool automaticPackageResolution = false}) =>
+      _unsupported();
+
+  @patch
+  void _pause(Capability resumeCapability) => _unsupported();
+
+  @patch
+  void resume(Capability resumeCapability) => _unsupported();
+
+  @patch
+  void addOnExitListener(SendPort responsePort, {Object response}) =>
+      _unsupported();
+
+  @patch
+  void removeOnExitListener(SendPort responsePort) => _unsupported();
+
+  @patch
+  void setErrorsFatal(bool errorsAreFatal) => _unsupported();
+
+  @patch
+  void kill({int priority = beforeNextEvent}) => _unsupported();
+  @patch
+  void ping(SendPort responsePort,
+          {Object response, int priority = immediate}) =>
+      _unsupported();
+
+  @patch
+  void addErrorListener(SendPort port) => _unsupported();
+
+  @patch
+  void removeErrorListener(SendPort port) => _unsupported();
+}
+
+/** Default factory for receive ports. */
+@patch
+class ReceivePort {
+  @patch
+  factory ReceivePort() = _ReceivePort;
+
+  @patch
+  factory ReceivePort.fromRawReceivePort(RawReceivePort rawPort) =>
+      _unsupported();
+}
+
+/// ReceivePort is supported by dev_compiler because async test packages
+/// (async_helper, unittest) create a dummy receive port to keep the Dart VM
+/// alive.
+class _ReceivePort extends Stream implements ReceivePort {
+  close() {}
+
+  get sendPort => _unsupported();
+
+  listen(onData, {onError, onDone, cancelOnError}) => _unsupported();
+}
+
+@patch
+class RawReceivePort {
+  @patch
+  factory RawReceivePort([void handler(event)]) => _unsupported();
+}
+
+@patch
+class Capability {
+  @patch
+  factory Capability() => _unsupported();
+}
+
+@patch
+abstract class TransferableTypedData {
+  @patch
+  factory TransferableTypedData.fromList(List<TypedData> list) =>
+      _unsupported();
+}
+
+@NoReifyGeneric()
+T _unsupported<T>() {
+  throw UnsupportedError('dart:isolate is not supported on dart4web');
+}
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/patch/math_patch.dart b/sdk_nnbd/lib/_internal/js_dev_runtime/patch/math_patch.dart
new file mode 100644
index 0000000..2ba4220
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/patch/math_patch.dart
@@ -0,0 +1,348 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Patch file for dart:math library.
+import 'dart:_foreign_helper' show JS;
+import 'dart:_js_helper' show patch, nullCheck, notNull;
+import 'dart:typed_data' show ByteData;
+
+@patch
+@notNull
+T min<T extends num>(@nullCheck T a, @nullCheck T b) =>
+    JS('-dynamic', r'Math.min(#, #)', a, b);
+
+@patch
+@notNull
+T max<T extends num>(@nullCheck T a, @nullCheck T b) =>
+    JS('-dynamic', r'Math.max(#, #)', a, b);
+
+@patch
+@notNull
+double sqrt(@nullCheck num x) => JS<num>('!', r'Math.sqrt(#)', x);
+
+@patch
+@notNull
+double sin(@nullCheck num radians) => JS<num>('!', r'Math.sin(#)', radians);
+
+@patch
+@notNull
+double cos(@nullCheck num radians) => JS<num>('!', r'Math.cos(#)', radians);
+
+@patch
+@notNull
+double tan(@nullCheck num radians) => JS<num>('!', r'Math.tan(#)', radians);
+
+@patch
+@notNull
+double acos(@nullCheck num x) => JS<num>('!', r'Math.acos(#)', x);
+
+@patch
+@notNull
+double asin(@nullCheck num x) => JS<num>('!', r'Math.asin(#)', x);
+
+@patch
+@notNull
+double atan(@nullCheck num x) => JS<num>('!', r'Math.atan(#)', x);
+
+@patch
+@notNull
+double atan2(@nullCheck num a, @nullCheck num b) =>
+    JS<num>('!', r'Math.atan2(#, #)', a, b);
+
+@patch
+@notNull
+double exp(@nullCheck num x) => JS<num>('!', r'Math.exp(#)', x);
+
+@patch
+@notNull
+double log(@nullCheck num x) => JS<num>('!', r'Math.log(#)', x);
+
+@patch
+@notNull
+num pow(@nullCheck num x, @nullCheck num exponent) =>
+    JS<num>('!', r'Math.pow(#, #)', x, exponent);
+
+const int _POW2_32 = 0x100000000;
+
+@patch
+class Random {
+  static Random _secureRandom;
+
+  @patch
+  factory Random([int seed]) =>
+      (seed == null) ? const _JSRandom() : _Random(seed);
+
+  @patch
+  factory Random.secure() => _secureRandom ??= _JSSecureRandom();
+}
+
+class _JSRandom implements Random {
+  // The Dart2JS implementation of Random doesn't use a seed.
+  const _JSRandom();
+
+  @notNull
+  int nextInt(int max) {
+    if (max <= 0 || max > _POW2_32) {
+      throw RangeError("max must be in range 0 < max ≤ 2^32, was $max");
+    }
+    return JS("int", "(Math.random() * #) >>> 0", max);
+  }
+
+  /**
+   * Generates a positive random floating point value uniformly distributed on
+   * the range from 0.0, inclusive, to 1.0, exclusive.
+   */
+  @notNull
+  double nextDouble() => JS("double", "Math.random()");
+
+  /**
+   * Generates a random boolean value.
+   */
+  @notNull
+  bool nextBool() => JS("bool", "Math.random() < 0.5");
+}
+
+class _Random implements Random {
+  // Constants used by the algorithm or masking.
+  static const double _POW2_53_D = 1.0 * (0x20000000000000);
+  static const double _POW2_27_D = 1.0 * (1 << 27);
+  static const int _MASK32 = 0xFFFFFFFF;
+
+  // State comprised of two unsigned 32 bit integers.
+  @notNull
+  int _lo = 0;
+  @notNull
+  int _hi = 0;
+
+  // Implements:
+  //   uint64_t hash = 0;
+  //   do {
+  //      hash = hash * 1037 ^ mix64((uint64_t)seed);
+  //      seed >>= 64;
+  //   } while (seed != 0 && seed != -1);  // Limits for pos/neg seed.
+  //   if (hash == 0) {
+  //     hash = 0x5A17;
+  //   }
+  //   _lo = hash & _MASK_32;
+  //   _hi = hash >> 32;
+  // and then does four _nextState calls to shuffle bits around.
+  _Random(int seed) {
+    int empty_seed = 0;
+    if (seed < 0) {
+      empty_seed = -1;
+    }
+    do {
+      int low = seed & _MASK32;
+      seed = (seed - low) ~/ _POW2_32;
+      int high = seed & _MASK32;
+      seed = (seed - high) ~/ _POW2_32;
+
+      // Thomas Wang's 64-bit mix function.
+      // http://www.concentric.net/~Ttwang/tech/inthash.htm
+      // via. http://web.archive.org/web/20071223173210/http://www.concentric.net/~Ttwang/tech/inthash.htm
+
+      // key = ~key + (key << 21);
+      int tmplow = low << 21;
+      int tmphigh = (high << 21) | (low >> 11);
+      tmplow = (~low & _MASK32) + tmplow;
+      low = tmplow & _MASK32;
+      high = (~high + tmphigh + ((tmplow - low) ~/ 0x100000000)) & _MASK32;
+      // key = key ^ (key >> 24).
+      tmphigh = high >> 24;
+      tmplow = (low >> 24) | (high << 8);
+      low ^= tmplow;
+      high ^= tmphigh;
+      // key = key * 265
+      tmplow = low * 265;
+      low = tmplow & _MASK32;
+      high = (high * 265 + (tmplow - low) ~/ 0x100000000) & _MASK32;
+      // key = key ^ (key >> 14);
+      tmphigh = high >> 14;
+      tmplow = (low >> 14) | (high << 18);
+      low ^= tmplow;
+      high ^= tmphigh;
+      // key = key * 21
+      tmplow = low * 21;
+      low = tmplow & _MASK32;
+      high = (high * 21 + (tmplow - low) ~/ 0x100000000) & _MASK32;
+      // key = key ^ (key >> 28).
+      tmphigh = high >> 28;
+      tmplow = (low >> 28) | (high << 4);
+      low ^= tmplow;
+      high ^= tmphigh;
+      // key = key + (key << 31);
+      tmplow = low << 31;
+      tmphigh = (high << 31) | (low >> 1);
+      tmplow += low;
+      low = tmplow & _MASK32;
+      high = (high + tmphigh + (tmplow - low) ~/ 0x100000000) & _MASK32;
+      // Mix end.
+
+      // seed = seed * 1037 ^ key;
+      tmplow = _lo * 1037;
+      _lo = tmplow & _MASK32;
+      _hi = (_hi * 1037 + (tmplow - _lo) ~/ 0x100000000) & _MASK32;
+      _lo ^= low;
+      _hi ^= high;
+    } while (seed != empty_seed);
+
+    if (_hi == 0 && _lo == 0) {
+      _lo = 0x5A17;
+    }
+    _nextState();
+    _nextState();
+    _nextState();
+    _nextState();
+  }
+
+  // The algorithm used here is Multiply with Carry (MWC) with a Base b = 2^32.
+  // http://en.wikipedia.org/wiki/Multiply-with-carry
+  // The constant A (0xFFFFDA61) is selected from "Numerical Recipes 3rd
+  // Edition" p.348 B1.
+
+  // Implements:
+  //   var state = (A * _lo + _hi) & _MASK_64;
+  //   _lo = state & _MASK_32;
+  //   _hi = state >> 32;
+  void _nextState() {
+    // Simulate (0xFFFFDA61 * lo + hi) without overflowing 53 bits.
+    int tmpHi = 0xFFFF0000 * _lo; // At most 48 bits of significant result.
+    int tmpHiLo = tmpHi & _MASK32; // Get the lower 32 bits.
+    int tmpHiHi = tmpHi - tmpHiLo; // And just the upper 32 bits.
+    int tmpLo = 0xDA61 * _lo;
+    int tmpLoLo = tmpLo & _MASK32;
+    int tmpLoHi = tmpLo - tmpLoLo;
+
+    int newLo = tmpLoLo + tmpHiLo + _hi;
+    _lo = newLo & _MASK32;
+    int newLoHi = newLo - _lo;
+    _hi = ((tmpLoHi + tmpHiHi + newLoHi) ~/ _POW2_32) & _MASK32;
+    assert(_lo < _POW2_32);
+    assert(_hi < _POW2_32);
+  }
+
+  @notNull
+  int nextInt(@nullCheck int max) {
+    if (max <= 0 || max > _POW2_32) {
+      throw RangeError("max must be in range 0 < max ≤ 2^32, was $max");
+    }
+    if ((max & (max - 1)) == 0) {
+      // Fast case for powers of two.
+      _nextState();
+      return _lo & (max - 1);
+    }
+
+    int rnd32;
+    int result;
+    do {
+      _nextState();
+      rnd32 = _lo;
+      result = rnd32.remainder(max); // % max;
+    } while ((rnd32 - result + max) >= _POW2_32);
+    return result;
+  }
+
+  @notNull
+  double nextDouble() {
+    _nextState();
+    int bits26 = _lo & ((1 << 26) - 1);
+    _nextState();
+    int bits27 = _lo & ((1 << 27) - 1);
+    return (bits26 * _POW2_27_D + bits27) / _POW2_53_D;
+  }
+
+  @notNull
+  bool nextBool() {
+    _nextState();
+    return (_lo & 1) == 0;
+  }
+}
+
+class _JSSecureRandom implements Random {
+  // Reused buffer with room enough for a double.
+  final _buffer = ByteData(8);
+
+  _JSSecureRandom() {
+    var crypto = JS("", "self.crypto");
+    if (crypto != null) {
+      var getRandomValues = JS("", "#.getRandomValues", crypto);
+      if (getRandomValues != null) {
+        return;
+      }
+    }
+    throw UnsupportedError(
+        "No source of cryptographically secure random numbers available.");
+  }
+
+  /// Fill _buffer from [start] to `start + length` with random bytes.
+  void _getRandomBytes(int start, int length) {
+    JS("void", "crypto.getRandomValues(#)",
+        _buffer.buffer.asUint8List(start, length));
+  }
+
+  @notNull
+  bool nextBool() {
+    _getRandomBytes(0, 1);
+    return _buffer.getUint8(0).isOdd;
+  }
+
+  @notNull
+  double nextDouble() {
+    _getRandomBytes(1, 7);
+    // Set top bits 12 of double to 0x3FF which is the exponent for numbers
+    // between 1.0 and 2.0.
+    _buffer.setUint8(0, 0x3F);
+    int highByte = _buffer.getUint8(1);
+    _buffer.setUint8(1, highByte | 0xF0);
+
+    // Buffer now contains double in the range [1.0-2.0)
+    // with 52 bits of entropy (not 53).
+    // To get 53 bits, we extract the 53rd bit from higthByte before
+    // overwriting it, and add that as a least significant bit.
+    // The getFloat64 method is big-endian as default.
+    double result = _buffer.getFloat64(0) - 1.0;
+    if (highByte & 0x10 != 0) {
+      result += 1.1102230246251565e-16; // pow(2,-53).
+    }
+    return result;
+  }
+
+  @notNull
+  int nextInt(@nullCheck int max) {
+    if (max <= 0 || max > _POW2_32) {
+      throw RangeError("max must be in range 0 < max ≤ 2^32, was $max");
+    }
+    int byteCount = 1;
+    if (max > 0xFF) {
+      byteCount++;
+      if (max > 0xFFFF) {
+        byteCount++;
+        if (max > 0xFFFFFF) {
+          byteCount++;
+        }
+      }
+    }
+    _buffer.setUint32(0, 0);
+    int start = 4 - byteCount;
+    int randomLimit = pow(256, byteCount);
+    while (true) {
+      _getRandomBytes(start, byteCount);
+      // The getUint32 method is big-endian as default.
+      int random = _buffer.getUint32(0);
+      if (max & (max - 1) == 0) {
+        // Max is power of 2.
+        return random & (max - 1);
+      }
+      int result = random.remainder(max);
+      // Ensure results have equal probability by rejecting values in the
+      // last range of k*max .. 256**byteCount.
+      // TODO: Consider picking a higher byte count if the last range is a
+      // significant portion of the entire range - a 50% chance of having
+      // to use two more bytes is no worse than always using one more.
+      if (random - result + max < randomLimit) {
+        return result;
+      }
+    }
+  }
+}
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/patch/mirrors_patch.dart b/sdk_nnbd/lib/_internal/js_dev_runtime/patch/mirrors_patch.dart
new file mode 100644
index 0000000..e3b015b
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/patch/mirrors_patch.dart
@@ -0,0 +1,82 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Patch library for dart:mirrors.
+
+import 'dart:_js_helper' show patch;
+import 'dart:_js_mirrors' as js;
+import 'dart:_runtime' as dart;
+
+@patch
+class MirrorSystem {
+  @patch
+  LibraryMirror findLibrary(Symbol libraryName) {
+    return libraries.values
+        .singleWhere((library) => library.simpleName == libraryName);
+  }
+
+  @patch
+  static String getName(Symbol symbol) => js.getName(symbol);
+
+  @patch
+  static Symbol getSymbol(String name, [LibraryMirror library]) {
+    return js.getSymbol(name, library);
+  }
+}
+
+@patch
+MirrorSystem currentMirrorSystem() => js.currentJsMirrorSystem;
+
+@patch
+InstanceMirror reflect(Object reflectee) => js.reflect(reflectee);
+
+@patch
+ClassMirror reflectClass(Type key) {
+  if (key is! Type || key == dynamic) {
+    throw ArgumentError('$key does not denote a class');
+  }
+  TypeMirror tm = reflectType(key);
+  if (tm is! ClassMirror) {
+    throw ArgumentError("$key does not denote a class");
+  }
+  return (tm as ClassMirror).originalDeclaration;
+}
+
+@patch
+TypeMirror reflectType(Type type, [List<Type> typeArguments]) {
+  if (typeArguments != null) {
+    type = _instantiateClass(type, typeArguments);
+  }
+  return js.reflectType(type);
+}
+
+/// Instantiates the generic class [type] with [typeArguments] and returns the
+/// result.
+///
+/// [type] may be instantiated with type arguments already. In that case, they
+/// are ignored. For example calling this function with `(List<int>, [String])`
+/// and `(List<dynamic>, [String])` will produce `List<String>` in both cases.
+Type _instantiateClass(Type type, List<Type> typeArguments) {
+  var unwrapped = dart.unwrapType(type);
+  var genericClass = dart.getGenericClass(unwrapped);
+  if (genericClass == null) {
+    throw ArgumentError('Type `$type` must be generic to apply '
+        'type arguments: `$typeArguments`.');
+  }
+
+  var typeArgsLenth = typeArguments.length;
+  var unwrappedArgs = List(typeArgsLenth);
+  for (int i = 0; i < typeArgsLenth; i++) {
+    unwrappedArgs[i] = dart.unwrapType(typeArguments[i]);
+  }
+  var typeFormals = dart.getGenericTypeFormals(genericClass);
+  if (typeFormals.length != typeArgsLenth) {
+    throw ArgumentError('Type `$type` has ${typeFormals.length} type '
+        'parameters, but $typeArgsLenth type arguments were '
+        'passed: `$typeArguments`.');
+  }
+  // TODO(jmesserly): this does not validate bounds, as we don't have them
+  // available at runtime. Consider storing them when dart:mirrors is enabled.
+  return dart.wrapType(dart.instantiateClass(genericClass, unwrappedArgs));
+}
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/patch/typed_data_patch.dart b/sdk_nnbd/lib/_internal/js_dev_runtime/patch/typed_data_patch.dart
new file mode 100644
index 0000000..f1e2dc1
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/patch/typed_data_patch.dart
@@ -0,0 +1,191 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:collection';
+import 'dart:_js_helper' show patch;
+import 'dart:_native_typed_data';
+
+@patch
+class ByteData {
+  @patch
+  factory ByteData(int length) = NativeByteData;
+}
+
+@patch
+class Float32List {
+  @patch
+  factory Float32List(int length) = NativeFloat32List;
+
+  @patch
+  factory Float32List.fromList(List<double> elements) =
+      NativeFloat32List.fromList;
+}
+
+@patch
+class Float64List {
+  @patch
+  factory Float64List(int length) = NativeFloat64List;
+
+  @patch
+  factory Float64List.fromList(List<double> elements) =
+      NativeFloat64List.fromList;
+}
+
+@patch
+class Int16List {
+  @patch
+  factory Int16List(int length) = NativeInt16List;
+
+  @patch
+  factory Int16List.fromList(List<int> elements) = NativeInt16List.fromList;
+}
+
+@patch
+class Int32List {
+  @patch
+  factory Int32List(int length) = NativeInt32List;
+
+  @patch
+  factory Int32List.fromList(List<int> elements) = NativeInt32List.fromList;
+}
+
+@patch
+class Int8List {
+  @patch
+  factory Int8List(int length) = NativeInt8List;
+
+  @patch
+  factory Int8List.fromList(List<int> elements) = NativeInt8List.fromList;
+}
+
+@patch
+class Uint32List {
+  @patch
+  factory Uint32List(int length) = NativeUint32List;
+
+  @patch
+  factory Uint32List.fromList(List<int> elements) = NativeUint32List.fromList;
+}
+
+@patch
+class Uint16List {
+  @patch
+  factory Uint16List(int length) = NativeUint16List;
+
+  @patch
+  factory Uint16List.fromList(List<int> elements) = NativeUint16List.fromList;
+}
+
+@patch
+class Uint8ClampedList {
+  @patch
+  factory Uint8ClampedList(int length) = NativeUint8ClampedList;
+
+  @patch
+  factory Uint8ClampedList.fromList(List<int> elements) =
+      NativeUint8ClampedList.fromList;
+}
+
+@patch
+class Uint8List {
+  @patch
+  factory Uint8List(int length) = NativeUint8List;
+
+  @patch
+  factory Uint8List.fromList(List<int> elements) = NativeUint8List.fromList;
+}
+
+@patch
+class Int64List {
+  @patch
+  factory Int64List(int length) {
+    throw UnsupportedError("Int64List not supported by dart2js.");
+  }
+
+  @patch
+  factory Int64List.fromList(List<int> elements) {
+    throw UnsupportedError("Int64List not supported by dart2js.");
+  }
+}
+
+@patch
+class Uint64List {
+  @patch
+  factory Uint64List(int length) {
+    throw UnsupportedError("Uint64List not supported by dart2js.");
+  }
+
+  @patch
+  factory Uint64List.fromList(List<int> elements) {
+    throw UnsupportedError("Uint64List not supported by dart2js.");
+  }
+}
+
+@patch
+class Int32x4List {
+  @patch
+  factory Int32x4List(int length) = NativeInt32x4List;
+
+  @patch
+  factory Int32x4List.fromList(List<Int32x4> elements) =
+      NativeInt32x4List.fromList;
+}
+
+@patch
+class Float32x4List {
+  @patch
+  factory Float32x4List(int length) = NativeFloat32x4List;
+
+  @patch
+  factory Float32x4List.fromList(List<Float32x4> elements) =
+      NativeFloat32x4List.fromList;
+}
+
+@patch
+class Float64x2List {
+  @patch
+  factory Float64x2List(int length) = NativeFloat64x2List;
+
+  @patch
+  factory Float64x2List.fromList(List<Float64x2> elements) =
+      NativeFloat64x2List.fromList;
+}
+
+@patch
+class Float32x4 {
+  @patch
+  factory Float32x4(double x, double y, double z, double w) = NativeFloat32x4;
+  @patch
+  factory Float32x4.splat(double v) = NativeFloat32x4.splat;
+  @patch
+  factory Float32x4.zero() = NativeFloat32x4.zero;
+  @patch
+  factory Float32x4.fromInt32x4Bits(Int32x4 x) =
+      NativeFloat32x4.fromInt32x4Bits;
+  @patch
+  factory Float32x4.fromFloat64x2(Float64x2 v) = NativeFloat32x4.fromFloat64x2;
+}
+
+@patch
+class Int32x4 {
+  @patch
+  factory Int32x4(int x, int y, int z, int w) = NativeInt32x4;
+  @patch
+  factory Int32x4.bool(bool x, bool y, bool z, bool w) = NativeInt32x4.bool;
+  @patch
+  factory Int32x4.fromFloat32x4Bits(Float32x4 x) =
+      NativeInt32x4.fromFloat32x4Bits;
+}
+
+@patch
+class Float64x2 {
+  @patch
+  factory Float64x2(double x, double y) = NativeFloat64x2;
+  @patch
+  factory Float64x2.splat(double v) = NativeFloat64x2.splat;
+  @patch
+  factory Float64x2.zero() = NativeFloat64x2.zero;
+  @patch
+  factory Float64x2.fromFloat32x4(Float32x4 v) = NativeFloat64x2.fromFloat32x4;
+}
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/private/annotations.dart b/sdk_nnbd/lib/_internal/js_dev_runtime/private/annotations.dart
new file mode 100644
index 0000000..bc437da
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/private/annotations.dart
@@ -0,0 +1,91 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart._js_helper;
+
+/// Tells the optimizing compiler to always inline the annotated method.
+class ForceInline {
+  const ForceInline();
+}
+
+class _NotNull {
+  const _NotNull();
+}
+
+/// Marks a variable or API to be non-nullable.
+/// ****CAUTION******
+/// This is currently unchecked, and hence should never be used
+/// on any public interface where user code could subclass, implement,
+/// or otherwise cause the contract to be violated.
+/// TODO(leafp): Consider adding static checking and exposing
+/// this to user code.
+const notNull = _NotNull();
+
+/// Marks a generic function or static method API to be not reified.
+/// ****CAUTION******
+/// This is currently unchecked, and hence should be used very carefully for
+/// internal SDK APIs only.
+class NoReifyGeneric {
+  const NoReifyGeneric();
+}
+
+/// Enables/disables reification of functions within the body of this function.
+/// ****CAUTION******
+/// This is currently unchecked, and hence should be used very carefully for
+/// internal SDK APIs only.
+class ReifyFunctionTypes {
+  final bool value;
+  const ReifyFunctionTypes(this.value);
+}
+
+class _NullCheck {
+  const _NullCheck();
+}
+
+/// Annotation indicating the parameter should default to the JavaScript
+/// undefined constant.
+const undefined = _Undefined();
+
+class _Undefined {
+  const _Undefined();
+}
+
+/// Tells the development compiler to check a variable for null at its
+/// declaration point, and then to assume that the variable is non-null
+/// from that point forward.
+/// ****CAUTION******
+/// This is currently unchecked, and hence will not catch re-assignments
+/// of a variable with null
+const nullCheck = _NullCheck();
+
+/// Tells the optimizing compiler that the annotated method cannot throw.
+/// Requires @NoInline() to function correctly.
+class NoThrows {
+  const NoThrows();
+}
+
+/// Tells the optimizing compiler to not inline the annotated method.
+class NoInline {
+  const NoInline();
+}
+
+/// Marks a class as native and defines its JavaScript name(s).
+class Native {
+  final String name;
+  const Native(this.name);
+}
+
+class JsPeerInterface {
+  /// The JavaScript type that we should match the API of.
+  /// Used for classes where Dart subclasses should be callable from JavaScript
+  /// matching the JavaScript calling conventions.
+  final String name;
+  const JsPeerInterface({this.name});
+}
+
+/// A Dart interface may only be implemented by a native JavaScript object
+/// if it is marked with this annotation.
+class SupportJsExtensionMethods {
+  const SupportJsExtensionMethods();
+}
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/private/custom_hash_map.dart b/sdk_nnbd/lib/_internal/js_dev_runtime/private/custom_hash_map.dart
new file mode 100644
index 0000000..c7c920d
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/private/custom_hash_map.dart
@@ -0,0 +1,197 @@
+// 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.
+
+part of dart._js_helper;
+
+class CustomKeyHashMap<K, V> extends CustomHashMap<K, V> {
+  final _Predicate<Object> _validKey;
+  CustomKeyHashMap(_Equality<K> equals, _Hasher<K> hashCode, this._validKey)
+      : super(equals, hashCode);
+
+  @override
+  @notNull
+  bool containsKey(Object key) {
+    if (!_validKey(key)) return false;
+    return super.containsKey(key);
+  }
+
+  @override
+  V operator [](Object key) {
+    if (!_validKey(key)) return null;
+    return super[key];
+  }
+
+  @override
+  V remove(Object key) {
+    if (!_validKey(key)) return null;
+    return super.remove(key);
+  }
+}
+
+class CustomHashMap<K, V> extends InternalMap<K, V> {
+  /// The backing store for this map.
+  @notNull
+  final _map = JS('', 'new Map()');
+
+  /// Our map used to map keys onto the canonical key that is stored in [_map].
+  @notNull
+  final _keyMap = JS('', 'new Map()');
+
+  // We track the number of modifications done to the key set of the
+  // hash map to be able to throw when the map is modified while being
+  // iterated over.
+  //
+  // Value cycles after 2^30 modifications so that modification counts are
+  // always unboxed (Smi) values. Modification detection will be missed if you
+  // make exactly some multiple of 2^30 modifications between advances of an
+  // iterator.
+  @notNull
+  int _modifications = 0;
+
+  final _Equality<K> _equals;
+  final _Hasher<K> _hashCode;
+
+  CustomHashMap(this._equals, this._hashCode);
+
+  @notNull
+  int get length => JS<int>('!', '#.size', _map);
+
+  @notNull
+  bool get isEmpty => JS<bool>('!', '#.size == 0', _map);
+
+  @notNull
+  bool get isNotEmpty => JS<bool>('!', '#.size != 0', _map);
+
+  Iterable<K> get keys => _JSMapIterable<K>(this, true);
+  Iterable<V> get values => _JSMapIterable<V>(this, false);
+
+  @notNull
+  bool containsKey(Object key) {
+    if (key is K) {
+      var buckets = JS('', '#.get(# & 0x3ffffff)', _keyMap, _hashCode(key));
+      if (buckets != null) {
+        var equals = _equals;
+        for (int i = 0, n = JS<int>('!', '#.length', buckets); i < n; i++) {
+          K k = JS('', '#[#]', buckets, i);
+          if (equals(k, key)) return true;
+        }
+      }
+    }
+    return false;
+  }
+
+  bool containsValue(Object value) {
+    for (var v in JS('', '#.values()', _map)) {
+      if (value == v) return true;
+    }
+    return false;
+  }
+
+  void addAll(Map<K, V> other) {
+    other.forEach((K key, V value) {
+      this[key] = value;
+    });
+  }
+
+  V operator [](Object key) {
+    if (key is K) {
+      var buckets = JS('', '#.get(# & 0x3ffffff)', _keyMap, _hashCode(key));
+      if (buckets != null) {
+        var equals = _equals;
+        for (int i = 0, n = JS<int>('!', '#.length', buckets); i < n; i++) {
+          K k = JS('', '#[#]', buckets, i);
+          if (equals(k, key)) {
+            V value = JS('', '#.get(#)', _map, k);
+            return value == null ? null : value; // coerce undefined to null.
+          }
+        }
+      }
+    }
+    return null;
+  }
+
+  void operator []=(K key, V value) {
+    var keyMap = _keyMap;
+    int hash = JS('!', '# & 0x3ffffff', _hashCode(key));
+    var buckets = JS('', '#.get(#)', keyMap, hash);
+    if (buckets == null) {
+      JS('', '#.set(#, [#])', keyMap, hash, key);
+    } else {
+      var equals = _equals;
+      for (int i = 0, n = JS<int>('!', '#.length', buckets);;) {
+        K k = JS('', '#[#]', buckets, i);
+        if (equals(k, key)) {
+          key = k;
+          break;
+        }
+        if (++i >= n) {
+          JS('', '#.push(#)', buckets, key);
+          break;
+        }
+      }
+    }
+    JS('', '#.set(#, #)', _map, key, value);
+    _modifications = (_modifications + 1) & 0x3ffffff;
+  }
+
+  V putIfAbsent(K key, V ifAbsent()) {
+    var keyMap = _keyMap;
+    int hash = JS('!', '# & 0x3ffffff', _hashCode(key));
+    var buckets = JS('', '#.get(#)', keyMap, hash);
+    if (buckets == null) {
+      JS('', '#.set(#, [#])', keyMap, hash, key);
+    } else {
+      var equals = _equals;
+      for (int i = 0, n = JS<int>('!', '#.length', buckets); i < n; i++) {
+        K k = JS('', '#[#]', buckets, i);
+        if (equals(k, key)) return JS('', '#.get(#)', _map, k);
+      }
+      JS('', '#.push(#)', buckets, key);
+    }
+    V value = ifAbsent();
+    if (value == null) value = null; // coerce undefined to null.
+    JS('', '#.set(#, #)', _map, key, value);
+    _modifications = (_modifications + 1) & 0x3ffffff;
+    return value;
+  }
+
+  V remove(Object key) {
+    if (key is K) {
+      int hash = JS('!', '# & 0x3ffffff', _hashCode(key));
+      var keyMap = _keyMap;
+      var buckets = JS('', '#.get(#)', keyMap, hash);
+      if (buckets == null) return null; // not found
+      var equals = _equals;
+      for (int i = 0, n = JS<int>('!', '#.length', buckets); i < n; i++) {
+        K k = JS('', '#[#]', buckets, i);
+        if (equals(k, key)) {
+          if (n == 1) {
+            JS('', '#.delete(#)', keyMap, hash);
+          } else {
+            JS('', '#.splice(#, 1)', buckets, i);
+          }
+          var map = _map;
+          V value = JS('', '#.get(#)', map, k);
+          JS('', '#.delete(#)', map, k);
+          _modifications = (_modifications + 1) & 0x3ffffff;
+          return value == null ? null : value; // coerce undefined to null.
+        }
+      }
+    }
+    return null;
+  }
+
+  void clear() {
+    var map = _map;
+    if (JS<int>('!', '#.size', map) > 0) {
+      JS('', '#.clear()', map);
+      JS('', '#.clear()', _keyMap);
+      _modifications = (_modifications + 1) & 0x3ffffff;
+    }
+  }
+}
+
+typedef bool _Equality<K>(K a, K b);
+typedef int _Hasher<K>(K object);
+typedef bool _Predicate<T>(T value);
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/private/ddc_runtime/classes.dart b/sdk_nnbd/lib/_internal/js_dev_runtime/private/ddc_runtime/classes.dart
new file mode 100644
index 0000000..8fe2fa6
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/private/ddc_runtime/classes.dart
@@ -0,0 +1,537 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// This library defines the operations that define and manipulate Dart
+/// classes.  Included in this are:
+///   - Generics
+///   - Class metadata
+///   - Extension methods
+///
+
+// TODO(leafp): Consider splitting some of this out.
+part of dart._runtime;
+
+/// Returns a new type that mixes members from base and the mixin.
+void applyMixin(to, from) {
+  JS('', '#[#] = #', to, _mixin, from);
+  var toProto = JS('', '#.prototype', to);
+  var fromProto = JS('', '#.prototype', from);
+  _copyMembers(toProto, fromProto);
+  _mixinSignature(to, from, _methodSig);
+  _mixinSignature(to, from, _fieldSig);
+  _mixinSignature(to, from, _getterSig);
+  _mixinSignature(to, from, _setterSig);
+  var mixinOnFn = JS('', '#[#]', from, mixinOn);
+  if (mixinOnFn != null) {
+    var proto = JS('', '#(#.__proto__).prototype', mixinOnFn, to);
+    _copyMembers(toProto, proto);
+  }
+}
+
+void _copyMembers(to, from) {
+  var names = getOwnNamesAndSymbols(from);
+  for (int i = 0, n = JS('!', '#.length', names); i < n; ++i) {
+    String name = JS('', '#[#]', names, i);
+    if (name == 'constructor') continue;
+    _copyMember(to, from, name);
+  }
+  return to;
+}
+
+void _copyMember(to, from, name) {
+  var desc = getOwnPropertyDescriptor(from, name);
+  if (JS('!', '# == Symbol.iterator', name)) {
+    // On native types, Symbol.iterator may already be present.
+    // TODO(jmesserly): investigate if we still need this.
+    // If so, we need to find a better solution.
+    // See https://github.com/dart-lang/sdk/issues/28324
+    var existing = getOwnPropertyDescriptor(to, name);
+    if (existing != null) {
+      if (JS('!', '#.writable', existing)) {
+        JS('', '#[#] = #.value', to, name, desc);
+      }
+      return;
+    }
+  }
+  var getter = JS('', '#.get', desc);
+  var setter = JS('', '#.set', desc);
+  if (getter != null) {
+    if (setter == null) {
+      var obj = JS(
+          '',
+          '#.set = { __proto__: #.__proto__, '
+              'set [#](x) { return super[#] = x; } }',
+          desc,
+          to,
+          name,
+          name);
+      JS('', '#.set = #.set', desc, getOwnPropertyDescriptor(obj, name));
+    }
+  } else if (setter != null) {
+    if (getter == null) {
+      var obj = JS(
+          '',
+          '#.get = { __proto__: #.__proto__, '
+              'get [#]() { return super[#]; } }',
+          desc,
+          to,
+          name,
+          name);
+      JS('', '#.get = #.get', desc, getOwnPropertyDescriptor(obj, name));
+    }
+  }
+  defineProperty(to, name, desc);
+}
+
+void _mixinSignature(to, from, kind) {
+  JS('', '#[#] = #', to, kind, () {
+    var baseMembers = _getMembers(JS('', '#.__proto__', to), kind);
+    var fromMembers = _getMembers(from, kind);
+    if (fromMembers == null) return baseMembers;
+    var toSignature = JS('', '{ __proto__: # }', baseMembers);
+    copyProperties(toSignature, fromMembers);
+    return toSignature;
+  });
+}
+
+final _mixin = JS('', 'Symbol("mixin")');
+
+getMixin(clazz) => JS('', 'Object.hasOwnProperty.call(#, #) ? #[#] : null',
+    clazz, _mixin, clazz, _mixin);
+
+final mixinOn = JS('', 'Symbol("mixinOn")');
+
+@JSExportName('implements')
+final implements_ = JS('', 'Symbol("implements")');
+
+List Function() getImplements(clazz) => JS(
+    '',
+    'Object.hasOwnProperty.call(#, #) ? #[#] : null',
+    clazz,
+    implements_,
+    clazz,
+    implements_);
+
+/// The Symbol for storing type arguments on a specialized generic type.
+final _typeArguments = JS('', 'Symbol("typeArguments")');
+
+final _originalDeclaration = JS('', 'Symbol("originalDeclaration")');
+
+final mixinNew = JS('', 'Symbol("dart.mixinNew")');
+
+/// Memoize a generic type constructor function.
+generic(typeConstructor, setBaseClass) => JS('', '''(() => {
+  let length = $typeConstructor.length;
+  if (length < 1) {
+    $throwInternalError('must have at least one generic type argument');
+  }
+  let resultMap = new Map();
+  // TODO(vsm): Rethink how to clear the resultMap on hot restart.
+  // A simple clear via:
+  //   _cacheMaps.push(resultMap);
+  // will break (a) we hoist type expressions in generated code and
+  // (b) we don't clear those type expressions in the presence of a
+  // hot restart.  Not clearing this map (as we're doing now) should
+  // not affect correctness, but can result in a memory leak across
+  // multiple restarts.
+  function makeGenericType(...args) {
+    if (args.length != length && args.length != 0) {
+      $throwInternalError('requires ' + length + ' or 0 type arguments');
+    }
+    while (args.length < length) args.push($dynamic);
+
+    let value = resultMap;
+    for (let i = 0; i < length; i++) {
+      let arg = args[i];
+      if (arg == null) {
+        $throwInternalError('type arguments should not be null: '
+                          + $typeConstructor);
+      }
+      let map = value;
+      value = map.get(arg);
+      if (value === void 0) {
+        if (i + 1 == length) {
+          value = $typeConstructor.apply(null, args);
+          // Save the type constructor and arguments for reflection.
+          if (value) {
+            value[$_typeArguments] = args;
+            value[$_originalDeclaration] = makeGenericType;
+          }
+          map.set(arg, value);
+          if ($setBaseClass != null) $setBaseClass.apply(null, args);
+        } else {
+          value = new Map();
+          map.set(arg, value);
+        }
+      }
+    }
+    return value;
+  }
+  makeGenericType[$_genericTypeCtor] = $typeConstructor;
+  return makeGenericType;
+})()''');
+
+getGenericClass(type) => safeGetOwnProperty(type, _originalDeclaration);
+
+List getGenericArgs(type) =>
+    JS('List', '#', safeGetOwnProperty(type, _typeArguments));
+
+List<TypeVariable> getGenericTypeFormals(genericClass) {
+  return _typeFormalsFromFunction(getGenericTypeCtor(genericClass));
+}
+
+Object instantiateClass(Object genericClass, List<Object> typeArgs) {
+  return JS('', '#.apply(null, #)', genericClass, typeArgs);
+}
+
+final _constructorSig = JS('', 'Symbol("sigCtor")');
+final _methodSig = JS('', 'Symbol("sigMethod")');
+final _fieldSig = JS('', 'Symbol("sigField")');
+final _getterSig = JS('', 'Symbol("sigGetter")');
+final _setterSig = JS('', 'Symbol("sigSetter")');
+final _staticMethodSig = JS('', 'Symbol("sigStaticMethod")');
+final _staticFieldSig = JS('', 'Symbol("sigStaticField")');
+final _staticGetterSig = JS('', 'Symbol("sigStaticGetter")');
+final _staticSetterSig = JS('', 'Symbol("sigStaticSetter")');
+final _genericTypeCtor = JS('', 'Symbol("genericType")');
+final _libraryUri = JS('', 'Symbol("libraryUri")');
+
+getConstructors(value) => _getMembers(value, _constructorSig);
+getMethods(value) => _getMembers(value, _methodSig);
+getFields(value) => _getMembers(value, _fieldSig);
+getGetters(value) => _getMembers(value, _getterSig);
+getSetters(value) => _getMembers(value, _setterSig);
+getStaticMethods(value) => _getMembers(value, _staticMethodSig);
+getStaticFields(value) => _getMembers(value, _staticFieldSig);
+getStaticGetters(value) => _getMembers(value, _staticGetterSig);
+getStaticSetters(value) => _getMembers(value, _staticSetterSig);
+
+getGenericTypeCtor(value) => JS('', '#[#]', value, _genericTypeCtor);
+
+/// Get the type of a method from an object using the stored signature
+getType(obj) =>
+    JS('', '# == null ? # : #.__proto__.constructor', obj, Object, obj);
+
+getLibraryUri(value) => JS('', '#[#]', value, _libraryUri);
+setLibraryUri(f, uri) => JS('', '#[#] = #', f, _libraryUri, uri);
+
+bool isJsInterop(obj) {
+  if (obj == null) return false;
+  if (JS('!', 'typeof # === "function"', obj)) {
+    // A function is a Dart function if it has runtime type information.
+    return JS('!', '#[#] == null', obj, _runtimeType);
+  }
+  // Primitive types are not JS interop types.
+  if (JS('!', 'typeof # !== "object"', obj)) return false;
+
+  // Extension types are not considered JS interop types.
+  // Note that it is still possible to call typed JS interop methods on
+  // extension types but the calls must be statically typed.
+  if (JS('!', '#[#] != null', obj, _extensionType)) return false;
+  return JS('!', '!($obj instanceof $Object)');
+}
+
+/// Get the type of a method from a type using the stored signature
+getMethodType(type, name) {
+  var m = getMethods(type);
+  return m != null ? JS('', '#[#]', m, name) : null;
+}
+
+/// Gets the type of the corresponding setter (this includes writable fields).
+getSetterType(type, name) {
+  var setters = getSetters(type);
+  if (setters != null) {
+    var type = JS('', '#[#]', setters, name);
+    if (type != null) {
+      if (JS('!', '# instanceof Array', type)) {
+        // The type has metadata attached.  Pull out just the type.
+        // TODO(jmesserly): remove when we remove mirrors
+        return JS('', '#[0]', type);
+      }
+      return type;
+    }
+  }
+  var fields = getFields(type);
+  if (fields != null) {
+    var fieldInfo = JS('', '#[#]', fields, name);
+    if (fieldInfo != null && JS<bool>('!', '!#.isFinal', fieldInfo)) {
+      return JS('', '#.type', fieldInfo);
+    }
+  }
+  return null;
+}
+
+finalFieldType(type, metadata) =>
+    JS('', '{ type: #, isFinal: true, metadata: # }', type, metadata);
+
+fieldType(type, metadata) =>
+    JS('', '{ type: #, isFinal: false, metadata: # }', type, metadata);
+
+/// Get the type of a constructor from a class using the stored signature
+/// If name is undefined, returns the type of the default constructor
+/// Returns undefined if the constructor is not found.
+classGetConstructorType(cls, name) {
+  if (cls == null) return null;
+  if (name == null) name = 'new';
+  var ctors = getConstructors(cls);
+  return ctors != null ? JS('', '#[#]', ctors, name) : null;
+}
+
+void setMethodSignature(f, sigF) => JS('', '#[#] = #', f, _methodSig, sigF);
+void setFieldSignature(f, sigF) => JS('', '#[#] = #', f, _fieldSig, sigF);
+void setGetterSignature(f, sigF) => JS('', '#[#] = #', f, _getterSig, sigF);
+void setSetterSignature(f, sigF) => JS('', '#[#] = #', f, _setterSig, sigF);
+
+// Set up the constructor signature field on the constructor
+void setConstructorSignature(f, sigF) =>
+    JS('', '#[#] = #', f, _constructorSig, sigF);
+
+// Set up the static signature field on the constructor
+void setStaticMethodSignature(f, sigF) =>
+    JS('', '#[#] = #', f, _staticMethodSig, sigF);
+
+void setStaticFieldSignature(f, sigF) =>
+    JS('', '#[#] = #', f, _staticFieldSig, sigF);
+
+void setStaticGetterSignature(f, sigF) =>
+    JS('', '#[#] = #', f, _staticGetterSig, sigF);
+
+void setStaticSetterSignature(f, sigF) =>
+    JS('', '#[#] = #', f, _staticSetterSig, sigF);
+
+_getMembers(type, kind) {
+  var sig = JS('', '#[#]', type, kind);
+  return JS<bool>('!', 'typeof # == "function"', sig)
+      ? JS('', '#[#] = #()', type, kind, sig)
+      : sig;
+}
+
+bool _hasMember(type, kind, name) {
+  var sig = _getMembers(type, kind);
+  return sig != null && JS<bool>('!', '# in #', name, sig);
+}
+
+bool hasMethod(type, name) => _hasMember(type, _methodSig, name);
+bool hasGetter(type, name) => _hasMember(type, _getterSig, name);
+bool hasSetter(type, name) => _hasMember(type, _setterSig, name);
+bool hasField(type, name) => _hasMember(type, _fieldSig, name);
+
+final _extensionType = JS('', 'Symbol("extensionType")');
+
+final dartx = JS('', 'dartx');
+
+/// Install properties in prototype-first order.  Properties / descriptors from
+/// more specific types should overwrite ones from less specific types.
+void _installProperties(jsProto, dartType, installedParent) {
+  if (JS('!', '# === #', dartType, Object)) {
+    _installPropertiesForObject(jsProto);
+    return;
+  }
+  // If the extension methods of the parent have been installed on the parent
+  // of [jsProto], the methods will be available via prototype inheritance.
+  var dartSupertype = JS('', '#.__proto__', dartType);
+  if (JS('!', '# !== #', dartSupertype, installedParent)) {
+    _installProperties(jsProto, dartSupertype, installedParent);
+  }
+
+  var dartProto = JS('', '#.prototype', dartType);
+  copyTheseProperties(jsProto, dartProto, getOwnPropertySymbols(dartProto));
+}
+
+void _installPropertiesForObject(jsProto) {
+  // core.Object members need to be copied from the non-symbol name to the
+  // symbol name.
+  var coreObjProto = JS('', '#.prototype', Object);
+  var names = getOwnPropertyNames(coreObjProto);
+  for (int i = 0, n = JS('!', '#.length', names); i < n; ++i) {
+    var name = JS<String>('!', '#[#]', names, i);
+    if (name == 'constructor') continue;
+    var desc = getOwnPropertyDescriptor(coreObjProto, name);
+    defineProperty(jsProto, JS('', '#.#', dartx, name), desc);
+  }
+}
+
+void _installPropertiesForGlobalObject(jsProto) {
+  _installPropertiesForObject(jsProto);
+  // Use JS toString for JS objects, rather than the Dart one.
+  JS('', '#[dartx.toString] = function() { return this.toString(); }', jsProto);
+  identityEquals ??= JS('', '#[dartx._equals]', jsProto);
+}
+
+final _extensionMap = JS('', 'new Map()');
+
+_applyExtension(jsType, dartExtType) {
+  // TODO(vsm): Not all registered js types are real.
+  if (jsType == null) return;
+  var jsProto = JS('', '#.prototype', jsType);
+  if (jsProto == null) return;
+
+  if (JS('!', '# === #', dartExtType, Object)) {
+    _installPropertiesForGlobalObject(jsProto);
+    return;
+  }
+
+  _installProperties(
+      jsProto, dartExtType, JS('', '#[#]', jsProto, _extensionType));
+
+  // Mark the JS type's instances so we can easily check for extensions.
+  if (JS('!', '# !== #', dartExtType, JSFunction)) {
+    JS('', '#[#] = #', jsProto, _extensionType, dartExtType);
+  }
+  JS('', '#[#] = #[#]', jsType, _methodSig, dartExtType, _methodSig);
+  JS('', '#[#] = #[#]', jsType, _fieldSig, dartExtType, _fieldSig);
+  JS('', '#[#] = #[#]', jsType, _getterSig, dartExtType, _getterSig);
+  JS('', '#[#] = #[#]', jsType, _setterSig, dartExtType, _setterSig);
+}
+
+/// Apply the previously registered extension to the type of [nativeObject].
+/// This is intended for types that are not available to polyfill at startup.
+applyExtension(name, nativeObject) {
+  var dartExtType = JS('', '#.get(#)', _extensionMap, name);
+  var jsType = JS('', '#.constructor', nativeObject);
+  _applyExtension(jsType, dartExtType);
+}
+
+/// Apply all registered extensions to a window.  This is intended for
+/// different frames, where registrations need to be reapplied.
+applyAllExtensions(global) {
+  JS('', '#.forEach((dartExtType, name) => #(#[name], dartExtType))',
+      _extensionMap, _applyExtension, global);
+}
+
+/// Copy symbols from the prototype of the source to destination.
+/// These are the only properties safe to copy onto an existing public
+/// JavaScript class.
+registerExtension(name, dartExtType) {
+  JS('', '#.set(#, #)', _extensionMap, name, dartExtType);
+  var jsType = JS('', '#[#]', global_, name);
+  _applyExtension(jsType, dartExtType);
+}
+
+///
+/// Mark a concrete type as implementing extension methods.
+/// For example: `class MyIter implements Iterable`.
+///
+/// This takes a list of names, which are the extension methods implemented.
+/// It will add a forwarder, so the extension method name redirects to the
+/// normal Dart method name. For example:
+///
+///     defineExtensionMembers(MyType, ['add', 'remove']);
+///
+/// Results in:
+///
+///     MyType.prototype[dartx.add] = MyType.prototype.add;
+///     MyType.prototype[dartx.remove] = MyType.prototype.remove;
+///
+// TODO(jmesserly): essentially this gives two names to the same method.
+// This benefit is roughly equivalent call performance either way, but the
+// cost is we need to call defineExtensionMembers any time a subclass
+// overrides one of these methods.
+defineExtensionMethods(type, Iterable memberNames) {
+  var proto = JS('', '#.prototype', type);
+  for (var name in memberNames) {
+    JS('', '#[dartx.#] = #[#]', proto, name, proto, name);
+  }
+}
+
+/// Like [defineExtensionMethods], but for getter/setter pairs.
+defineExtensionAccessors(type, Iterable memberNames) {
+  var proto = JS('', '#.prototype', type);
+  for (var name in memberNames) {
+    // Find the member. It should always exist (or we have a compiler bug).
+    var member;
+    var p = proto;
+    for (;; p = JS('', '#.__proto__', p)) {
+      member = getOwnPropertyDescriptor(p, name);
+      if (member != null) break;
+    }
+    defineProperty(proto, JS('', 'dartx[#]', name), member);
+  }
+}
+
+definePrimitiveHashCode(proto) {
+  defineProperty(proto, identityHashCode_,
+      getOwnPropertyDescriptor(proto, extensionSymbol('hashCode')));
+}
+
+/// Link the extension to the type it's extending as a base class.
+setBaseClass(derived, base) {
+  JS('', '#.prototype.__proto__ = #.prototype', derived, base);
+  // We use __proto__ to track the superclass hierarchy (see isSubtypeOf).
+  JS('', '#.__proto__ = #', derived, base);
+}
+
+/// Like [setBaseClass], but for generic extension types such as `JSArray<E>`.
+setExtensionBaseClass(dartType, jsType) {
+  // Mark the generic type as an extension type and link the prototype objects.
+  var dartProto = JS('', '#.prototype', dartType);
+  JS('', '#[#] = #', dartProto, _extensionType, dartType);
+  JS('', '#.__proto__ = #.prototype', dartProto, jsType);
+}
+
+/// Adds type test predicates to a class/interface type [ctor], using the
+/// provided [isClass] JS Symbol.
+///
+/// This will operate quickly for non-generic types, native extension types,
+/// as well as matching exact generic type arguments:
+///
+///     class C<T> {}
+///     class D extends C<int> {}
+///     main() { dynamic d = new D(); d as C<int>; }
+///
+addTypeTests(ctor, isClass) {
+  if (isClass == null) isClass = JS('', 'Symbol("_is_" + ctor.name)');
+  // TODO(jmesserly): since we know we're dealing with class/interface types,
+  // we can optimize this rather than go through the generic `dart.is` helpers.
+  JS('', '#.prototype[#] = true', ctor, isClass);
+  JS(
+      '',
+      '''#.is = function is_C(obj) {
+    return obj != null && (obj[#] || #(obj, this));
+  }''',
+      ctor,
+      isClass,
+      instanceOf);
+  JS(
+      '',
+      '''#.as = function as_C(obj) {
+    if (obj == null || obj[#]) return obj;
+    return #(obj, this, false);
+  }''',
+      ctor,
+      isClass,
+      cast);
+  JS(
+      '',
+      '''#._check = function check_C(obj) {
+    if (obj == null || obj[#]) return obj;
+    return #(obj, this, true);
+  }''',
+      ctor,
+      isClass,
+      cast);
+}
+
+// TODO(jmesserly): should we do this for all interfaces?
+
+/// The well known symbol for testing `is Future`
+final isFuture = JS('', 'Symbol("_is_Future")');
+
+/// The well known symbol for testing `is Iterable`
+final isIterable = JS('', 'Symbol("_is_Iterable")');
+
+/// The well known symbol for testing `is List`
+final isList = JS('', 'Symbol("_is_List")');
+
+/// The well known symbol for testing `is Map`
+final isMap = JS('', 'Symbol("_is_Map")');
+
+/// The well known symbol for testing `is Stream`
+final isStream = JS('', 'Symbol("_is_Stream")');
+
+/// The well known symbol for testing `is StreamSubscription`
+final isStreamSubscription = JS('', 'Symbol("_is_StreamSubscription")');
+
+/// The default `operator ==` that calls [identical].
+var identityEquals;
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/private/ddc_runtime/errors.dart b/sdk_nnbd/lib/_internal/js_dev_runtime/private/ddc_runtime/errors.dart
new file mode 100644
index 0000000..f875336
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/private/ddc_runtime/errors.dart
@@ -0,0 +1,271 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart._runtime;
+
+// We need to set these properties while the sdk is only partially initialized
+// so we cannot use regular Dart fields.
+// The default values for these properties are set when the global_ final field
+// in runtime.dart is initialized.
+
+argumentError(value) {
+  throw ArgumentError.value(value);
+}
+
+throwUnimplementedError(String message) {
+  throw UnimplementedError(message);
+}
+
+// TODO(nshahan) Cleanup embeded strings and extract file location at runtime
+// from the stacktrace.
+assertFailed(String message,
+    [String fileUri, int line, int column, String conditionSource]) {
+  throw AssertionErrorImpl(message, fileUri, line, column, conditionSource);
+}
+
+throwCyclicInitializationError([Object field]) {
+  throw CyclicInitializationError(field);
+}
+
+throwNullValueError() {
+  // TODO(vsm): Per spec, we should throw an NSM here.  Technically, we ought
+  // to thread through method info, but that uglifies the code and can't
+  // actually be queried ... it only affects how the error is printed.
+  throw NoSuchMethodError(
+      null, Symbol('<Unexpected Null Value>'), null, null, null);
+}
+
+castError(obj, expectedType, [@notNull bool isImplicit = false]) {
+  var actualType = getReifiedType(obj);
+  var message = _castErrorMessage(actualType, expectedType);
+  var error = isImplicit ? TypeErrorImpl(message) : CastErrorImpl(message);
+  throw error;
+}
+
+String _castErrorMessage(from, to) {
+  // If both types are generic classes, see if we can infer generic type
+  // arguments for `from` that would allow the subtype relation to work.
+  var fromClass = getGenericClass(from);
+  if (fromClass != null) {
+    var fromTypeFormals = getGenericTypeFormals(fromClass);
+    var fromType = instantiateClass(fromClass, fromTypeFormals);
+    var inferrer = _TypeInferrer(fromTypeFormals);
+    if (inferrer.trySubtypeMatch(fromType, to)) {
+      var inferredTypes = inferrer.getInferredTypes();
+      if (inferredTypes != null) {
+        var inferred = instantiateClass(fromClass, inferredTypes);
+        return "Type '${typeName(from)}' should be '${typeName(inferred)}' "
+            "to implement expected type '${typeName(to)}'.";
+      }
+    }
+  }
+  return "Expected a value of type '${typeName(to)}', "
+      "but got one of type '${typeName(from)}'";
+}
+
+/// The symbol that references the thrown Dart Object (typically but not
+/// necessarily an [Error] or [Exception]), used by the [exception] function.
+final Object _thrownValue = JS('', 'Symbol("_thrownValue")');
+
+/// For a Dart [Error], this provides access to the JS Error object that
+/// contains the stack trace if the error was thrown.
+final Object _jsError = JS('', 'Symbol("_jsError")');
+
+/// Gets the thrown Dart Object from an [error] caught by a JS catch.
+///
+/// If the throw originated in Dart, the result will typically be an [Error]
+/// or [Exception], but it could be any Dart object.
+///
+/// If the throw originated in JavaScript, then there is not a corresponding
+/// Dart value, so we just return the error object.
+Object getThrown(Object error) {
+  if (error != null) {
+    // Get the Dart thrown value, if any.
+    var value = JS('', '#[#]', error, _thrownValue);
+    if (value != null) return value;
+  }
+  // Otherwise return the original object.
+  return error;
+}
+
+final _stackTrace = JS('', 'Symbol("_stackTrace")');
+
+/// Returns the stack trace from an [error] caught by a JS catch.
+///
+/// If the throw originated in Dart, we should always have JS Error
+/// (see [throw_]) so we can create a Dart [StackTrace] from that (or return a
+/// previously created instance).
+///
+/// If the throw originated in JavaScript and was an `Error`, then we can get
+/// the corresponding stack trace the same way we do for Dart throws. If the
+/// throw object was not an Error, then we don't have a JS trace, so we create
+/// one here.
+StackTrace stackTrace(Object error) {
+  if (JS<bool>('!', '!(# instanceof Error)', error)) {
+    // We caught something that isn't a JS Error.
+    //
+    // We should only hit this path when a non-Error was thrown from JS. In
+    // case, there is no stack trace available, so create one here.
+    return _StackTrace.missing(error);
+  }
+
+  // If we've already created the Dart stack trace object, return it.
+  StackTrace trace = JS('', '#[#]', error, _stackTrace);
+  if (trace != null) return trace;
+
+  // Otherwise create the Dart stack trace (by parsing the JS stack), and
+  // cache it so we don't repeat the parsing/allocation.
+  return JS('', '#[#] = #', error, _stackTrace, _StackTrace(error));
+}
+
+StackTrace stackTraceForError(Error error) {
+  return stackTrace(JS('', '#[#]', error, _jsError));
+}
+
+/// Implements `rethrow` of [error], allowing rethrow in an expression context.
+///
+/// Note: [error] must be the raw JS error caught in the JS catch, not the
+/// unwrapped value returned by [getThrown].
+@JSExportName('rethrow')
+void rethrow_(Object error) {
+  JS('', 'throw #', error);
+}
+
+/// Subclass of JS `Error` that wraps a thrown Dart object, and evaluates the
+/// message lazily by calling `toString()` on the wrapped Dart object.
+///
+/// Also creates a pointer from the thrown Dart object to the JS Error
+/// (via [_jsError]). This is used to implement [Error.stackTrace], but also
+/// provides a way to recover the stack trace if we lose track of it.
+/// [Error] requires preserving the original stack trace if an error is
+/// rethrown, so we only update the pointer if it wasn't already set.
+///
+/// TODO(jmesserly): Dart Errors should simply be JS Errors.
+final Object DartError = JS(
+    '!',
+    '''class DartError extends Error {
+      constructor(error) {
+        super();
+        if (error == null) error = #;
+        this[#] = error;
+        if (error != null && typeof error == "object" && error[#] == null) {
+          error[#] = this;
+        }
+      }
+      get message() {
+        return #(this[#]);
+      }
+    }''',
+    NullThrownError(),
+    _thrownValue,
+    _jsError,
+    _jsError,
+    _toString,
+    _thrownValue);
+
+/// Subclass of [DartError] for cases where we're rethrowing with a different,
+/// original Dart StackTrace object.
+///
+/// This includes the original stack trace in the JS Error message so it doesn't
+/// get lost if the exception reaches JS.
+final Object RethrownDartError = JS(
+    '!',
+    '''class RethrownDartError extends # {
+      constructor(error, stackTrace) {
+        super(error);
+        this[#] = stackTrace;
+      }
+      get message() {
+        return super.message + "\\n    " + #(this[#]) + "\\n";
+      }
+    }''',
+    DartError,
+    _stackTrace,
+    _toString,
+    _stackTrace);
+
+/// Implements `throw` of [exception], allowing for throw in an expression
+/// context, and capturing the current stack trace.
+@JSExportName('throw')
+void throw_(Object exception) {
+  /// Wrap the object so we capture a new stack trace, and so it will print
+  /// nicely from JS, as if it were a normal JS error.
+  JS('', 'throw new #(#)', DartError, exception);
+}
+
+/// Returns a JS error for throwing the Dart [exception] Object and using the
+/// provided stack [trace].
+///
+/// This is used by dart:async to rethrow unhandled errors in [Zone]s, and by
+/// `async`/`async*` to rethrow errors from Futures/Streams into the generator
+/// (so a try/catch in there can catch it).
+///
+/// If the exception and trace originated from the same Dart throw, then we can
+/// simply return the original JS Error. Otherwise, we have to create a new JS
+/// Error. The new error will have the correct Dart trace, but it will not have
+/// the correct JS stack trace (visible if JavaScript ends up handling it). To
+/// fix that, we use [RethrownDartError] to preserve the Dart trace and make
+/// sure it gets displayed in the JS error message.
+///
+/// If the stack trace is null, this will preserve the original stack trace
+/// on the exception, if available, otherwise it will capture the current stack
+/// trace.
+Object createErrorWithStack(Object exception, StackTrace trace) {
+  if (trace == null) {
+    var error = JS('', '#[#]', exception, _jsError);
+    return error != null ? error : JS('', 'new #(#)', DartError, exception);
+  }
+  if (trace is _StackTrace) {
+    /// Optimization: if this stack trace and exception already have a matching
+    /// Error, we can just rethrow it.
+    var originalError = trace._jsError;
+    if (identical(exception, getThrown(originalError))) {
+      return originalError;
+    }
+  }
+  return JS('', 'new #(#, #)', RethrownDartError, exception, trace);
+}
+
+// This is a utility function: it is only intended to be called from dev
+// tools.
+void stackPrint(Object error) {
+  JS('', 'console.log(#.stack ? #.stack : "No stack trace for: " + #)', error,
+      error, error);
+}
+
+class _StackTrace implements StackTrace {
+  final Object _jsError;
+  final Object _jsObjectMissingTrace;
+  String _trace;
+
+  _StackTrace(this._jsError) : _jsObjectMissingTrace = null;
+
+  _StackTrace.missing(Object caughtObj)
+      : _jsObjectMissingTrace = caughtObj != null ? caughtObj : 'null',
+        _jsError = JS('', 'Error()');
+
+  String toString() {
+    if (_trace != null) return _trace;
+
+    var e = _jsError;
+    String trace = '';
+    if (e != null && JS<bool>('!', 'typeof # === "object"', e)) {
+      trace = e is NativeError ? e.dartStack() : JS<String>('', '#.stack', e);
+      if (trace != null && stackTraceMapper != null) {
+        trace = stackTraceMapper(trace);
+      }
+    }
+    if (trace.isEmpty || _jsObjectMissingTrace != null) {
+      String jsToString;
+      try {
+        jsToString = JS('', '"" + #', _jsObjectMissingTrace);
+      } catch (_) {
+        jsToString = '<error converting JS object to string>';
+      }
+      trace = 'Non-error `$jsToString` thrown by JS does not have stack trace.'
+          '\nCaught in Dart at:\n\n$trace';
+    }
+    return _trace = trace;
+  }
+}
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/private/ddc_runtime/operations.dart b/sdk_nnbd/lib/_internal/js_dev_runtime/private/ddc_runtime/operations.dart
new file mode 100644
index 0000000..e388cd6
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/private/ddc_runtime/operations.dart
@@ -0,0 +1,725 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// This library defines runtime operations on objects used by the code
+/// generator.
+part of dart._runtime;
+
+// TODO(jmesserly): remove this in favor of _Invocation.
+class InvocationImpl extends Invocation {
+  final Symbol memberName;
+  final List positionalArguments;
+  final Map<Symbol, dynamic> namedArguments;
+  final List<Type> typeArguments;
+  final bool isMethod;
+  final bool isGetter;
+  final bool isSetter;
+  final String failureMessage;
+
+  InvocationImpl(memberName, List<Object> positionalArguments,
+      {namedArguments,
+      List typeArguments,
+      this.isMethod = false,
+      this.isGetter = false,
+      this.isSetter = false,
+      this.failureMessage = 'method not found'})
+      : memberName =
+            isSetter ? _setterSymbol(memberName) : _dartSymbol(memberName),
+        positionalArguments = List.unmodifiable(positionalArguments),
+        namedArguments = _namedArgsToSymbols(namedArguments),
+        typeArguments = typeArguments == null
+            ? const []
+            : List.unmodifiable(typeArguments.map(wrapType));
+
+  static Map<Symbol, dynamic> _namedArgsToSymbols(namedArgs) {
+    if (namedArgs == null) return const {};
+    return Map.unmodifiable(Map.fromIterable(getOwnPropertyNames(namedArgs),
+        key: _dartSymbol, value: (k) => JS('', '#[#]', namedArgs, k)));
+  }
+}
+
+/// Given an object and a method name, tear off the method.
+/// Sets the runtime type of the torn off method appropriately,
+/// and also binds the object.
+///
+/// If the optional `f` argument is passed in, it will be used as the method.
+/// This supports cases like `super.foo` where we need to tear off the method
+/// from the superclass, not from the `obj` directly.
+// TODO(leafp): Consider caching the tearoff on the object?
+bind(obj, name, method) {
+  if (obj == null) obj = jsNull;
+  if (method == null) method = JS('', '#[#]', obj, name);
+  var f = JS('', '#.bind(#)', method, obj);
+  // TODO(jmesserly): canonicalize tearoffs.
+  JS('', '#._boundObject = #', f, obj);
+  JS('', '#._boundMethod = #', f, method);
+  JS('', '#[#] = #', f, _runtimeType, getMethodType(getType(obj), name));
+  return f;
+}
+
+/// Binds the `call` method of an interface type, handling null.
+///
+/// Essentially this works like `obj?.call`. It also handles the needs of
+/// [dsend]/[dcall], returning `null` if no method was found with the given
+/// canonical member [name].
+///
+/// [name] is typically `"call"` but it could be the [extensionSymbol] for
+/// `call`, if we define it on a native type, and [obj] is known statially to be
+/// a native type/interface with `call`.
+bindCall(obj, name) {
+  if (obj == null) return null;
+  var ftype = getMethodType(getType(obj), name);
+  if (ftype == null) return null;
+  var method = JS('', '#[#]', obj, name);
+  var f = JS('', '#.bind(#)', method, obj);
+  // TODO(jmesserly): canonicalize tearoffs.
+  JS('', '#._boundObject = #', f, obj);
+  JS('', '#._boundMethod = #', f, method);
+  JS('', '#[#] = #', f, _runtimeType, ftype);
+  return f;
+}
+
+/// Instantiate a generic method.
+///
+/// We need to apply the type arguments both to the function, as well as its
+/// associated function type.
+gbind(f, @rest List typeArgs) {
+  GenericFunctionType type = JS('!', '#[#]', f, _runtimeType);
+  type.checkBounds(typeArgs);
+  // Create a JS wrapper function that will also pass the type arguments, and
+  // tag it with the instantiated function type.
+  var result =
+      JS('', '(...args) => #.apply(null, #.concat(args))', f, typeArgs);
+  return fn(result, type.instantiate(typeArgs));
+}
+
+dloadRepl(obj, field) => dload(obj, replNameLookup(obj, field), false);
+
+// Warning: dload, dput, and dsend assume they are never called on methods
+// implemented by the Object base class as those methods can always be
+// statically resolved.
+dload(obj, field, [@undefined mirrors]) {
+  if (JS('!', 'typeof # == "function" && # == "call"', obj, field)) {
+    return obj;
+  }
+  var f = _canonicalMember(obj, field);
+
+  trackCall(obj);
+  if (f != null) {
+    var type = getType(obj);
+
+    if (hasField(type, f) || hasGetter(type, f)) return JS('', '#[#]', obj, f);
+    if (hasMethod(type, f)) return bind(obj, f, null);
+
+    // Always allow for JS interop objects.
+    if (!JS<bool>('!', '#', mirrors) && isJsInterop(obj)) {
+      return JS('', '#[#]', obj, f);
+    }
+  }
+  return noSuchMethod(obj, InvocationImpl(field, JS('', '[]'), isGetter: true));
+}
+
+// Version of dload that matches legacy mirrors behavior for JS types.
+dloadMirror(obj, field) => dload(obj, field, true);
+
+_stripGenericArguments(type) {
+  var genericClass = getGenericClass(type);
+  if (genericClass != null) return JS('', '#()', genericClass);
+  return type;
+}
+
+// Version of dput that matches legacy Dart 1 type check rules and mirrors
+// behavior for JS types.
+// TODO(jacobr): remove the type checking rules workaround when mirrors based
+// PageLoader code can generate the correct reified generic types.
+dputMirror(obj, field, value) => dput(obj, field, value, true);
+
+dputRepl(obj, field, value) =>
+    dput(obj, replNameLookup(obj, field), value, false);
+
+dput(obj, field, value, [@undefined mirrors]) {
+  var f = _canonicalMember(obj, field);
+  trackCall(obj);
+  if (f != null) {
+    var setterType = getSetterType(getType(obj), f);
+    if (setterType != null) {
+      if (JS('!', '#', mirrors))
+        setterType = _stripGenericArguments(setterType);
+      return JS('', '#[#] = #._check(#)', obj, f, setterType, value);
+    }
+    // Always allow for JS interop objects.
+    if (!JS<bool>('!', '#', mirrors) && isJsInterop(obj)) {
+      return JS('', '#[#] = #', obj, f, value);
+    }
+  }
+  noSuchMethod(
+      obj, InvocationImpl(field, JS('', '[#]', value), isSetter: true));
+  return value;
+}
+
+/// Returns an error message if function of a given [type] can't be applied to
+/// [actuals] and [namedActuals].
+///
+/// Returns `null` if all checks pass.
+String _argumentErrors(FunctionType type, List actuals, namedActuals) {
+  // Check for too few required arguments.
+  int actualsCount = JS('!', '#.length', actuals);
+  var required = type.args;
+  int requiredCount = JS('!', '#.length', required);
+  if (actualsCount < requiredCount) {
+    return 'Dynamic call with too few arguments. '
+        'Expected: $requiredCount Actual: $actualsCount';
+  }
+
+  // Check for too many postional arguments.
+  var extras = actualsCount - requiredCount;
+  var optionals = type.optionals;
+  if (extras > JS<int>('!', '#.length', optionals)) {
+    return 'Dynamic call with too many arguments. '
+        'Expected: $requiredCount Actual: $actualsCount';
+  }
+
+  // Check if we have invalid named arguments.
+  Iterable names;
+  var named = type.named;
+  if (namedActuals != null) {
+    names = getOwnPropertyNames(namedActuals);
+    for (var name in names) {
+      if (!JS('!', '#.hasOwnProperty(#)', named, name)) {
+        return "Dynamic call with unexpected named argument '$name'.";
+      }
+    }
+  }
+  // Now that we know the signature matches, we can perform type checks.
+  for (var i = 0; i < requiredCount; ++i) {
+    JS('', '#[#]._check(#[#])', required, i, actuals, i);
+  }
+  for (var i = 0; i < extras; ++i) {
+    JS('', '#[#]._check(#[#])', optionals, i, actuals, i + requiredCount);
+  }
+  if (names != null) {
+    for (var name in names) {
+      JS('', '#[#]._check(#[#])', named, name, namedActuals, name);
+    }
+  }
+  return null;
+}
+
+_toSymbolName(symbol) => JS('', '''(() => {
+        let str = $symbol.toString();
+        // Strip leading 'Symbol(' and trailing ')'
+        return str.substring(7, str.length-1);
+    })()''');
+
+_toDisplayName(name) => JS('', '''(() => {
+      // Names starting with _ are escaped names used to disambiguate Dart and
+      // JS names.
+      if ($name[0] === '_') {
+        // Inverse of
+        switch($name) {
+          case '_get':
+            return '[]';
+          case '_set':
+            return '[]=';
+          case '_negate':
+            return 'unary-';
+          case '_constructor':
+          case '_prototype':
+            return $name.substring(1);
+        }
+      }
+      return $name;
+  })()''');
+
+Symbol _dartSymbol(name) {
+  return (JS<bool>('!', 'typeof # === "symbol"', name))
+      ? JS('Symbol', '#(new #.new(#, #))', const_, PrivateSymbol,
+          _toSymbolName(name), name)
+      : JS('Symbol', '#(new #.new(#))', const_, internal.Symbol,
+          _toDisplayName(name));
+}
+
+Symbol _setterSymbol(name) {
+  return (JS<bool>('!', 'typeof # === "symbol"', name))
+      ? JS('Symbol', '#(new #.new(# + "=", #))', const_, PrivateSymbol,
+          _toSymbolName(name), name)
+      : JS('Symbol', '#(new #.new(# + "="))', const_, internal.Symbol,
+          _toDisplayName(name));
+}
+
+_checkAndCall(f, ftype, obj, typeArgs, args, named, displayName) =>
+    JS('', '''(() => {
+  $trackCall($obj);
+
+  let originalTarget = obj === void 0 ? f : obj;
+
+  function callNSM(errorMessage) {
+    return $noSuchMethod(originalTarget, new $InvocationImpl.new(
+        $displayName, $args, {
+          namedArguments: $named,
+          typeArguments: $typeArgs,
+          isMethod: true,
+          failureMessage: errorMessage
+        }));
+  }
+  if ($f == null) return callNSM('Dynamic call of null.');
+  if (!($f instanceof Function)) {
+    // We're not a function (and hence not a method either)
+    // Grab the `call` method if it's not a function.
+    if ($f != null) {
+      // Getting the member succeeded, so update the originalTarget.
+      // (we're now trying `call()` on `f`, so we want to call its nSM rather
+      // than the original target's nSM).
+      originalTarget = f;
+      $f = ${bindCall(f, _canonicalMember(f, 'call'))};
+      $ftype = null;
+      $displayName = "call";
+    }
+    if ($f == null) return callNSM(
+        "Dynamic call of object has no instance method 'call'.");
+  }
+  // If f is a function, but not a method (no method type)
+  // then it should have been a function valued field, so
+  // get the type from the function.
+  if ($ftype == null) $ftype = $f[$_runtimeType];
+
+  if ($ftype == null) {
+    // TODO(leafp): Allow JS objects to go through?
+    if ($typeArgs != null) {
+      // TODO(jmesserly): is there a sensible way to handle these?
+      $throwTypeError('call to JS object `' + $obj +
+          '` with type arguments <' + $typeArgs + '> is not supported.');
+    }
+
+    if ($named != null) $args.push($named);
+    return $f.apply($obj, $args);
+  }
+
+  // TODO(vsm): Remove when we no longer need mirrors metadata.
+  // An array is used to encode annotations attached to the type.
+  if ($ftype instanceof Array) $ftype = $ftype[0];
+
+  // Apply type arguments
+  if ($ftype instanceof $GenericFunctionType) {
+    let formalCount = $ftype.formalCount;
+
+    if ($typeArgs == null) {
+      $typeArgs = $ftype.instantiateDefaultBounds();
+    } else if ($typeArgs.length != formalCount) {
+      return callNSM('Dynamic call with incorrect number of type arguments. ' +
+          'Expected: ' + formalCount + ' Actual: ' + $typeArgs.length);
+    } else {
+      $ftype.checkBounds($typeArgs);
+    }
+    $ftype = $ftype.instantiate($typeArgs);
+  } else if ($typeArgs != null) {
+    return callNSM('Dynamic call with unexpected type arguments. ' +
+        'Expected: 0 Actual: ' + $typeArgs.length);
+  }
+  let errorMessage = $_argumentErrors($ftype, $args, $named);
+  if (errorMessage == null) {
+    if ($typeArgs != null) $args = $typeArgs.concat($args);
+    if ($named != null) $args.push($named);
+    return $f.apply($obj, $args);
+  }
+  return callNSM(errorMessage);
+})()''');
+
+dcall(f, args, [@undefined named]) => _checkAndCall(
+    f, null, JS('', 'void 0'), null, args, named, JS('', 'f.name'));
+
+dgcall(f, typeArgs, args, [@undefined named]) =>
+    _checkAndCall(f, null, JS('', 'void 0'), typeArgs, args, named, 'call');
+
+/// Helper for REPL dynamic invocation variants that make a best effort to
+/// enable accessing private members across library boundaries.
+replNameLookup(object, field) => JS('', '''(() => {
+  let rawField = $field;
+  if (typeof(field) == 'symbol') {
+    // test if the specified field exists in which case it is safe to use it.
+    if ($field in $object) return $field;
+
+    // Symbol is from a different library. Make a best effort to
+    $field = $field.toString();
+    $field = $field.substring('Symbol('.length, field.length - 1);
+
+  } else if ($field.charAt(0) != '_') {
+    // Not a private member so default call path is safe.
+    return $field;
+  }
+
+  // If the exact field name is present, invoke callback with it.
+  if ($field in $object) return $field;
+
+  // TODO(jacobr): warn if there are multiple private members with the same
+  // name which could happen if super classes in different libraries have
+  // the same private member name.
+  let proto = $object;
+  while (proto !== null) {
+    // Private field (indicated with "_").
+    let symbols = Object.getOwnPropertySymbols(proto);
+    let target = 'Symbol(' + $field + ')';
+
+    for (let s = 0; s < symbols.length; s++) {
+      let sym = symbols[s];
+      if (target == sym.toString()) return sym;
+    }
+    proto = proto.__proto__;
+  }
+  // We didn't find a plausible alternate private symbol so just fall back
+  // to the regular field.
+  return rawField;
+})()''');
+
+/// Shared code for dsend, dindex, and dsetindex.
+callMethod(obj, name, typeArgs, args, named, displayName) {
+  if (JS('!', 'typeof # == "function" && # == "call"', obj, name)) {
+    return dgcall(obj, typeArgs, args, named);
+  }
+  var symbol = _canonicalMember(obj, name);
+  if (symbol == null) {
+    return noSuchMethod(obj, InvocationImpl(displayName, args, isMethod: true));
+  }
+  var f = obj != null ? JS('', '#[#]', obj, symbol) : null;
+  var type = getType(obj);
+  var ftype = getMethodType(type, symbol);
+  // No such method if dart object and ftype is missing.
+  return _checkAndCall(f, ftype, obj, typeArgs, args, named, displayName);
+}
+
+dsend(obj, method, args, [@undefined named]) =>
+    callMethod(obj, method, null, args, named, method);
+
+dgsend(obj, typeArgs, method, args, [@undefined named]) =>
+    callMethod(obj, method, typeArgs, args, named, method);
+
+dsendRepl(obj, method, args, [@undefined named]) =>
+    callMethod(obj, replNameLookup(obj, method), null, args, named, method);
+
+dgsendRepl(obj, typeArgs, method, args, [@undefined named]) =>
+    callMethod(obj, replNameLookup(obj, method), typeArgs, args, named, method);
+
+dindex(obj, index) => callMethod(obj, '_get', null, [index], null, '[]');
+
+dsetindex(obj, index, value) =>
+    callMethod(obj, '_set', null, [index, value], null, '[]=');
+
+@notNull
+@JSExportName('is')
+bool instanceOf(obj, type) {
+  if (obj == null) {
+    return identical(type, unwrapType(Null)) || _isTop(type);
+  }
+  return isSubtypeOf(getReifiedType(obj), type);
+}
+
+@JSExportName('as')
+cast(obj, type, @notNull bool isImplicit) {
+  if (obj == null) return obj;
+  var actual = getReifiedType(obj);
+  if (isSubtypeOf(actual, type)) {
+    return obj;
+  }
+  return castError(obj, type, isImplicit);
+}
+
+bool test(bool obj) {
+  if (obj == null) _throwBooleanConversionError();
+  return obj;
+}
+
+bool dtest(obj) {
+  if (obj is! bool) booleanConversionFailed(obj);
+  return obj;
+}
+
+void _throwBooleanConversionError() => throw BooleanConversionAssertionError();
+
+void booleanConversionFailed(obj) {
+  var actual = typeName(getReifiedType(test(obj)));
+  throw TypeErrorImpl("type '$actual' is not a 'bool' in boolean expression");
+}
+
+asInt(obj) {
+  if (obj == null) return null;
+
+  if (JS('!', 'Math.floor(#) != #', obj, obj)) {
+    castError(obj, JS('', '#', int), false);
+  }
+  return obj;
+}
+
+/// Checks that `x` is not null or undefined.
+//
+// TODO(jmesserly): inline this, either by generating it as a function into
+// the module, or via some other pattern such as:
+//
+//     <expr> || nullErr()
+//     (t0 = <expr>) != null ? t0 : nullErr()
+@JSExportName('notNull')
+_notNull(x) {
+  if (x == null) throwNullValueError();
+  return x;
+}
+
+/// The global constant map table.
+final constantMaps = JS('', 'new Map()');
+
+// TODO(leafp): This table gets quite large in apps.
+// Keeping the paths is probably expensive.  It would probably
+// be more space efficient to just use a direct hash table with
+// an appropriately defined structural equality function.
+Object _lookupNonTerminal(Object map, Object key) {
+  var result = JS('', '#.get(#)', map, key);
+  if (result != null) return result;
+  JS('', '#.set(#, # = new Map())', map, key, result);
+  return result;
+}
+
+Map<K, V> constMap<K, V>(JSArray elements) {
+  var count = elements.length;
+  var map = _lookupNonTerminal(constantMaps, count);
+  for (var i = 0; i < count; i++) {
+    map = _lookupNonTerminal(map, JS('', '#[#]', elements, i));
+  }
+  map = _lookupNonTerminal(map, K);
+  var result = JS('', '#.get(#)', map, V);
+  if (result != null) return result;
+  result = ImmutableMap<K, V>.from(elements);
+  JS('', '#.set(#, #)', map, V, result);
+  return result;
+}
+
+final constantSets = JS('', 'new Map()');
+var _immutableSetConstructor;
+
+// We cannot invoke private class constructors directly in Dart.
+Set<E> _createImmutableSet<E>(JSArray<E> elements) {
+  _immutableSetConstructor ??=
+      JS('', '#.#', getLibrary('dart:collection'), '_ImmutableSet\$');
+  return JS('', 'new (#(#)).from(#)', _immutableSetConstructor, E, elements);
+}
+
+Set<E> constSet<E>(JSArray<E> elements) {
+  var count = elements.length;
+  var map = _lookupNonTerminal(constantSets, count);
+  for (var i = 0; i < count; i++) {
+    map = _lookupNonTerminal(map, JS('', '#[#]', elements, i));
+  }
+  var result = JS('', '#.get(#)', map, E);
+  if (result != null) return result;
+  result = _createImmutableSet<E>(elements);
+  JS('', '#.set(#, #)', map, E, result);
+  return result;
+}
+
+bool dassert(value) {
+  if (JS('!', '# != null && #[#] instanceof #', value, value, _runtimeType,
+      AbstractFunctionType)) {
+    value = dcall(value, []);
+  }
+  return dtest(value);
+}
+
+final _value = JS('', 'Symbol("_value")');
+
+///
+/// Looks up a sequence of [keys] in [map], recursively, and
+/// returns the result. If the value is not found, [valueFn] will be called to
+/// add it. For example:
+///
+///     let map = new Map();
+///     putIfAbsent(map, [1, 2, 'hi ', 'there '], () => 'world');
+///
+/// ... will create a Map with a structure like:
+///
+///     { 1: { 2: { 'hi ': { 'there ': 'world' } } } }
+///
+multiKeyPutIfAbsent(map, keys, valueFn) => JS('', '''(() => {
+  for (let k of $keys) {
+    let value = $map.get(k);
+    if (!value) {
+      // TODO(jmesserly): most of these maps are very small (e.g. 1 item),
+      // so it may be worth optimizing for that.
+      $map.set(k, value = new Map());
+    }
+    $map = value;
+  }
+  if ($map.has($_value)) return $map.get($_value);
+  let value = $valueFn();
+  $map.set($_value, value);
+  return value;
+})()''');
+
+/// The global constant table.
+/// This maps the number of names in the object (n)
+/// to a path of length 2*n of maps indexed by the name and
+/// and value of the field.  The final map is
+/// indexed by runtime type, and contains the canonical
+/// version of the object.
+final constants = JS('', 'new Map()');
+
+///
+/// Canonicalize a constant object.
+///
+/// Preconditions:
+/// - `obj` is an objects or array, not a primitive.
+/// - nested values of the object are themselves already canonicalized.
+///
+@JSExportName('const')
+const_(obj) => JS('', '''(() => {
+  let names = $getOwnNamesAndSymbols($obj);
+  let count = names.length;
+  // Index by count.  All of the paths through this map
+  // will have 2*count length.
+  let map = $_lookupNonTerminal($constants, count);
+  // TODO(jmesserly): there's no guarantee in JS that names/symbols are
+  // returned in the same order.
+  //
+  // We could probably get the same order if we're judicious about
+  // initializing fields in a consistent order across all const constructors.
+  // Alternatively we need a way to sort them to make consistent.
+  //
+  // Right now we use the (name,value) pairs in sequence, which prevents
+  // an object with incorrect field values being returned, but won't
+  // canonicalize correctly if key order is different.
+  //
+  // See issue https://github.com/dart-lang/sdk/issues/30876
+  for (let i = 0; i < count; i++) {
+    let name = names[i];
+    map = $_lookupNonTerminal(map, name);
+    map = $_lookupNonTerminal(map, $obj[name]);
+  }
+  // TODO(leafp): It may be the case that the reified type
+  // is always one of the keys already used above?
+  let type = $getReifiedType($obj);
+  let value = map.get(type);
+  if (value) return value;
+  map.set(type, $obj);
+  return $obj;
+})()''');
+
+/// The global constant list table.
+/// This maps the number of elements in the list (n)
+/// to a path of length n of maps indexed by the value
+/// of the field.  The final map is indexed by the element
+/// type and contains the canonical version of the list.
+final constantLists = JS('', 'new Map()');
+
+/// Canonicalize a constant list
+constList(elements, elementType) => JS('', '''(() => {
+  let count = $elements.length;
+  let map = $_lookupNonTerminal($constantLists, count);
+  for (let i = 0; i < count; i++) {
+    map = $_lookupNonTerminal(map, elements[i]);
+  }
+  let value = map.get($elementType);
+  if (value) return value;
+
+  ${getGenericClass(JSArray)}($elementType).unmodifiable($elements);
+  map.set($elementType, elements);
+  return elements;
+})()''');
+
+constFn(x) => JS('', '() => x');
+
+/// Gets the extension symbol given a member [name].
+///
+/// This is inlined by the compiler when used with a literal string.
+extensionSymbol(String name) => JS('', 'dartx[#]', name);
+
+// The following are helpers for Object methods when the receiver
+// may be null. These should only be generated by the compiler.
+bool equals(x, y) {
+  // We handle `y == null` inside our generated operator methods, to keep this
+  // function minimal.
+  // This pattern resulted from performance testing; it found that dispatching
+  // was the fastest solution, even for primitive types.
+  return JS('!', '# == null ? # == null : #[#](#)', x, y, x,
+      extensionSymbol('_equals'), y);
+}
+
+int hashCode(obj) {
+  return obj == null ? 0 : JS('!', '#[#]', obj, extensionSymbol('hashCode'));
+}
+
+@JSExportName('toString')
+String _toString(obj) {
+  if (obj == null) return "null";
+  if (obj is String) return obj;
+  return JS('!', '#[#]()', obj, extensionSymbol('toString'));
+}
+
+/// Converts to a non-null [String], equivalent to
+/// `dart.notNull(dart.toString(obj))`.
+///
+/// This is commonly used in string interpolation.
+@notNull
+String str(obj) {
+  if (obj == null) return "null";
+  if (obj is String) return obj;
+  return _notNull(JS('!', '#[#]()', obj, extensionSymbol('toString')));
+}
+
+// TODO(jmesserly): is the argument type verified statically?
+noSuchMethod(obj, Invocation invocation) {
+  if (obj == null) defaultNoSuchMethod(obj, invocation);
+  return JS('', '#[#](#)', obj, extensionSymbol('noSuchMethod'), invocation);
+}
+
+/// The default implementation of `noSuchMethod` to match `Object.noSuchMethod`.
+defaultNoSuchMethod(obj, Invocation i) {
+  throw NoSuchMethodError.withInvocation(obj, i);
+}
+
+runtimeType(obj) {
+  return obj == null ? Null : JS('', '#[dartx.runtimeType]', obj);
+}
+
+final identityHashCode_ = JS('', 'Symbol("_identityHashCode")');
+
+/// Adapts a Dart `get iterator` into a JS `[Symbol.iterator]`.
+// TODO(jmesserly): instead of an adaptor, we could compile Dart iterators
+// natively implementing the JS iterator protocol. This would allow us to
+// optimize them a bit.
+final JsIterator = JS('', '''
+  class JsIterator {
+    constructor(dartIterator) {
+      this.dartIterator = dartIterator;
+    }
+    next() {
+      let i = this.dartIterator;
+      let done = !i.moveNext();
+      return { done: done, value: done ? void 0 : i.current };
+    }
+  }
+''');
+
+_canonicalMember(obj, name) {
+  // Private names are symbols and are already canonical.
+  if (JS('!', 'typeof # === "symbol"', name)) return name;
+
+  if (obj != null && JS<bool>('!', '#[#] != null', obj, _extensionType)) {
+    return JS('', 'dartx.#', name);
+  }
+
+  // Check for certain names that we can't use in JS
+  if (JS('!', '# == "constructor" || # == "prototype"', name, name)) {
+    JS('', '# = "+" + #', name, name);
+  }
+  return name;
+}
+
+/// Emulates the implicit "loadLibrary" function provided by a deferred library.
+///
+/// Libraries are not actually deferred in DDC, so this just returns a future
+/// that completes immediately.
+Future loadLibrary() => Future.value();
+
+/// Defines lazy statics.
+void defineLazy(to, from) {
+  for (var name in getOwnNamesAndSymbols(from)) {
+    defineLazyField(to, name, getOwnPropertyDescriptor(from, name));
+  }
+}
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/private/ddc_runtime/rtti.dart b/sdk_nnbd/lib/_internal/js_dev_runtime/private/ddc_runtime/rtti.dart
new file mode 100644
index 0000000..11ea1ae
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/private/ddc_runtime/rtti.dart
@@ -0,0 +1,222 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// This library defines the association between runtime objects and
+/// runtime types.
+part of dart._runtime;
+
+/// Runtime type information.  This module defines the mapping from
+/// runtime objects to their runtime type information.  See the types
+/// module for the definition of how type information is represented.
+///
+/// There are two kinds of objects that represent "types" at runtime. A
+/// "runtime type" contains all of the data needed to implement the runtime
+/// type checking inserted by the compiler. These objects fall into four
+/// categories:
+///
+///   - Things represented by javascript primitives, such as
+///     null, numbers, booleans, strings, and symbols.  For these
+///     we map directly from the javascript type (given by typeof)
+///     to the appropriate class type from core, which serves as their
+///     rtti.
+///
+///   - Functions, which are represented by javascript functions.
+///     Representations of Dart functions always have a
+///     _runtimeType property attached to them with the appropriate
+///     rtti.
+///
+///   - Objects (instances) which are represented by instances of
+///     javascript (ES6) classes.  Their types are given by their
+///     classes, and the rtti is accessed by projecting out their
+///     constructor field.
+///
+///   - Types objects, which are represented as described in the types
+///     module.  Types always have a _runtimeType property attached to
+///     them with the appropriate rtti.  The rtti for these is always
+///     core.Type.  TODO(leafp): consider the possibility that we can
+///     reliably recognize type objects and map directly to core.Type
+///     rather than attaching this property everywhere.
+///
+/// The other kind of object representing a "type" is the instances of the
+/// dart:core Type class. These are the user visible objects you get by calling
+/// "runtimeType" on an object or using a class literal expression. These are
+/// different from the above objects, and are created by calling `wrapType()`
+/// on a runtime type.
+
+/// Tag a closure with a type.
+///
+/// `dart.fn(closure, type)` marks [closure] with the provided runtime [type].
+fn(closure, type) {
+  JS('', '#[#] = #', closure, _runtimeType, type);
+  return closure;
+}
+
+/// Tag a closure with a type that's computed lazily.
+///
+/// `dart.fn(closure, type)` marks [closure] with a getter that uses
+/// [computeType] to return the runtime type.
+///
+/// The getter/setter replaces the property with a value property, so the
+/// resulting function is compatible with [fn] and the type can be set again
+/// safely.
+lazyFn(closure, Object Function() computeType) {
+  defineAccessor(closure, _runtimeType,
+      get: () => defineValue(closure, _runtimeType, computeType()),
+      set: (value) => defineValue(closure, _runtimeType, value),
+      configurable: true);
+  return closure;
+}
+
+// TODO(vsm): How should we encode the runtime type?
+final _runtimeType = JS('', 'Symbol("_runtimeType")');
+
+final _moduleName = JS('', 'Symbol("_moduleName")');
+
+getFunctionType(obj) {
+  // TODO(vsm): Encode this properly on the function for Dart-generated code.
+  var args = JS<List>('!', 'Array(#.length).fill(#)', obj, dynamic);
+  return fnType(bottom, args, JS('', 'void 0'));
+}
+
+/// Returns the runtime representation of the type of obj.
+///
+/// The resulting object is used internally for runtime type checking. This is
+/// different from the user-visible Type object returned by calling
+/// `runtimeType` on some Dart object.
+getReifiedType(obj) {
+  switch (JS<String>('!', 'typeof #', obj)) {
+    case "object":
+      if (obj == null) return JS('', '#', Null);
+      if (JS('!', '# instanceof #', obj, Object)) {
+        return JS('', '#.constructor', obj);
+      }
+      var result = JS('', '#[#]', obj, _extensionType);
+      if (result == null) return JS('', '#', jsobject);
+      return result;
+    case "function":
+      // All Dart functions and callable classes must set _runtimeType
+      var result = JS('', '#[#]', obj, _runtimeType);
+      if (result != null) return result;
+      return JS('', '#', jsobject);
+    case "undefined":
+      return JS('', '#', Null);
+    case "number":
+      return JS('', 'Math.floor(#) == # ? # : #', obj, obj, int, double);
+    case "boolean":
+      return JS('', '#', bool);
+    case "string":
+      return JS('', '#', String);
+    case "symbol":
+    default:
+      return JS('', '#', jsobject);
+  }
+}
+
+/// Return the module name for a raw library object.
+String getModuleName(Object module) => JS('', '#[#]', module, _moduleName);
+
+final _loadedModules = JS('', 'new Map()');
+final _loadedPartMaps = JS('', 'new Map()');
+final _loadedSourceMaps = JS('', 'new Map()');
+
+List<String> getModuleNames() {
+  return JSArray<String>.of(JS('', 'Array.from(#.keys())', _loadedModules));
+}
+
+String getSourceMap(String moduleName) {
+  return JS('!', '#.get(#)', _loadedSourceMaps, moduleName);
+}
+
+/// Return all library objects in the specified module.
+getModuleLibraries(String name) {
+  var module = JS('', '#.get(#)', _loadedModules, name);
+  if (module == null) return null;
+  JS('', '#[#] = #', module, _moduleName, name);
+  return module;
+}
+
+/// Return the part map for a specific module.
+getModulePartMap(String name) => JS('', '#.get(#)', _loadedPartMaps, name);
+
+/// Track all libraries
+void trackLibraries(
+    String moduleName, Object libraries, Object parts, String sourceMap) {
+  if (parts is String) {
+    // Added for backwards compatibility.
+    // package:build_web_compilers currently invokes this without [parts]
+    // in its bootstrap code.
+    sourceMap = parts as String;
+    parts = JS('', '{}');
+  }
+  JS('', '#.set(#, #)', _loadedSourceMaps, moduleName, sourceMap);
+  JS('', '#.set(#, #)', _loadedModules, moduleName, libraries);
+  JS('', '#.set(#, #)', _loadedPartMaps, moduleName, parts);
+}
+
+List<String> _libraries;
+Map<String, Object> _libraryObjects;
+Map<String, List<String>> _parts;
+
+_computeLibraryMetadata() {
+  _libraries = [];
+  _libraryObjects = {};
+  _parts = {};
+  var modules = getModuleNames();
+  for (var name in modules) {
+    // Add libraries from each module.
+    var module = getModuleLibraries(name);
+    var libraries = getOwnPropertyNames(module).cast<String>();
+    _libraries.addAll(libraries);
+    for (var library in libraries) {
+      _libraryObjects[library] = JS('', '#.#', module, library);
+    }
+
+    // Add parts from each module.
+    var partMap = getModulePartMap(name);
+    libraries = getOwnPropertyNames(partMap).cast<String>();
+    for (var library in libraries) {
+      _parts[library] = List.from(JS('List', '#.#', partMap, library));
+    }
+  }
+}
+
+/// Returns the JS library object for a given library [uri] or
+/// undefined / null if it isn't loaded.  Top-level types and
+/// methods are available on this object.
+Object getLibrary(String uri) {
+  if (_libraryObjects == null) {
+    _computeLibraryMetadata();
+  }
+  return _libraryObjects[uri];
+}
+
+/// Returns a JSArray of library uris (e.g,
+/// ['dart:core', 'dart:_internal', ..., 'package:foo/bar.dart', ... 'main.dart'])
+/// loaded in this application.
+List<String> getLibraries() {
+  if (_libraries == null) {
+    _computeLibraryMetadata();
+  }
+  return _libraries;
+}
+
+/// Returns a JSArray of part uris for a given [libraryUri].
+/// The part uris will be relative to the [libraryUri].
+///
+/// E.g., invoking `getParts('package:intl/intl.dart')` returns (as of this
+/// writing): ```
+/// ["src/intl/bidi_formatter.dart", "src/intl/bidi_utils.dart",
+///  "src/intl/compact_number_format.dart", "src/intl/date_format.dart",
+///  "src/intl/date_format_field.dart", "src/intl/date_format_helpers.dart",
+///  "src/intl/number_format.dart"]
+/// ```
+///
+/// If [libraryUri] doesn't map to a library or maps to a library with no
+/// parts, an empty list is returned.
+List<String> getParts(String libraryUri) {
+  if (_parts == null) {
+    _computeLibraryMetadata();
+  }
+  return _parts[libraryUri] ?? [];
+}
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/private/ddc_runtime/runtime.dart b/sdk_nnbd/lib/_internal/js_dev_runtime/private/ddc_runtime/runtime.dart
new file mode 100644
index 0000000..99e1ab9
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/private/ddc_runtime/runtime.dart
@@ -0,0 +1,210 @@
+// Copyright (c) 2015, 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.
+
+@ReifyFunctionTypes(false)
+library dart._runtime;
+
+import 'dart:async';
+import 'dart:collection';
+
+import 'dart:_debugger' show stackTraceMapper, trackCall;
+import 'dart:_foreign_helper' show JS, JSExportName, rest, spread;
+import 'dart:_interceptors' show JSArray, jsNull, JSFunction, NativeError;
+import 'dart:_internal' as internal show Symbol;
+import 'dart:_js_helper'
+    show
+        AssertionErrorImpl,
+        BooleanConversionAssertionError,
+        CastErrorImpl,
+        DartIterator,
+        TypeErrorImpl,
+        JsLinkedHashMap,
+        ImmutableMap,
+        PrivateSymbol,
+        ReifyFunctionTypes,
+        NoReifyGeneric,
+        notNull,
+        undefined;
+
+export 'dart:_debugger' show getDynamicStats, clearDynamicStats, trackCall;
+
+part 'utils.dart';
+part 'classes.dart';
+part 'rtti.dart';
+part 'types.dart';
+part 'errors.dart';
+part 'operations.dart';
+
+// TODO(vsm): Move polyfill code to dart:html.
+// Note, native extensions are registered onto types in dart.global.
+// This polyfill needs to run before the corresponding dart:html code is run.
+final _polyfilled = JS('', 'Symbol("_polyfilled")');
+
+bool polyfill(window) => JS('', '''(() => {
+  if ($window[$_polyfilled]) return false;
+  $window[$_polyfilled] = true;
+
+  if (typeof $window.NodeList !== "undefined") {
+    // TODO(vsm): Do we still need these?
+    $window.NodeList.prototype.get = function(i) { return this[i]; };
+    $window.NamedNodeMap.prototype.get = function(i) { return this[i]; };
+    $window.DOMTokenList.prototype.get = function(i) { return this[i]; };
+    $window.HTMLCollection.prototype.get = function(i) { return this[i]; };
+
+    // Expose constructors for DOM types dart:html needs to assume are
+    // available on window.
+    if (typeof $window.PannerNode == "undefined") {
+      let audioContext;
+      if (typeof $window.AudioContext == "undefined" &&
+          (typeof $window.webkitAudioContext != "undefined")) {
+        audioContext = new $window.webkitAudioContext();
+      } else {
+        audioContext = new $window.AudioContext();
+        $window.StereoPannerNode =
+            audioContext.createStereoPanner().constructor;
+      }
+      $window.PannerNode = audioContext.createPanner().constructor;
+    }
+    if (typeof $window.AudioSourceNode == "undefined") {
+      $window.AudioSourceNode = MediaElementAudioSourceNode.__proto__;
+    }
+    if (typeof $window.FontFaceSet == "undefined") {
+      // CSS Font Loading is not supported on Edge.
+      if (typeof $window.document.fonts != "undefined") {
+        $window.FontFaceSet = $window.document.fonts.__proto__.constructor;
+      }
+    }
+    if (typeof $window.MemoryInfo == "undefined") {
+      if (typeof $window.performance.memory != "undefined") {
+        $window.MemoryInfo = $window.performance.memory.constructor;
+      }
+    }
+    if (typeof $window.Geolocation == "undefined") {
+      $window.Geolocation == $window.navigator.geolocation.constructor;
+    }
+    if (typeof $window.Animation == "undefined") {
+      let d = $window.document.createElement('div');
+      if (typeof d.animate != "undefined") {
+        $window.Animation = d.animate(d).constructor;
+      }
+    }
+    if (typeof $window.SourceBufferList == "undefined") {
+      if ('MediaSource' in $window) {
+        $window.SourceBufferList =
+          new $window.MediaSource().sourceBuffers.constructor;
+      }
+    }
+    if (typeof $window.SpeechRecognition == "undefined") {
+      $window.SpeechRecognition = $window.webkitSpeechRecognition;
+      $window.SpeechRecognitionError = $window.webkitSpeechRecognitionError;
+      $window.SpeechRecognitionEvent = $window.webkitSpeechRecognitionEvent;
+    }
+  }
+  return true;
+})()''');
+
+@JSExportName('global')
+final global_ = JS('', '''
+  function () {
+    // Find global object.
+    var globalState = (typeof window != "undefined") ? window
+      : (typeof global != "undefined") ? global
+      : (typeof self != "undefined") ? self : null;
+    if (!globalState) {
+      // Some platforms (e.g., d8) do not define any of the above.  The
+      // following is a non-CSP safe way to access the global object:
+      globalState = new Function('return this;')();
+    }
+
+    $polyfill(globalState);
+
+    // By default, stack traces cutoff at 10.  Set the limit to Infinity for
+    // better debugging.
+    if (globalState.Error) {
+      globalState.Error.stackTraceLimit = Infinity;
+    }
+
+    // These settings must be configured before the application starts so that
+    // user code runs with the correct configuration.
+    let settings = 'ddcSettings' in globalState ? globalState.ddcSettings : {};
+
+    $trackProfile(
+        'trackProfile' in settings ? settings.trackProfile : false);
+
+    return globalState;
+  }()
+''');
+
+void trackProfile(bool flag) {
+  JS('', 'dart.__trackProfile = #', flag);
+}
+
+final JsSymbol = JS('', 'Symbol');
+
+/// The prototype used for all Dart libraries.
+///
+/// This makes it easy to identify Dart library objects, and also improves
+/// performance (JS engines such as V8 tend to assume `Object.create(null)` is
+/// used for a Map, so they don't optimize it as they normally would for
+/// class-like objects).
+///
+/// The `dart.library` field is set by the compiler during SDK bootstrapping
+/// (because it is needed for dart:_runtime itself), so we don't need to
+/// initialize it here. The name `dart.library` is used because it reads nicely,
+/// for example:
+///
+///     const my_library = Object.create(dart.library);
+///
+Object libraryPrototype = JS('', 'dart.library');
+
+// TODO(vsm): Remove once this flag we've removed the ability to
+// whitelist / fallback on the old behavior.
+bool startAsyncSynchronously = true;
+void setStartAsyncSynchronously([bool value = true]) {
+  startAsyncSynchronously = value;
+}
+
+/// A list of all JS Maps used for caching results, such as by [isSubtypeOf] and
+/// [generic].
+///
+/// This is used by [hotRestart] to ensure we don't leak types from previous
+/// libraries.
+@notNull
+final List<Object> _cacheMaps = JS('!', '[]');
+
+/// A list of functions to reset static fields back to their uninitialized
+/// state.
+///
+/// This is populated by [defineLazyField], and only contains the list of fields
+/// that have actually been initialized.
+@notNull
+final List<void Function()> _resetFields = JS('', '[]');
+
+/// Clears out runtime state in `dartdevc` so we can hot-restart.
+///
+/// This should be called when the user requests a hot-restart, when the UI is
+/// handling that user action.
+void hotRestart() {
+  // TODO(jmesserly): we need to prevent all pending callbacks from firing.
+  for (var f in _resetFields) f();
+  _resetFields.clear();
+  for (var m in _cacheMaps) JS('', '#.clear()', m);
+  _cacheMaps.clear();
+  JS('', '#.clear()', constantMaps);
+}
+
+/// Marks enqueuing an async operation.
+///
+/// This will be called by library code when enqueuing an async operation
+/// controlled by the JavaScript event handler.
+///
+/// It will also call [removeAsyncCallback] when Dart callback is about to be
+/// executed (note this is called *before* the callback executes, so more
+/// async operations could be added from that).
+void Function() addAsyncCallback = JS('', 'function() {}');
+
+/// Marks leaving a javascript async operation.
+///
+/// See [addAsyncCallback].
+void Function() removeAsyncCallback = JS('', 'function() {}');
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/private/ddc_runtime/types.dart b/sdk_nnbd/lib/_internal/js_dev_runtime/private/ddc_runtime/types.dart
new file mode 100644
index 0000000..3175eeb
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/private/ddc_runtime/types.dart
@@ -0,0 +1,1438 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// This library defines the representation of runtime types.
+part of dart._runtime;
+
+final metadata = JS('', 'Symbol("metadata")');
+
+/// Types in dart are represented internally at runtime as follows.
+///
+///   - Normal nominal types, produced from classes, are represented
+///     at runtime by the JS class of which they are an instance.
+///     If the type is the result of instantiating a generic class,
+///     then the "classes" module manages the association between the
+///     instantiated class and the original class declaration
+///     and the type arguments with which it was instantiated.  This
+///     association can be queried via the "classes" module".
+///
+///   - All other types are represented as instances of class [DartType],
+///     defined in this module.
+///     - Dynamic, Void, and Bottom are singleton instances of sentinal
+///       classes.
+///     - Function types are instances of subclasses of AbstractFunctionType.
+///
+/// Function types are represented in one of two ways:
+///   - As an instance of FunctionType.  These are eagerly computed.
+///   - As an instance of TypeDef.  The TypeDef representation lazily
+///     computes an instance of FunctionType, and delegates to that instance.
+///
+/// These above "runtime types" are what is used for implementing DDC's
+/// internal type checks. These objects are distinct from the objects exposed
+/// to user code by class literals and calling `Object.runtimeType`. In DDC,
+/// the latter are represented by instances of WrappedType which contain a
+/// real runtime type internally. This ensures that the returned object only
+/// exposes the API that Type defines:
+///
+///     get String name;
+///     String toString();
+///
+/// These "runtime types" have methods for performing type checks. The methods
+/// have the following JavaScript names which are designed to not collide with
+/// static methods, which are also placed 'on' the class constructor function.
+///
+///     T.is(o): Implements 'o is T'.
+///     T.as(o): Implements 'o as T'.
+///     T._check(o): Implements the type assertion of 'T x = o;'
+///
+/// By convention, we used named JavaScript functions for these methods with the
+/// name 'is_X', 'as_X' and 'check_X' for various X to indicate the type or the
+/// implementation strategy for the test (e.g 'is_String', 'is_G' for generic
+/// types, etc.)
+// TODO(jmesserly): we shouldn't implement Type here. It should be moved down
+// to AbstractFunctionType.
+class DartType implements Type {
+  String get name => this.toString();
+
+  // TODO(jmesserly): these should never be reached, can be make them abstract?
+  @notNull
+  @JSExportName('is')
+  bool is_T(object) => instanceOf(object, this);
+
+  @JSExportName('as')
+  as_T(object) => cast(object, this, false);
+
+  @JSExportName('_check')
+  check_T(object) => cast(object, this, true);
+}
+
+class DynamicType extends DartType {
+  toString() => 'dynamic';
+
+  @JSExportName('is')
+  bool is_T(object) => true;
+
+  @JSExportName('as')
+  as_T(object) => object;
+
+  @JSExportName('_check')
+  check_T(object) => object;
+}
+
+@notNull
+bool _isJsObject(obj) => JS('!', '# === #', getReifiedType(obj), jsobject);
+
+/// Asserts that [f] is a native JS functions and returns it if so.
+/// This function should be used to ensure that a function is a native
+/// JS functions in contexts that expect that.
+F assertInterop<F extends Function>(F f) {
+  // TODO(vsm): Throw a more specific error if this fails.
+  assert(_isJsObject(f));
+  return f;
+}
+
+/// The Dart type that represents a JavaScript class(/constructor) type.
+///
+/// The JavaScript type may not exist, either because it's not loaded yet, or
+/// because it's not available (such as with mocks). To handle this gracefully,
+/// we disable type checks for in these cases, and allow any JS object to work
+/// as if it were an instance of this JS type.
+class LazyJSType extends DartType {
+  Function() _getRawJSTypeFn;
+  @notNull
+  final String _dartName;
+  Object _rawJSType;
+
+  LazyJSType(this._getRawJSTypeFn, this._dartName);
+
+  toString() {
+    var raw = _getRawJSType();
+    return raw != null ? typeName(raw) : "JSObject<$_dartName>";
+  }
+
+  Object _getRawJSType() {
+    var raw = _rawJSType;
+    if (raw != null) return raw;
+
+    // Try to evaluate the JS type. If this fails for any reason, we'll try
+    // again next time.
+    // TODO(jmesserly): is it worth trying again? It may create unnecessary
+    // overhead, especially if exceptions are being thrown. Also it means the
+    // behavior of a given type check can change later on.
+    try {
+      raw = _getRawJSTypeFn();
+    } catch (e) {}
+
+    if (raw == null) {
+      _warn('Cannot find native JavaScript type ($_dartName) for type check');
+    } else {
+      _rawJSType = raw;
+      _getRawJSTypeFn = null; // Free the function that computes the JS type.
+    }
+    return raw;
+  }
+
+  Object rawJSTypeForCheck() => _getRawJSType() ?? jsobject;
+
+  @notNull
+  bool isRawJSType(obj) {
+    var raw = _getRawJSType();
+    if (raw != null) return JS('!', '# instanceof #', obj, raw);
+    return _isJsObject(obj);
+  }
+
+  @notNull
+  @JSExportName('is')
+  bool is_T(obj) => isRawJSType(obj) || instanceOf(obj, this);
+
+  @JSExportName('as')
+  as_T(obj) => obj == null || is_T(obj) ? obj : castError(obj, this, false);
+
+  @JSExportName('_check')
+  check_T(obj) => obj == null || is_T(obj) ? obj : castError(obj, this, true);
+}
+
+/// An anonymous JS type
+///
+/// For the purposes of subtype checks, these match any JS type.
+class AnonymousJSType extends DartType {
+  final String _dartName;
+  AnonymousJSType(this._dartName);
+  toString() => _dartName;
+
+  @JSExportName('is')
+  bool is_T(obj) => _isJsObject(obj) || instanceOf(obj, this);
+
+  @JSExportName('as')
+  as_T(obj) => obj == null || _isJsObject(obj) ? obj : cast(obj, this, false);
+
+  @JSExportName('_check')
+  check_T(obj) => obj == null || _isJsObject(obj) ? obj : cast(obj, this, true);
+}
+
+void _warn(arg) {
+  JS('void', 'console.warn(#)', arg);
+}
+
+var _lazyJSTypes = JS('', 'new Map()');
+var _anonymousJSTypes = JS('', 'new Map()');
+
+lazyJSType(Function() getJSTypeCallback, String name) {
+  var ret = JS('', '#.get(#)', _lazyJSTypes, name);
+  if (ret == null) {
+    ret = LazyJSType(getJSTypeCallback, name);
+    JS('', '#.set(#, #)', _lazyJSTypes, name, ret);
+  }
+  return ret;
+}
+
+anonymousJSType(String name) {
+  var ret = JS('', '#.get(#)', _anonymousJSTypes, name);
+  if (ret == null) {
+    ret = AnonymousJSType(name);
+    JS('', '#.set(#, #)', _anonymousJSTypes, name, ret);
+  }
+  return ret;
+}
+
+@JSExportName('dynamic')
+final _dynamic = DynamicType();
+
+class VoidType extends DartType {
+  toString() => 'void';
+}
+
+@JSExportName('void')
+final void_ = VoidType();
+
+class BottomType extends DartType {
+  toString() => 'bottom';
+}
+
+// TODO(vsm): We reify bottom as Null.  We will revisit this with
+// non-nullable types.
+final bottom = unwrapType(Null);
+
+class JSObjectType extends DartType {
+  toString() => 'NativeJavaScriptObject';
+}
+
+final jsobject = JSObjectType();
+
+/// Dev Compiler's implementation of Type, wrapping its internal [_type].
+class _Type extends Type {
+  /// The internal type representation, either a [DartType] or class constructor
+  /// function.
+  // TODO(jmesserly): introduce InterfaceType so we don't have to special case
+  // classes
+  @notNull
+  final Object _type;
+
+  _Type(this._type);
+
+  toString() => typeName(_type);
+
+  Type get runtimeType => Type;
+}
+
+/// Given an internal runtime type object, wraps it in a `_Type` object
+/// that implements the dart:core Type interface.
+Type wrapType(type) {
+  // If we've already wrapped this type once, use the previous wrapper. This
+  // way, multiple references to the same type return an identical Type.
+  if (JS('!', '#.hasOwnProperty(#)', type, _typeObject)) {
+    return JS('', '#[#]', type, _typeObject);
+  }
+  var result = _Type(type);
+  JS('', '#[#] = #', type, _typeObject, result);
+  return result;
+}
+
+/// The symbol used to store the cached `Type` object associated with a class.
+final _typeObject = JS('', 'Symbol("typeObject")');
+
+/// Given a WrappedType, return the internal runtime type object.
+Object unwrapType(Type obj) => JS<_Type>('', '#', obj)._type;
+
+// Marker class for generic functions, typedefs, and non-generic functions.
+abstract class AbstractFunctionType extends DartType {}
+
+/// Memo table for named argument groups. A named argument packet
+/// {name1 : type1, ..., namen : typen} corresponds to the path
+/// n, name1, type1, ...., namen, typen.  The element of the map
+/// reached via this path (if any) is the canonical representative
+/// for this packet.
+final _fnTypeNamedArgMap = JS('', 'new Map()');
+
+/// Memo table for positional argument groups. A positional argument
+/// packet [type1, ..., typen] (required or optional) corresponds to
+/// the path n, type1, ...., typen.  The element reached via
+/// this path (if any) is the canonical representative for this
+/// packet. Note that required and optional parameters packages
+/// may have the same canonical representation.
+final _fnTypeArrayArgMap = JS('', 'new Map()');
+
+/// Memo table for function types. The index path consists of the
+/// path length - 1, the returnType, the canonical positional argument
+/// packet, and if present, the canonical optional or named argument
+/// packet.  A level of indirection could be avoided here if desired.
+final _fnTypeTypeMap = JS('', 'new Map()');
+
+/// Memo table for small function types with no optional or named
+/// arguments and less than a fixed n (currently 3) number of
+/// required arguments.  Indexing into this table by the number
+/// of required arguments yields a map which is indexed by the
+/// argument types themselves.  The element reached via this
+/// index path (if present) is the canonical function type.
+final List _fnTypeSmallMap = JS('', '[new Map(), new Map(), new Map()]');
+
+@NoReifyGeneric()
+T _memoizeArray<T>(map, arr, T create()) => JS('', '''(() => {
+  let len = $arr.length;
+  $map = $_lookupNonTerminal($map, len);
+  for (var i = 0; i < len-1; ++i) {
+    $map = $_lookupNonTerminal($map, $arr[i]);
+  }
+  let result = $map.get($arr[len-1]);
+  if (result !== void 0) return result;
+  $map.set($arr[len-1], result = $create());
+  return result;
+})()''');
+
+List _canonicalizeArray(List array, map) =>
+    _memoizeArray(map, array, () => array);
+
+// TODO(leafp): This only canonicalizes of the names are
+// emitted in a consistent order.
+_canonicalizeNamed(named, map) => JS('', '''(() => {
+  let key = [];
+  let names = $getOwnPropertyNames($named);
+  for (var i = 0; i < names.length; ++i) {
+    let name = names[i];
+    let type = $named[name];
+    key.push(name);
+    key.push(type);
+  }
+  return $_memoizeArray($map, key, () => $named);
+})()''');
+
+// TODO(leafp): This handles some low hanging fruit, but
+// really we should make all of this faster, and also
+// handle more cases here.
+FunctionType _createSmall(returnType, List required) => JS('', '''(() => {
+  let count = $required.length;
+  let map = $_fnTypeSmallMap[count];
+  for (var i = 0; i < count; ++i) {
+    map = $_lookupNonTerminal(map, $required[i]);
+ }
+ let result = map.get($returnType);
+ if (result !== void 0) return result;
+ result = ${new FunctionType(returnType, required, [], JS('', '{}'))};
+ map.set($returnType, result);
+ return result;
+})()''');
+
+class FunctionType extends AbstractFunctionType {
+  final Type returnType;
+  List args;
+  List optionals;
+  // Named arguments native JS Object of the form { namedArgName: namedArgType }
+  final named;
+  // TODO(vsm): This is just parameter metadata for now.
+  // Suspected but not confirmed: Only used by mirrors for pageloader2 support.
+  // The metadata is represented as a list of JS arrays, one for each argument
+  // that contains the annotations for that argument or an empty array if there
+  // are no annotations.
+  List metadata = [];
+  String _stringValue;
+
+  /// Construct a function type.
+  ///
+  /// We eagerly normalize the argument types to avoid having to deal with this
+  /// logic in multiple places.
+  ///
+  /// This code does best effort canonicalization.  It does not guarantee that
+  /// all instances will share.
+  ///
+  /// Note: Generic function subtype checks assume types have been canonicalized
+  /// when testing if type bounds are equal.
+  static FunctionType create(returnType, List args, extra) {
+    // Note that if extra is ever passed as an empty array
+    // or an empty map, we can end up with semantically
+    // identical function types that don't canonicalize
+    // to the same object since we won't fall into this
+    // fast path.
+    if (extra == null && JS<bool>('!', '#.length < 3', args)) {
+      return _createSmall(returnType, args);
+    }
+    args = _canonicalizeArray(args, _fnTypeArrayArgMap);
+    var keys;
+    FunctionType Function() create;
+    if (extra == null) {
+      keys = [returnType, args];
+      create = () => FunctionType(returnType, args, [], JS('', '{}'));
+    } else if (JS('!', '# instanceof Array', extra)) {
+      var optionals =
+          _canonicalizeArray(JS('', '#', extra), _fnTypeArrayArgMap);
+      keys = [returnType, args, optionals];
+      create = () => FunctionType(returnType, args, optionals, JS('', '{}'));
+    } else {
+      var named = _canonicalizeNamed(extra, _fnTypeNamedArgMap);
+      keys = [returnType, args, named];
+      create = () => FunctionType(returnType, args, [], named);
+    }
+    return _memoizeArray(_fnTypeTypeMap, keys, create);
+  }
+
+  /// Returns the function arguments.
+  ///
+  /// If an argument is provided with annotations (encoded as a JS array where
+  /// the first element is the argument, and the rest are annotations) the
+  /// annotations are extracted and saved in [metadata].
+  List _process(List array) {
+    var result = [];
+    for (var i = 0; JS<bool>('!', '# < #.length', i, array); ++i) {
+      var arg = JS('', '#[#]', array, i);
+      if (JS('!', '# instanceof Array', arg)) {
+        JS('', '#.push(#.slice(1))', metadata, arg);
+        JS('', '#.push(#[0])', result, arg);
+      } else {
+        JS('', '#.push([])', metadata);
+        JS('', '#.push(#)', result, arg);
+      }
+    }
+    return result;
+  }
+
+  FunctionType(this.returnType, this.args, this.optionals, this.named) {
+    this.args = _process(this.args);
+    this.optionals = _process(this.optionals);
+    // TODO(vsm): Named arguments were never used by pageloader2 so they were
+    // never processed here.
+  }
+
+  toString() => name;
+
+  int get requiredParameterCount => args.length;
+  int get positionalParameterCount => args.length + optionals.length;
+
+  getPositionalParameter(int i) {
+    int n = args.length;
+    return i < n ? args[i] : optionals[i + n];
+  }
+
+  Map<String, Object> getNamedParameters() {
+    var result = <String, Object>{};
+    var names = getOwnPropertyNames(named);
+    JS('', '#.sort()', names);
+    for (var i = 0; JS<bool>('!', '# < #.length', i, names); ++i) {
+      String name = JS('!', '#[#]', names, i);
+      result[name] = JS('', '#[#]', named, name);
+    }
+    return result;
+  }
+
+  get name {
+    if (_stringValue != null) return _stringValue;
+
+    var buffer = '(';
+    for (var i = 0; JS<bool>('!', '# < #.length', i, args); ++i) {
+      if (i > 0) {
+        buffer += ', ';
+      }
+      buffer += typeName(JS('', '#[#]', args, i));
+    }
+    if (JS('!', '#.length > 0', optionals)) {
+      if (JS('!', '#.length > 0', args)) buffer += ', ';
+      buffer += '[';
+      for (var i = 0; JS<bool>('!', '# < #.length', i, optionals); ++i) {
+        if (i > 0) {
+          buffer += ', ';
+        }
+        buffer += typeName(JS('', '#[#]', optionals, i));
+      }
+      buffer += ']';
+    } else if (JS('!', 'Object.keys(#).length > 0', named)) {
+      if (JS('!', '#.length > 0', args)) buffer += ', ';
+      buffer += '{';
+      var names = getOwnPropertyNames(named);
+      JS('', '#.sort()', names);
+      for (var i = 0; JS<bool>('!', '# < #.length', i, names); ++i) {
+        if (i > 0) {
+          buffer += ', ';
+        }
+        var typeNameString = typeName(JS('', '#[#[#]]', named, names, i));
+        buffer += '$typeNameString ${JS('', '#[#]', names, i)}';
+      }
+      buffer += '}';
+    }
+
+    var returnTypeName = typeName(returnType);
+    buffer += ') => $returnTypeName';
+    _stringValue = buffer;
+    return buffer;
+  }
+
+  @JSExportName('is')
+  bool is_T(obj) {
+    if (JS('!', 'typeof # == "function"', obj)) {
+      var actual = JS('', '#[#]', obj, _runtimeType);
+      // If there's no actual type, it's a JS function.
+      // Allow them to subtype all Dart function types.
+      return actual == null || isSubtypeOf(actual, this);
+    }
+    return false;
+  }
+
+  @JSExportName('as')
+  as_T(obj, [@notNull bool isImplicit = false]) {
+    if (obj == null) return obj;
+    if (JS('!', 'typeof # == "function"', obj)) {
+      var actual = JS('', '#[#]', obj, _runtimeType);
+      // If there's no actual type, it's a JS function.
+      // Allow them to subtype all Dart function types.
+      if (actual == null || isSubtypeOf(actual, this)) {
+        return obj;
+      }
+    }
+    return castError(obj, this, isImplicit);
+  }
+
+  @JSExportName('_check')
+  check_T(obj) => as_T(obj, true);
+}
+
+/// A type variable, used by [GenericFunctionType] to represent a type formal.
+class TypeVariable extends DartType {
+  final String name;
+
+  TypeVariable(this.name);
+
+  toString() => name;
+}
+
+class GenericFunctionType extends AbstractFunctionType {
+  final _instantiateTypeParts;
+  final int formalCount;
+  final _instantiateTypeBounds;
+  List<TypeVariable> _typeFormals;
+
+  GenericFunctionType(instantiateTypeParts, this._instantiateTypeBounds)
+      : _instantiateTypeParts = instantiateTypeParts,
+        formalCount = JS('!', '#.length', instantiateTypeParts);
+
+  List<TypeVariable> get typeFormals {
+    if (_typeFormals != null) return _typeFormals;
+    return _typeFormals = _typeFormalsFromFunction(_instantiateTypeParts);
+  }
+
+  /// `true` if there are bounds on any of the generic type parameters.
+  get hasTypeBounds => _instantiateTypeBounds != null;
+
+  /// Checks that [typeArgs] satisfies the upper bounds of the [typeFormals],
+  /// and throws a [TypeError] if they do not.
+  void checkBounds(List typeArgs) {
+    // If we don't have explicit type parameter bounds, the bounds default to
+    // a top type, so there's nothing to check here.
+    if (!hasTypeBounds) return;
+
+    var bounds = instantiateTypeBounds(typeArgs);
+    var typeFormals = this.typeFormals;
+    for (var i = 0; i < typeArgs.length; i++) {
+      checkTypeBound(typeArgs[i], bounds[i], typeFormals[i].name);
+    }
+  }
+
+  FunctionType instantiate(typeArgs) {
+    var parts = JS('', '#.apply(null, #)', _instantiateTypeParts, typeArgs);
+    return FunctionType.create(
+        JS('', '#[0]', parts), JS('', '#[1]', parts), JS('', '#[2]', parts));
+  }
+
+  List instantiateTypeBounds(List typeArgs) {
+    if (!hasTypeBounds) {
+      // The Dart 1 spec says omitted type parameters have an upper bound of
+      // Object. However Dart 2 uses `dynamic` for the purpose of instantiate to
+      // bounds, so we use that here.
+      return List.filled(formalCount, _dynamic);
+    }
+    // Bounds can be recursive or depend on other type parameters, so we need to
+    // apply type arguments and return the resulting bounds.
+    return JS('List', '#.apply(null, #)', _instantiateTypeBounds, typeArgs);
+  }
+
+  toString() {
+    String s = "<";
+    var typeFormals = this.typeFormals;
+    var typeBounds = instantiateTypeBounds(typeFormals);
+    for (int i = 0, n = typeFormals.length; i < n; i++) {
+      if (i != 0) s += ", ";
+      s += JS<String>('!', '#[#].name', typeFormals, i);
+      var bound = typeBounds[i];
+      if (JS('!', '# !== # && # !== #', bound, dynamic, bound, Object)) {
+        s += " extends $bound";
+      }
+    }
+    s += ">" + instantiate(typeFormals).toString();
+    return s;
+  }
+
+  /// Given a [DartType] [type], if [type] is an uninstantiated
+  /// parameterized type then instantiate the parameters to their
+  /// bounds and return those type arguments.
+  ///
+  /// See the issue for the algorithm description:
+  /// <https://github.com/dart-lang/sdk/issues/27526#issuecomment-260021397>
+  List instantiateDefaultBounds() {
+    var typeFormals = this.typeFormals;
+
+    // All type formals
+    var all = HashMap<Object, int>.identity();
+    // ground types, by index.
+    //
+    // For each index, this will be a ground type for the corresponding type
+    // formal if known, or it will be the original TypeVariable if we are still
+    // solving for it. This array is passed to `instantiateToBounds` as we are
+    // progressively solving for type variables.
+    var defaults = List<Object>(typeFormals.length);
+    // not ground
+    var partials = Map<TypeVariable, Object>.identity();
+
+    var typeBounds = this.instantiateTypeBounds(typeFormals);
+    for (var i = 0; i < typeFormals.length; i++) {
+      var typeFormal = typeFormals[i];
+      var bound = typeBounds[i];
+      all[typeFormal] = i;
+      if (identical(bound, _dynamic)) {
+        defaults[i] = bound;
+      } else {
+        defaults[i] = typeFormal;
+        partials[typeFormal] = bound;
+      }
+    }
+
+    bool hasFreeFormal(Object t) {
+      if (partials.containsKey(t)) return true;
+
+      // Generic classes and typedefs.
+      var typeArgs = getGenericArgs(t);
+      if (typeArgs != null) return typeArgs.any(hasFreeFormal);
+
+      if (t is GenericFunctionType) {
+        return hasFreeFormal(t.instantiate(t.typeFormals));
+      }
+
+      if (t is FunctionType) {
+        return hasFreeFormal(t.returnType) || t.args.any(hasFreeFormal);
+      }
+
+      return false;
+    }
+
+    var hasProgress = true;
+    while (hasProgress) {
+      hasProgress = false;
+      for (var typeFormal in partials.keys) {
+        var partialBound = partials[typeFormal];
+        if (!hasFreeFormal(partialBound)) {
+          int index = all[typeFormal];
+          defaults[index] = instantiateTypeBounds(defaults)[index];
+          partials.remove(typeFormal);
+          hasProgress = true;
+          break;
+        }
+      }
+    }
+
+    // If we stopped making progress, and not all types are ground,
+    // then the whole type is malbounded and an error should be reported
+    // if errors are requested, and a partially completed type should
+    // be returned.
+    if (partials.isNotEmpty) {
+      throwTypeError('Instantiate to bounds failed for type with '
+          'recursive generic bounds: ${typeName(this)}. '
+          'Try passing explicit type arguments.');
+    }
+    return defaults;
+  }
+
+  @notNull
+  @JSExportName('is')
+  bool is_T(obj) {
+    if (JS('!', 'typeof # == "function"', obj)) {
+      var actual = JS('', '#[#]', obj, _runtimeType);
+      return actual != null && isSubtypeOf(actual, this);
+    }
+    return false;
+  }
+
+  @JSExportName('as')
+  as_T(obj) {
+    if (obj == null || is_T(obj)) return obj;
+    return castError(obj, this, false);
+  }
+
+  @JSExportName('_check')
+  check_T(obj) {
+    if (obj == null || is_T(obj)) return obj;
+    return castError(obj, this, true);
+  }
+}
+
+List<TypeVariable> _typeFormalsFromFunction(Object typeConstructor) {
+  // Extract parameter names from the function parameters.
+  //
+  // This is not robust in general for user-defined JS functions, but it
+  // should handle the functions generated by our compiler.
+  //
+  // TODO(jmesserly): names of TypeVariables are only used for display
+  // purposes, such as when an error happens or if someone calls
+  // `Type.toString()`. So we could recover them lazily rather than eagerly.
+  // Alternatively we could synthesize new names.
+  String str = JS('!', '#.toString()', typeConstructor);
+  var hasParens = str[0] == '(';
+  var end = str.indexOf(hasParens ? ')' : '=>');
+  if (hasParens) {
+    return str
+        .substring(1, end)
+        .split(',')
+        .map((n) => TypeVariable(n.trim()))
+        .toList();
+  } else {
+    return [TypeVariable(str.substring(0, end).trim())];
+  }
+}
+
+/// Create a function type.
+FunctionType fnType(returnType, List args, [@undefined extra]) =>
+    FunctionType.create(returnType, args, extra);
+
+/// Creates a generic function type from [instantiateFn] and [typeBounds].
+///
+/// A function type consists of two things:
+/// * An instantiate function that takes type arguments and returns the
+///   function signature in the form of a two element list. The first element
+///   is the return type. The second element is a list of the argument types.
+/// * A function that returns a list of upper bound constraints for each of
+///   the type formals.
+///
+/// Both functions accept the type parameters, allowing us to substitute values.
+/// The upper bound constraints can be omitted if all of the type parameters use
+/// the default upper bound.
+///
+/// For example given the type <T extends Iterable<T>>(T) -> T, we can declare
+/// this type with `gFnType(T => [T, [T]], T => [Iterable$(T)])`.
+gFnType(instantiateFn, typeBounds) =>
+    GenericFunctionType(instantiateFn, typeBounds);
+
+/// TODO(vsm): Remove when mirrors is deprecated.
+/// This is a temporary workaround to support dart:mirrors, which doesn't
+/// understand generic methods.
+getFunctionTypeMirror(AbstractFunctionType type) {
+  if (type is GenericFunctionType) {
+    var typeArgs = List.filled(type.formalCount, dynamic);
+    return type.instantiate(typeArgs);
+  }
+  return type;
+}
+
+/// Whether the given JS constructor [obj] is a Dart class type.
+@notNull
+bool isType(obj) => JS('', '#[#] === #', obj, _runtimeType, Type);
+
+void checkTypeBound(
+    @notNull Object type, @notNull Object bound, @notNull String name) {
+  if (!isSubtypeOf(type, bound)) {
+    throwTypeError('type `$type` does not extend `$bound` of `$name`.');
+  }
+}
+
+@notNull
+String typeName(type) => JS('', '''(() => {
+  if ($type === void 0) return "undefined type";
+  if ($type === null) return "null type";
+  // Non-instance types
+  if ($type instanceof $DartType) {
+    return $type.toString();
+  }
+
+  // Instance types
+  let tag = $type[$_runtimeType];
+  if (tag === $Type) {
+    let name = $type.name;
+    let args = ${getGenericArgs(type)};
+    if (args == null) return name;
+
+    if (${getGenericClass(type)} == ${getGenericClass(JSArray)}) name = 'List';
+
+    let result = name;
+    result += '<';
+    for (let i = 0; i < args.length; ++i) {
+      if (i > 0) result += ', ';
+      result += $typeName(args[i]);
+    }
+    result += '>';
+    return result;
+  }
+  if (tag) return "Not a type: " + tag.name;
+  return "JSObject<" + $type.name + ">";
+})()''');
+
+/// Returns true if [ft1] <: [ft2].
+_isFunctionSubtype(ft1, ft2) => JS('', '''(() => {
+  let ret1 = $ft1.returnType;
+  let ret2 = $ft2.returnType;
+
+  let args1 = $ft1.args;
+  let args2 = $ft2.args;
+
+  if (args1.length > args2.length) {
+    return false;
+  }
+
+  for (let i = 0; i < args1.length; ++i) {
+    if (!$_isSubtype(args2[i], args1[i])) {
+      return false;
+    }
+  }
+
+  let optionals1 = $ft1.optionals;
+  let optionals2 = $ft2.optionals;
+
+  if (args1.length + optionals1.length < args2.length + optionals2.length) {
+    return false;
+  }
+
+  let j = 0;
+  for (let i = args1.length; i < args2.length; ++i, ++j) {
+    if (!$_isSubtype(args2[i], optionals1[j])) {
+      return false;
+    }
+  }
+
+  for (let i = 0; i < optionals2.length; ++i, ++j) {
+    if (!$_isSubtype(optionals2[i], optionals1[j])) {
+      return false;
+    }
+  }
+
+  let named1 = $ft1.named;
+  let named2 = $ft2.named;
+
+  let names = $getOwnPropertyNames(named2);
+  for (let i = 0; i < names.length; ++i) {
+    let name = names[i];
+    let n1 = named1[name];
+    let n2 = named2[name];
+    if (n1 === void 0) {
+      return false;
+    }
+    if (!$_isSubtype(n2, n1)) {
+      return false;
+    }
+  }
+
+  return $_isSubtype(ret1, ret2);
+})()''');
+
+/// Returns true if [t1] <: [t2].
+@notNull
+bool isSubtypeOf(Object t1, Object t2) {
+  // TODO(jmesserly): we've optimized `is`/`as`/implicit type checks, so they're
+  // dispatched on the type. Can we optimize the subtype relation too?
+  Object map;
+  if (JS('!', '!#.hasOwnProperty(#)', t1, _subtypeCache)) {
+    JS('', '#[#] = # = new Map()', t1, _subtypeCache, map);
+    _cacheMaps.add(map);
+  } else {
+    map = JS('', '#[#]', t1, _subtypeCache);
+    bool result = JS('', '#.get(#)', map, t2);
+    if (JS('!', '# !== void 0', result)) return result;
+  }
+  var result = _isSubtype(t1, t2);
+  JS('', '#.set(#, #)', map, t2, result);
+  return result;
+}
+
+final _subtypeCache = JS('', 'Symbol("_subtypeCache")');
+
+@notNull
+bool _isBottom(type) => JS('!', '# == # || # == #', type, bottom, type, Null);
+
+@notNull
+bool _isTop(type) {
+  if (_isFutureOr(type)) {
+    return _isTop(JS('', '#[0]', getGenericArgs(type)));
+  }
+  return JS('!', '# == # || # == # || # == #', type, Object, type, dynamic,
+      type, void_);
+}
+
+@notNull
+bool _isFutureOr(type) =>
+    identical(getGenericClass(type), getGenericClass(FutureOr));
+
+bool _isSubtype(t1, t2) => JS('', '''(() => {
+  if ($t1 === $t2) {
+    return true;
+  }
+
+  // Trivially true.
+  if (${_isTop(t2)} || ${_isBottom(t1)}) {
+    return true;
+  }
+
+  // Trivially false.
+  if (${_isTop(t1)} || ${_isBottom(t2)}) {
+    return false;
+  }
+
+  // Handle FutureOr<T> union type.
+  if (${_isFutureOr(t1)}) {
+    let t1TypeArg = ${getGenericArgs(t1)}[0];
+    if (${_isFutureOr(t2)}) {
+      let t2TypeArg = ${getGenericArgs(t2)}[0];
+      // FutureOr<A> <: FutureOr<B> iff A <: B
+      return $_isSubtype(t1TypeArg, t2TypeArg);
+    }
+
+    // given t1 is Future<A> | A, then:
+    // (Future<A> | A) <: t2 iff Future<A> <: t2 and A <: t2.
+    let t1Future = ${getGenericClass(Future)}(t1TypeArg);
+    // Known to handle the case FutureOr<Null> <: Future<Null>.
+    return $_isSubtype(t1Future, $t2) && $_isSubtype(t1TypeArg, $t2);
+  }
+
+  if ($_isFutureOr($t2)) {
+    // given t2 is Future<A> | A, then:
+    // t1 <: (Future<A> | A) iff t1 <: Future<A> or t1 <: A
+    let t2TypeArg = ${getGenericArgs(t2)}[0];
+    let t2Future = ${getGenericClass(Future)}(t2TypeArg);
+    return $_isSubtype($t1, t2Future) || $_isSubtype($t1, t2TypeArg);
+  }
+
+  // "Traditional" name-based subtype check.  Avoid passing
+  // function types to the class subtype checks, since we don't
+  // currently distinguish between generic typedefs and classes.
+  if (!($t2 instanceof $AbstractFunctionType)) {
+    // t2 is an interface type.
+
+    if ($t1 instanceof $AbstractFunctionType) {
+      // Function types are only subtypes of interface types `Function` (and top
+      // types, handled already above).
+      return $t2 === $Function;
+    }
+
+    // All JS types are subtypes of anonymous JS types.
+    if ($t1 === $jsobject && $t2 instanceof $AnonymousJSType) {
+      return true;
+    }
+
+    // Compare two interface types.
+    return ${_isInterfaceSubtype(t1, t2)};
+  }
+
+  // Function subtyping.
+  if (!($t1 instanceof $AbstractFunctionType)) {
+    return false;
+  }
+
+  // Handle generic functions.
+  if ($t1 instanceof $GenericFunctionType) {
+    if (!($t2 instanceof $GenericFunctionType)) {
+      return false;
+    }
+
+    // Given generic functions g1 and g2, g1 <: g2 iff:
+    //
+    //     g1<TFresh> <: g2<TFresh>
+    //
+    // where TFresh is a list of fresh type variables that both g1 and g2 will
+    // be instantiated with.
+    let formalCount = $t1.formalCount;
+    if (formalCount !== $t2.formalCount) {
+      return false;
+    }
+
+    // Using either function's type formals will work as long as they're both
+    // instantiated with the same ones. The instantiate operation is guaranteed
+    // to avoid capture because it does not depend on its TypeVariable objects,
+    // rather it uses JS function parameters to ensure correct binding.
+    let fresh = $t2.typeFormals;
+
+    // Without type bounds all will instantiate to dynamic. Only need to check
+    // further if at least one of the functions has type bounds.
+    if ($t1.hasTypeBounds || $t2.hasTypeBounds) {
+      // Check the bounds of the type parameters of g1 and g2.
+      // given a type parameter `T1 extends U1` from g1, and a type parameter
+      // `T2 extends U2` from g2, we must ensure that:
+      //
+      //      U2 == U1
+      //
+      // (Note there is no variance in the type bounds of type parameters of
+      // generic functions).
+      let t1Bounds = $t1.instantiateTypeBounds(fresh);
+      let t2Bounds = $t2.instantiateTypeBounds(fresh);
+      for (let i = 0; i < formalCount; i++) {
+        if (t2Bounds[i] != t1Bounds[i]) {
+          return false;
+        }
+      }
+    }
+
+    $t1 = $t1.instantiate(fresh);
+    $t2 = $t2.instantiate(fresh);
+  } else if ($t2 instanceof $GenericFunctionType) {
+    return false;
+  }
+
+  // Handle non-generic functions.
+  return ${_isFunctionSubtype(t1, t2)};
+})()''');
+
+bool _isInterfaceSubtype(t1, t2) => JS('', '''(() => {
+  // If we have lazy JS types, unwrap them.  This will effectively
+  // reduce to a prototype check below.
+  if ($t1 instanceof $LazyJSType) $t1 = $t1.rawJSTypeForCheck();
+  if ($t2 instanceof $LazyJSType) $t2 = $t2.rawJSTypeForCheck();
+
+  if ($t1 === $t2) {
+    return true;
+  }
+  if ($t1 === $Object) {
+    return false;
+  }
+
+  // Classes cannot subtype `Function` or vice versa.
+  if ($t1 === $Function || $t2 === $Function) {
+    return false;
+  }
+
+  // If t1 is a JS Object, we may not hit core.Object.
+  if ($t1 == null) {
+    return $t2 == $Object || $t2 == $dynamic;
+  }
+
+  // Check if t1 and t2 have the same raw type.  If so, check covariance on
+  // type parameters.
+  let raw1 = $getGenericClass($t1);
+  let raw2 = $getGenericClass($t2);
+  if (raw1 != null && raw1 == raw2) {
+    let typeArguments1 = $getGenericArgs($t1);
+    let typeArguments2 = $getGenericArgs($t2);
+    if (typeArguments1.length != typeArguments2.length) {
+      $assertFailed();
+    }
+    for (let i = 0; i < typeArguments1.length; ++i) {
+      if (!$_isSubtype(typeArguments1[i], typeArguments2[i])) {
+        return false;
+      }
+    }
+    return true;
+  }
+
+  if ($_isInterfaceSubtype(t1.__proto__, $t2)) {
+    return true;
+  }
+
+  // Check mixin.
+  let m1 = $getMixin($t1);
+  if (m1 != null && $_isInterfaceSubtype(m1, $t2)) {
+    return true;
+  }
+
+  // Check interfaces.
+  let getInterfaces = $getImplements($t1);
+  if (getInterfaces) {
+    for (let i1 of getInterfaces()) {
+      if ($_isInterfaceSubtype(i1, $t2)) {
+        return true;
+      }
+    }
+  }
+  return false;
+})()''');
+
+Object extractTypeArguments<T>(T instance, Function f) {
+  if (instance == null) {
+    throw ArgumentError('Cannot extract type of null instance.');
+  }
+  var type = unwrapType(T);
+  if (type is AbstractFunctionType || _isFutureOr(type)) {
+    throw ArgumentError('Cannot extract from non-class type ($type).');
+  }
+  var typeArguments = getGenericArgs(type);
+  if (typeArguments.isEmpty) {
+    throw ArgumentError('Cannot extract from non-generic type ($type).');
+  }
+  var supertype = _getMatchingSupertype(getReifiedType(instance), type);
+  // The signature of this method guarantees that instance is a T, so we
+  // should have a valid non-empty list at this point.
+  assert(supertype != null);
+  var typeArgs = getGenericArgs(supertype);
+  assert(typeArgs != null && typeArgs.isNotEmpty);
+  return dgcall(f, typeArgs, []);
+}
+
+/// Infers type variables based on a series of [trySubtypeMatch] calls, followed
+/// by [getInferredTypes] to return the type.
+class _TypeInferrer {
+  final Map<TypeVariable, TypeConstraint> _typeVariables;
+
+  /// Creates a [TypeConstraintGatherer] which is prepared to gather type
+  /// constraints for the given type parameters.
+  _TypeInferrer(Iterable<TypeVariable> typeVariables)
+      : _typeVariables = Map.fromIterables(
+            typeVariables, typeVariables.map((_) => TypeConstraint()));
+
+  /// Returns the inferred types based on the current constraints.
+  List<Object> getInferredTypes() {
+    var result = List<Object>();
+    for (var constraint in _typeVariables.values) {
+      // Prefer the known bound, if any.
+      if (constraint.lower != null) {
+        result.add(constraint.lower);
+      } else if (constraint.upper != null) {
+        result.add(constraint.upper);
+      } else {
+        return null;
+      }
+    }
+    return result;
+  }
+
+  /// Tries to match [subtype] against [supertype].
+  ///
+  /// If the match succeeds, the resulting type constraints are recorded for
+  /// later use by [computeConstraints].  If the match fails, the set of type
+  /// constraints is unchanged.
+  bool trySubtypeMatch(Object subtype, Object supertype) =>
+      _isSubtypeMatch(subtype, supertype);
+
+  void _constrainLower(TypeVariable parameter, Object lower) {
+    _typeVariables[parameter]._constrainLower(lower);
+  }
+
+  void _constrainUpper(TypeVariable parameter, Object upper) {
+    _typeVariables[parameter]._constrainUpper(upper);
+  }
+
+  bool _isFunctionSubtypeMatch(FunctionType subtype, FunctionType supertype) {
+    // A function type `(M0,..., Mn, [M{n+1}, ..., Mm]) -> R0` is a subtype
+    // match for a function type `(N0,..., Nk, [N{k+1}, ..., Nr]) -> R1` with
+    // respect to `L` under constraints `C0 + ... + Cr + C`
+    // - If `R0` is a subtype match for a type `R1` with respect to `L` under
+    //   constraints `C`:
+    // - If `n <= k` and `r <= m`.
+    // - And for `i` in `0...r`, `Ni` is a subtype match for `Mi` with respect
+    //   to `L` under constraints `Ci`.
+    // Function types with named parameters are treated analogously to the
+    // positional parameter case above.
+    // A generic function type `<T0 extends B0, ..., Tn extends Bn>F0` is a
+    // subtype match for a generic function type `<S0 extends B0, ..., Sn
+    // extends Bn>F1` with respect to `L` under constraints `Cl`:
+    // - If `F0[Z0/T0, ..., Zn/Tn]` is a subtype match for `F0[Z0/S0, ...,
+    //   Zn/Sn]` with respect to `L` under constraints `C`, where each `Zi` is a
+    //   fresh type variable with bound `Bi`.
+    // - And `Cl` is `C` with each constraint replaced with its closure with
+    //   respect to `[Z0, ..., Zn]`.
+    if (subtype.requiredParameterCount > supertype.requiredParameterCount) {
+      return false;
+    }
+    if (subtype.positionalParameterCount < supertype.positionalParameterCount) {
+      return false;
+    }
+    // Test the return types.
+    if (supertype.returnType is! VoidType &&
+        !_isSubtypeMatch(subtype.returnType, supertype.returnType)) {
+      return false;
+    }
+
+    // Test the parameter types.
+    for (int i = 0, n = supertype.positionalParameterCount; i < n; ++i) {
+      if (!_isSubtypeMatch(supertype.getPositionalParameter(i),
+          subtype.getPositionalParameter(i))) {
+        return false;
+      }
+    }
+    var supertypeNamed = supertype.getNamedParameters();
+    var subtypeNamed = supertype.getNamedParameters();
+    for (var name in supertypeNamed.keys) {
+      var subtypeParamType = subtypeNamed[name];
+      if (subtypeParamType == null) return false;
+      if (!_isSubtypeMatch(supertypeNamed[name], subtypeParamType)) {
+        return false;
+      }
+    }
+    return true;
+  }
+
+  bool _isInterfaceSubtypeMatch(Object subtype, Object supertype) {
+    // A type `P<M0, ..., Mk>` is a subtype match for `P<N0, ..., Nk>` with
+    // respect to `L` under constraints `C0 + ... + Ck`:
+    // - If `Mi` is a subtype match for `Ni` with respect to `L` under
+    //   constraints `Ci`.
+    // A type `P<M0, ..., Mk>` is a subtype match for `Q<N0, ..., Nj>` with
+    // respect to `L` under constraints `C`:
+    // - If `R<B0, ..., Bj>` is the superclass of `P<M0, ..., Mk>` and `R<B0,
+    //   ..., Bj>` is a subtype match for `Q<N0, ..., Nj>` with respect to `L`
+    //   under constraints `C`.
+    // - Or `R<B0, ..., Bj>` is one of the interfaces implemented by `P<M0, ...,
+    //   Mk>` (considered in lexical order) and `R<B0, ..., Bj>` is a subtype
+    //   match for `Q<N0, ..., Nj>` with respect to `L` under constraints `C`.
+    // - Or `R<B0, ..., Bj>` is a mixin into `P<M0, ..., Mk>` (considered in
+    //   lexical order) and `R<B0, ..., Bj>` is a subtype match for `Q<N0, ...,
+    //   Nj>` with respect to `L` under constraints `C`.
+
+    // Note that since kernel requires that no class may only appear in the set
+    // of supertypes of a given type more than once, the order of the checks
+    // above is irrelevant; we just need to find the matched superclass,
+    // substitute, and then iterate through type variables.
+    var matchingSupertype = _getMatchingSupertype(subtype, supertype);
+    if (matchingSupertype == null) return false;
+
+    var matchingTypeArgs = getGenericArgs(matchingSupertype);
+    var supertypeTypeArgs = getGenericArgs(supertype);
+    for (int i = 0; i < supertypeTypeArgs.length; i++) {
+      if (!_isSubtypeMatch(matchingTypeArgs[i], supertypeTypeArgs[i])) {
+        return false;
+      }
+    }
+    return true;
+  }
+
+  bool _isNull(Object type) => identical(type, unwrapType(Null));
+
+  /// Attempts to match [subtype] as a subtype of [supertype], gathering any
+  /// constraints discovered in the process.
+  ///
+  /// If a set of constraints was found, `true` is returned and the caller
+  /// may proceed to call [computeConstraints].  Otherwise, `false` is returned.
+  ///
+  /// In the case where `false` is returned, some bogus constraints may have
+  /// been added to [_protoConstraints].  It is the caller's responsibility to
+  /// discard them if necessary.
+  bool _isSubtypeMatch(Object subtype, Object supertype) {
+    // A type variable `T` in `L` is a subtype match for any type schema `Q`:
+    // - Under constraint `T <: Q`.
+    if (subtype is TypeVariable && _typeVariables.containsKey(subtype)) {
+      _constrainUpper(subtype, supertype);
+      return true;
+    }
+    // A type schema `Q` is a subtype match for a type variable `T` in `L`:
+    // - Under constraint `Q <: T`.
+    if (supertype is TypeVariable && _typeVariables.containsKey(supertype)) {
+      _constrainLower(supertype, subtype);
+      return true;
+    }
+    // Any two equal types `P` and `Q` are subtype matches under no constraints.
+    // Note: to avoid making the algorithm quadratic, we just check for
+    // identical().  If P and Q are equal but not identical, recursing through
+    // the types will give the proper result.
+    if (identical(subtype, supertype)) return true;
+    // Any type `P` is a subtype match for `dynamic`, `Object`, or `void` under
+    // no constraints.
+    if (_isTop(supertype)) return true;
+    // `Null` is a subtype match for any type `Q` under no constraints.
+    // Note that nullable types will change this.
+    if (_isNull(subtype)) return true;
+
+    // Handle FutureOr<T> union type.
+    if (_isFutureOr(subtype)) {
+      var subtypeArg = getGenericArgs(subtype)[0];
+      if (_isFutureOr(supertype)) {
+        // `FutureOr<P>` is a subtype match for `FutureOr<Q>` with respect to `L`
+        // under constraints `C`:
+        // - If `P` is a subtype match for `Q` with respect to `L` under constraints
+        //   `C`.
+        var supertypeArg = getGenericArgs(supertype)[0];
+        return _isSubtypeMatch(subtypeArg, supertypeArg);
+      }
+
+      // `FutureOr<P>` is a subtype match for `Q` with respect to `L` under
+      // constraints `C0 + C1`:
+      // - If `Future<P>` is a subtype match for `Q` with respect to `L` under
+      //   constraints `C0`.
+      // - And `P` is a subtype match for `Q` with respect to `L` under
+      //   constraints `C1`.
+      var subtypeFuture = JS('!', '#(#)', getGenericClass(Future), subtypeArg);
+      return _isSubtypeMatch(subtypeFuture, supertype) &&
+          _isSubtypeMatch(subtypeArg, supertype);
+    }
+
+    if (_isFutureOr(supertype)) {
+      // `P` is a subtype match for `FutureOr<Q>` with respect to `L` under
+      // constraints `C`:
+      // - If `P` is a subtype match for `Future<Q>` with respect to `L` under
+      //   constraints `C`.
+      // - Or `P` is not a subtype match for `Future<Q>` with respect to `L` under
+      //   constraints `C`
+      //   - And `P` is a subtype match for `Q` with respect to `L` under
+      //     constraints `C`
+      var supertypeArg = getGenericArgs(supertype)[0];
+      var supertypeFuture =
+          JS('!', '#(#)', getGenericClass(Future), supertypeArg);
+      return _isSubtypeMatch(subtype, supertypeFuture) ||
+          _isSubtypeMatch(subtype, supertypeArg);
+    }
+
+    // A type variable `T` not in `L` with bound `P` is a subtype match for the
+    // same type variable `T` with bound `Q` with respect to `L` under
+    // constraints `C`:
+    // - If `P` is a subtype match for `Q` with respect to `L` under constraints
+    //   `C`.
+    if (subtype is TypeVariable) {
+      return supertype is TypeVariable && identical(subtype, supertype);
+    }
+    if (subtype is GenericFunctionType) {
+      if (supertype is GenericFunctionType) {
+        // Given generic functions g1 and g2, g1 <: g2 iff:
+        //
+        //     g1<TFresh> <: g2<TFresh>
+        //
+        // where TFresh is a list of fresh type variables that both g1 and g2 will
+        // be instantiated with.
+        var formalCount = subtype.formalCount;
+        if (formalCount != supertype.formalCount) return false;
+
+        // Using either function's type formals will work as long as they're
+        // both instantiated with the same ones. The instantiate operation is
+        // guaranteed to avoid capture because it does not depend on its
+        // TypeVariable objects, rather it uses JS function parameters to ensure
+        // correct binding.
+        var fresh = supertype.typeFormals;
+
+        // Check the bounds of the type parameters of g1 and g2.
+        // given a type parameter `T1 extends U1` from g1, and a type parameter
+        // `T2 extends U2` from g2, we must ensure that:
+        //
+        //      U2 <: U1
+        //
+        // (Note the reversal of direction -- type formal bounds are
+        // contravariant, similar to the function's formal parameter types).
+        //
+        var t1Bounds = subtype.instantiateTypeBounds(fresh);
+        var t2Bounds = supertype.instantiateTypeBounds(fresh);
+        // TODO(jmesserly): we could optimize for the common case of no bounds.
+        for (var i = 0; i < formalCount; i++) {
+          if (!_isSubtypeMatch(t2Bounds[i], t1Bounds[i])) {
+            return false;
+          }
+        }
+        return _isFunctionSubtypeMatch(
+            subtype.instantiate(fresh), supertype.instantiate(fresh));
+      } else {
+        return false;
+      }
+    } else if (supertype is GenericFunctionType) {
+      return false;
+    }
+
+    // A type `P` is a subtype match for `Function` with respect to `L` under no
+    // constraints:
+    // - If `P` implements a call method.
+    // - Or if `P` is a function type.
+    // TODO(paulberry): implement this case.
+    // A type `P` is a subtype match for a type `Q` with respect to `L` under
+    // constraints `C`:
+    // - If `P` is an interface type which implements a call method of type `F`,
+    //   and `F` is a subtype match for a type `Q` with respect to `L` under
+    //   constraints `C`.
+    // TODO(paulberry): implement this case.
+    if (subtype is FunctionType) {
+      if (supertype is! FunctionType) {
+        if (identical(supertype, unwrapType(Function)) ||
+            identical(supertype, unwrapType(Object))) {
+          return true;
+        } else {
+          return false;
+        }
+      }
+      if (supertype is FunctionType) {
+        return _isFunctionSubtypeMatch(subtype, supertype);
+      }
+    }
+    return _isInterfaceSubtypeMatch(subtype, supertype);
+  }
+
+  bool _isTop(Object type) =>
+      identical(type, _dynamic) ||
+      identical(type, void_) ||
+      identical(type, unwrapType(Object));
+}
+
+/// A constraint on a type parameter that we're inferring.
+class TypeConstraint {
+  /// The lower bound of the type being constrained.  This bound must be a
+  /// subtype of the type being constrained.
+  Object lower;
+
+  /// The upper bound of the type being constrained.  The type being constrained
+  /// must be a subtype of this bound.
+  Object upper;
+
+  void _constrainLower(Object type) {
+    if (lower != null) {
+      if (isSubtypeOf(lower, type)) {
+        // nothing to do, existing lower bound is lower than the new one.
+        return;
+      }
+      if (!isSubtypeOf(type, lower)) {
+        // Neither bound is lower and we don't have GLB, so use bottom type.
+        type = unwrapType(Null);
+      }
+    }
+    lower = type;
+  }
+
+  void _constrainUpper(Object type) {
+    if (upper != null) {
+      if (isSubtypeOf(type, upper)) {
+        // nothing to do, existing upper bound is higher than the new one.
+        return;
+      }
+      if (!isSubtypeOf(upper, type)) {
+        // Neither bound is higher and we don't have LUB, so use top type.
+        type = unwrapType(Object);
+      }
+    }
+    upper = type;
+  }
+
+  String toString() => '${typeName(lower)} <: <type> <: ${typeName(upper)}';
+}
+
+/// Finds a supertype of [subtype] that matches the class [supertype], but may
+/// contain different generic type arguments.
+Object _getMatchingSupertype(Object subtype, Object supertype) {
+  if (identical(subtype, supertype)) return supertype;
+  if (subtype == null || subtype == unwrapType(Object)) return null;
+
+  var subclass = getGenericClass(subtype);
+  var superclass = getGenericClass(supertype);
+  if (subclass != null && identical(subclass, superclass)) {
+    return subtype; // matching supertype found!
+  }
+
+  var result = _getMatchingSupertype(JS('', '#.__proto__', subtype), supertype);
+  if (result != null) return result;
+
+  // Check mixin.
+  var mixin = getMixin(subtype);
+  if (mixin != null) {
+    result = _getMatchingSupertype(mixin, supertype);
+    if (result != null) return result;
+  }
+
+  // Check interfaces.
+  var getInterfaces = getImplements(subtype);
+  if (getInterfaces != null) {
+    for (var iface in getInterfaces()) {
+      result = _getMatchingSupertype(iface, supertype);
+      if (result != null) return result;
+    }
+  }
+
+  return null;
+}
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/private/ddc_runtime/utils.dart b/sdk_nnbd/lib/_internal/js_dev_runtime/private/ddc_runtime/utils.dart
new file mode 100644
index 0000000..2c06179
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/private/ddc_runtime/utils.dart
@@ -0,0 +1,136 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart._runtime;
+
+/// This library defines a set of general javascript utilities for us
+/// by the Dart runtime.
+// TODO(ochafik): Rewrite some of these in Dart when possible.
+
+final Function(Object, Object, Object) defineProperty =
+    JS('', 'Object.defineProperty');
+
+defineValue(obj, name, value) {
+  defineAccessor(obj, name, value: value, configurable: true, writable: true);
+  return value;
+}
+
+final Function(Object, Object,
+    {Object get,
+    Object set,
+    Object value,
+    bool configurable,
+    bool writable}) defineAccessor = JS('', 'Object.defineProperty');
+
+final Function(Object, Object) getOwnPropertyDescriptor =
+    JS('', 'Object.getOwnPropertyDescriptor');
+
+final Iterable Function(Object) getOwnPropertyNames =
+    JS('', 'Object.getOwnPropertyNames');
+
+final Function(Object) getOwnPropertySymbols =
+    JS('', 'Object.getOwnPropertySymbols');
+
+final Function(Object) getPrototypeOf = JS('', 'Object.getPrototypeOf');
+
+/// This error indicates a strong mode specific failure, other than a type
+/// assertion failure (TypeError) or CastError.
+void throwTypeError(String message) {
+  throw TypeErrorImpl(message);
+}
+
+/// This error indicates a bug in the runtime or the compiler.
+void throwInternalError(String message) {
+  JS('', 'throw Error(#)', message);
+}
+
+Iterable getOwnNamesAndSymbols(obj) {
+  var names = getOwnPropertyNames(obj);
+  var symbols = getOwnPropertySymbols(obj);
+  return JS('', '#.concat(#)', names, symbols);
+}
+
+safeGetOwnProperty(obj, name) {
+  var desc = getOwnPropertyDescriptor(obj, name);
+  if (desc != null) return JS('', '#.value', desc);
+}
+
+/// Defines a lazy static field.
+/// After initial get or set, it will replace itself with a value property.
+// TODO(jmesserly): reusing descriptor objects has been shown to improve
+// performance in other projects (e.g. webcomponents.js ShadowDOM polyfill).
+defineLazyField(to, name, desc) => JS('', '''(() => {
+  const initializer = $desc.get;
+  let init = initializer;
+  let value = null;
+  $desc.get = function() {
+    if (init == null) return value;
+    let f = init;
+    init = $throwCyclicInitializationError;
+    if (f === init) f($name); // throw cycle error
+
+    // On the first (non-cyclic) execution, record the field so we can reset it
+    // later if needed (hot restart).
+    $_resetFields.push(() => {
+      init = initializer;
+      value = null;
+    });
+
+    // Try to evaluate the field, using try+catch to ensure we implement the
+    // correct Dart error semantics.
+    try {
+      value = f();
+      init = null;
+      return value;
+    } catch (e) {
+      init = null;
+      value = null;
+      throw e;
+    }
+  };
+  $desc.configurable = true;
+  if ($desc.set != null) {
+    $desc.set = function(x) {
+      init = null;
+      value = x;
+    };
+  }
+  return ${defineProperty(to, name, desc)};
+})()''');
+
+copyTheseProperties(to, from, names) {
+  for (int i = 0, n = JS('!', '#.length', names); i < n; ++i) {
+    var name = JS('', '#[#]', names, i);
+    if (name == 'constructor') continue;
+    copyProperty(to, from, name);
+  }
+  return to;
+}
+
+copyProperty(to, from, name) {
+  var desc = getOwnPropertyDescriptor(from, name);
+  if (JS('!', '# == Symbol.iterator', name)) {
+    // On native types, Symbol.iterator may already be present.
+    // TODO(jmesserly): investigate if we still need this.
+    // If so, we need to find a better solution.
+    // See https://github.com/dart-lang/sdk/issues/28324
+    var existing = getOwnPropertyDescriptor(to, name);
+    if (existing != null) {
+      if (JS('!', '#.writable', existing)) {
+        JS('', '#[#] = #.value', to, name, desc);
+      }
+      return;
+    }
+  }
+  defineProperty(to, name, desc);
+}
+
+@JSExportName('export')
+exportProperty(to, from, name) => copyProperty(to, from, name);
+
+/// Copy properties from source to destination object.
+/// This operation is commonly called `mixin` in JS.
+copyProperties(to, from) {
+  return copyTheseProperties(to, from, getOwnNamesAndSymbols(from));
+}
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/private/debugger.dart b/sdk_nnbd/lib/_internal/js_dev_runtime/private/debugger.dart
new file mode 100644
index 0000000..4618317
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/private/debugger.dart
@@ -0,0 +1,1016 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library dart._debugger;
+
+import 'dart:_foreign_helper' show JS;
+import 'dart:_interceptors' show JSArray;
+import 'dart:_js_helper' show InternalMap;
+import 'dart:_runtime' as dart;
+import 'dart:core';
+import 'dart:collection';
+import 'dart:html' as html;
+import 'dart:math';
+
+part 'profile.dart';
+
+/// JsonMLConfig object to pass to devtools to specify how an Object should
+/// be displayed. skipDart signals that an object should not be formatted
+/// by the Dart formatter. This is used to specify that an Object
+/// should just be displayed using the regular JavaScript view instead of a
+/// custom Dart view. For example, this is used to display the JavaScript view
+/// of a Dart Function as a child of the regular Function object. keyToString
+/// signals that a map key object should have its toString() displayed by
+/// the Dart formatter.
+///
+/// We'd like this to be an enum, but we can't because it's a dev_compiler bug.
+class JsonMLConfig {
+  const JsonMLConfig(this.name);
+
+  final String name;
+  static const none = JsonMLConfig("none");
+  static const skipDart = JsonMLConfig("skipDart");
+  static const keyToString = JsonMLConfig("keyToString");
+  static const asClass = JsonMLConfig("asClass");
+  static const asObject = JsonMLConfig("asObject");
+  static const asMap = JsonMLConfig("asMap");
+  toString() => "JsonMLConfig($name)";
+}
+
+int _maxSpanLength = 100;
+var _devtoolsFormatter = JsonMLFormatter(DartFormatter());
+
+/// We truncate a toString() longer than [maxStringLength].
+int maxFormatterStringLength = 100;
+
+String _typeof(object) => JS<String>('!', 'typeof #', object);
+
+List<String> getOwnPropertyNames(object) =>
+    JSArray<String>.of(dart.getOwnPropertyNames(object));
+
+List getOwnPropertySymbols(object) =>
+    JS('List', 'Object.getOwnPropertySymbols(#)', object);
+
+// TODO(jacobr): move this to dart:js and fully implement.
+class JSNative {
+  // Name may be a String or a Symbol.
+  static getProperty(object, name) => JS('', '#[#]', object, name);
+  // Name may be a String or a Symbol.
+  static setProperty(object, name, value) =>
+      JS('', '#[#]=#', object, name, value);
+}
+
+void addMetadataChildren(object, Set<NameValuePair> ret) {
+  ret.add(NameValuePair(
+      name: "[[class]]",
+      value: dart.getReifiedType(object),
+      config: JsonMLConfig.asClass));
+}
+
+/// Add properties from a signature definition [sig] for [object].
+/// Walk the prototype chain if [walkProtypeChain] is set.
+/// Tag types on function typed properties of [object] if [tagTypes] is set.
+///
+void addPropertiesFromSignature(
+    sig, Set<NameValuePair> properties, object, bool walkPrototypeChain,
+    {tagTypes = false}) {
+  // Including these property names doesn't add any value and just clutters
+  // the debugger output.
+  // TODO(jacobr): consider adding runtimeType to this list.
+  var skippedNames = Set()..add('hashCode');
+  var objectPrototype = JS('', 'Object.prototype');
+  while (sig != null && !identical(sig, objectPrototype)) {
+    for (var symbol in getOwnPropertySymbols(sig)) {
+      var dartName = symbolName(symbol);
+      String dartXPrefix = 'dartx.';
+      if (dartName.startsWith(dartXPrefix)) {
+        dartName = dartName.substring(dartXPrefix.length);
+      }
+      if (skippedNames.contains(dartName)) continue;
+      var value = safeGetProperty(object, symbol);
+      // Tag the function with its runtime type.
+      if (tagTypes && _typeof(value) == 'function') {
+        dart.fn(value, JS('', '#[#]', sig, symbol));
+      }
+      properties.add(NameValuePair(name: dartName, value: value));
+    }
+
+    for (var name in getOwnPropertyNames(sig)) {
+      var value = safeGetProperty(object, name);
+      if (skippedNames.contains(name)) continue;
+      // Tag the function with its runtime type.
+      if (tagTypes && _typeof(value) == 'function') {
+        dart.fn(value, JS('', '#[#]', sig, name));
+      }
+      properties.add(NameValuePair(name: name, value: value));
+    }
+
+    if (!walkPrototypeChain) break;
+
+    sig = dart.getPrototypeOf(sig);
+  }
+}
+
+/// Sort properties sorting public names before private names.
+List<NameValuePair> sortProperties(Iterable<NameValuePair> properties) {
+  var sortedProperties = properties.toList();
+
+  sortedProperties.sort((a, b) {
+    var aPrivate = a.name.startsWith('_');
+    var bPrivate = b.name.startsWith('_');
+    if (aPrivate != bPrivate) return aPrivate ? 1 : -1;
+    return a.name.compareTo(b.name);
+  });
+  return sortedProperties;
+}
+
+String getObjectTypeName(object) {
+  var reifiedType = dart.getReifiedType(object);
+  if (reifiedType == null) {
+    if (_typeof(object) == 'function') {
+      return '[[Raw JavaScript Function]]';
+    }
+    return '<Error getting type name>';
+  }
+  return getTypeName(reifiedType);
+}
+
+String getTypeName(type) {
+  // TODO(jacobr): it would be nice if there was a way we could distinguish
+  // between a List<dynamic> created from Dart and an Array passed in from
+  // JavaScript.
+  return dart.typeName(type);
+}
+
+String safePreview(object, config) {
+  try {
+    var preview = _devtoolsFormatter._simpleFormatter.preview(object, config);
+    if (preview != null) return preview;
+    return object.toString();
+  } catch (e) {
+    return '<Exception thrown> $e';
+  }
+}
+
+String symbolName(symbol) {
+  var name = symbol.toString();
+  assert(name.startsWith('Symbol('));
+  return name.substring('Symbol('.length, name.length - 1);
+}
+
+bool hasMethod(object, String name) {
+  try {
+    return dart.hasMethod(object, name);
+  } catch (e) {
+    return false;
+  }
+}
+
+/// [JsonMLFormatter] consumes [NameValuePair] objects and
+class NameValuePair {
+  NameValuePair(
+      {this.name,
+      this.value,
+      this.config = JsonMLConfig.none,
+      this.hideName = false});
+
+  // Define equality and hashCode so that NameValuePair can be used
+  // in a Set to dedupe entries with duplicate names.
+  bool operator ==(other) {
+    if (other is! NameValuePair) return false;
+    if (this.hideName || other.hideName) return identical(this, other);
+    return other.name == name;
+  }
+
+  int get hashCode => name.hashCode;
+
+  final String name;
+  final Object value;
+  final JsonMLConfig config;
+  final bool hideName;
+
+  String get displayName => hideName ? '' : name;
+}
+
+class MapEntry {
+  MapEntry({this.key, this.value});
+
+  final Object key;
+  final Object value;
+}
+
+class IterableSpan {
+  IterableSpan(this.start, this.end, this.iterable);
+
+  final int start;
+  final int end;
+  final Iterable iterable;
+  int get length => end - start;
+
+  /// Using length - .5, a list of length 10000 results in a
+  /// maxPowerOfSubsetSize of 1, so the list will be broken up into 100,
+  /// 100-length subsets. A list of length 10001 results in a
+  /// maxPowerOfSubsetSize of 2, so the list will be broken up into 1
+  /// 10000-length subset and 1 1-length subset.
+  int get maxPowerOfSubsetSize =>
+      (log(length - .5) / log(_maxSpanLength)).truncate();
+  int get subsetSize => pow(_maxSpanLength, maxPowerOfSubsetSize);
+
+  Map<int, dynamic> asMap() =>
+      iterable.skip(start).take(length).toList().asMap();
+
+  List<NameValuePair> children() {
+    var children = <NameValuePair>[];
+    if (length <= _maxSpanLength) {
+      asMap().forEach((i, element) {
+        children
+            .add(NameValuePair(name: (i + start).toString(), value: element));
+      });
+    } else {
+      for (var i = start; i < end; i += subsetSize) {
+        var subSpan = IterableSpan(i, min(end, subsetSize + i), iterable);
+        if (subSpan.length == 1) {
+          children.add(
+              NameValuePair(name: i.toString(), value: iterable.elementAt(i)));
+        } else {
+          children.add(NameValuePair(
+              name: '[${i}...${subSpan.end - 1}]',
+              value: subSpan,
+              hideName: true));
+        }
+      }
+    }
+    return children;
+  }
+}
+
+class Library {
+  Library(this.name, this.object);
+
+  final String name;
+  final Object object;
+}
+
+class NamedConstructor {
+  NamedConstructor(this.object);
+
+  final Object object;
+}
+
+class HeritageClause {
+  HeritageClause(this.name, this.types);
+
+  final String name;
+  final List types;
+}
+
+Object safeGetProperty(Object protoChain, Object name) {
+  try {
+    return JSNative.getProperty(protoChain, name);
+  } catch (e) {
+    return '<Exception thrown> $e';
+  }
+}
+
+safeProperties(object) => Map.fromIterable(
+    getOwnPropertyNames(object)
+        .where((each) => safeGetProperty(object, each) != null),
+    key: (name) => name,
+    value: (name) => safeGetProperty(object, name));
+
+/// Class to simplify building the JsonML objects expected by the
+/// Devtools Formatter API.
+class JsonMLElement {
+  dynamic _attributes;
+  List _jsonML;
+
+  JsonMLElement(tagName) {
+    _attributes = JS('', '{}');
+    _jsonML = [tagName, _attributes];
+  }
+
+  appendChild(element) {
+    _jsonML.add(element.toJsonML());
+  }
+
+  JsonMLElement createChild(String tagName) {
+    var c = JsonMLElement(tagName);
+    _jsonML.add(c.toJsonML());
+    return c;
+  }
+
+  JsonMLElement createObjectTag(object) =>
+      createChild('object')..addAttribute('object', object);
+
+  void setStyle(String style) {
+    _attributes.style = style;
+  }
+
+  addStyle(String style) {
+    if (_attributes.style == null) {
+      _attributes.style = style;
+    } else {
+      _attributes.style += style;
+    }
+  }
+
+  addAttribute(key, value) {
+    JSNative.setProperty(_attributes, key, value);
+  }
+
+  createTextChild(String text) {
+    _jsonML.add(text);
+  }
+
+  toJsonML() => _jsonML;
+}
+
+/// Whether an object is a native JavaScript type where we should display the
+/// JavaScript view of the object instead of the custom Dart specific render
+/// of properties.
+bool isNativeJavaScriptObject(object) {
+  var type = _typeof(object);
+  if (type != 'object' && type != 'function') return true;
+
+  // Consider all regular JS objects that do not represent Dart modules native
+  // JavaScript objects.
+  if (dart.isJsInterop(object) && dart.getModuleName(object) == null) {
+    return true;
+  }
+
+  // Treat Node objects as a native JavaScript type as the regular DOM render
+  // in devtools is superior to the dart specific view.
+  return object is html.Node;
+}
+
+/// Class implementing the Devtools Formatter API described by:
+/// https://docs.google.com/document/d/1FTascZXT9cxfetuPRT2eXPQKXui4nWFivUnS_335T3U
+/// Specifically, a formatter implements a header, hasBody, and body method.
+/// This class renders the simple structured format objects [_simpleFormatter]
+/// provides as JsonML.
+class JsonMLFormatter {
+  // TODO(jacobr): define a SimpleFormatter base class that DartFormatter
+  // implements if we decide to use this class elsewhere. We specify that the
+  // type is DartFormatter here purely to get type checking benefits not because
+  // this class is really intended to only support instances of type
+  // DartFormatter.
+  DartFormatter _simpleFormatter;
+
+  bool customFormattersOn = false;
+
+  JsonMLFormatter(this._simpleFormatter);
+
+  void setMaxSpanLengthForTestingOnly(int spanLength) {
+    _maxSpanLength = spanLength;
+  }
+
+  header(object, config) {
+    customFormattersOn = true;
+    if (config == JsonMLConfig.skipDart || isNativeJavaScriptObject(object)) {
+      return null;
+    }
+    var c = _simpleFormatter.preview(object, config);
+    if (c == null) return null;
+
+    if (config == JsonMLConfig.keyToString) {
+      c = object.toString();
+    }
+
+    // Indicate this is a Dart Object by using a Dart background color.
+    // This is stylistically a bit ugly but it eases distinguishing Dart and
+    // JS objects.
+    var element = JsonMLElement('span')
+      ..setStyle('background-color: #d9edf7;color: black')
+      ..createTextChild(c);
+    return element.toJsonML();
+  }
+
+  bool hasBody(object, config) => _simpleFormatter.hasChildren(object, config);
+
+  body(object, config) {
+    var body = JsonMLElement('ol')
+      ..setStyle('list-style-type: none;'
+          'padding-left: 0px;'
+          'margin-top: 0px;'
+          'margin-bottom: 0px;'
+          'margin-left: 12px;');
+    if (object is StackTrace) {
+      body.addStyle('background-color: thistle;color: rgb(196, 26, 22);');
+    }
+    var children = _simpleFormatter.children(object, config);
+    if (children == null) return body.toJsonML();
+    for (NameValuePair child in children) {
+      var li = body.createChild('li');
+      li.setStyle("padding-left: 13px;");
+
+      // The value is indented when it is on a different line from the name
+      // by setting right padding of the name to -13px and the padding of the
+      // value to 13px.
+      JsonMLElement nameSpan;
+      var valueStyle = '';
+      if (!child.hideName) {
+        nameSpan = JsonMLElement('span')
+          ..createTextChild(
+              child.displayName.isNotEmpty ? '${child.displayName}: ' : '')
+          ..setStyle(
+              'background-color: thistle; color: rgb(136, 19, 145); margin-right: -13px');
+        valueStyle = 'margin-left: 13px';
+      }
+
+      if (_typeof(child.value) == 'object' ||
+          _typeof(child.value) == 'function') {
+        var valueSpan = JsonMLElement('span')..setStyle(valueStyle);
+        valueSpan.createObjectTag(child.value)
+          ..addAttribute('config', child.config);
+        if (nameSpan != null) {
+          li.appendChild(nameSpan);
+        }
+        li.appendChild(valueSpan);
+      } else {
+        var line = li.createChild('span');
+        if (nameSpan != null) {
+          line.appendChild(nameSpan);
+        }
+        line.appendChild(JsonMLElement('span')
+          ..createTextChild(safePreview(child.value, child.config))
+          ..setStyle(valueStyle));
+      }
+    }
+    return body.toJsonML();
+  }
+}
+
+abstract class Formatter {
+  bool accept(object, config);
+  String preview(object);
+  bool hasChildren(object);
+  List<NameValuePair> children(object);
+}
+
+class DartFormatter {
+  List<Formatter> _formatters;
+
+  DartFormatter() {
+    // The order of formatters matters as formatters earlier in the list take
+    // precedence.
+    _formatters = [
+      ObjectInternalsFormatter(),
+      ClassFormatter(),
+      TypeFormatter(),
+      NamedConstructorFormatter(),
+      MapFormatter(),
+      MapOverviewFormatter(),
+      IterableFormatter(),
+      IterableSpanFormatter(),
+      MapEntryFormatter(),
+      StackTraceFormatter(),
+      ErrorAndExceptionFormatter(),
+      FunctionFormatter(),
+      HeritageClauseFormatter(),
+      LibraryModuleFormatter(),
+      LibraryFormatter(),
+      ObjectFormatter(),
+    ];
+  }
+
+  String preview(object, config) {
+    try {
+      if (object == null ||
+          object is num ||
+          object is String ||
+          isNativeJavaScriptObject(object)) {
+        return object.toString();
+      }
+      for (var formatter in _formatters) {
+        if (formatter.accept(object, config)) return formatter.preview(object);
+      }
+    } catch (e, trace) {
+      // Log formatter internal errors as unfortunately the devtools cannot
+      // be used to debug formatter errors.
+      html.window.console.error("Caught exception $e\n trace:\n$trace");
+    }
+
+    return null;
+  }
+
+  bool hasChildren(object, config) {
+    if (object == null) return false;
+    try {
+      for (var formatter in _formatters) {
+        if (formatter.accept(object, config))
+          return formatter.hasChildren(object);
+      }
+    } catch (e, trace) {
+      // See comment for preview.
+      html.window.console
+          .error("[hasChildren] Caught exception $e\n trace:\n$trace");
+    }
+    return false;
+  }
+
+  List<NameValuePair> children(object, config) {
+    try {
+      if (object != null) {
+        for (var formatter in _formatters) {
+          if (formatter.accept(object, config))
+            return formatter.children(object);
+        }
+      }
+    } catch (e, trace) {
+      // See comment for preview.
+      html.window.console.error("Caught exception $e\n trace:\n$trace");
+    }
+    return <NameValuePair>[];
+  }
+}
+
+/// Default formatter for Dart Objects.
+class ObjectFormatter extends Formatter {
+  bool accept(object, config) => !isNativeJavaScriptObject(object);
+
+  String preview(object) {
+    var typeName = getObjectTypeName(object);
+    try {
+      // An explicit toString() call might not actually be a string. This way
+      // we're sure.
+      var toString = "$object";
+      if (toString.length > maxFormatterStringLength) {
+        toString = toString.substring(0, maxFormatterStringLength - 3) + "...";
+      }
+      // The default toString() will be "Instance of 'Foo'", in which case we
+      // don't need any further indication of the class.
+      if (toString.contains(typeName)) {
+        return toString;
+      } else {
+        // If there's no class indication, e.g. an Int64 that just prints as a
+        // number, then add the class name.
+        return "$toString ($typeName)";
+      }
+    } catch (e) {}
+    // We will only get here if there was an error getting the toString, in
+    // which case we just use the type name.
+    return typeName;
+  }
+
+  bool hasChildren(object) => true;
+
+  List<NameValuePair> children(object) {
+    var type = dart.getType(object);
+    var ret = LinkedHashSet<NameValuePair>();
+    // We use a Set rather than a List to avoid duplicates.
+    var fields = Set<NameValuePair>();
+    addPropertiesFromSignature(dart.getFields(type), fields, object, true);
+    var getters = Set<NameValuePair>();
+    addPropertiesFromSignature(dart.getGetters(type), getters, object, true);
+    ret.addAll(sortProperties(fields));
+    ret.addAll(sortProperties(getters));
+    addMetadataChildren(object, ret);
+    return ret.toList();
+  }
+}
+
+/// Show the object instance members and a reduced preview.
+///
+/// Used as a sub-entry to show the internals of objects that have a different
+/// primary format. For example, a Map shows the key-value pairs, but this makes
+/// the internals of the map visible for debugging.
+class ObjectInternalsFormatter extends ObjectFormatter {
+  bool accept(object, config) =>
+      super.accept(object, config) && config == JsonMLConfig.asObject;
+
+  // A minimal preview because we expect a full preview is already shown in a
+  // parent formatter.
+  String preview(object) {
+    return getObjectTypeName(object);
+  }
+}
+
+/// Formatter for module Dart Library objects.
+class LibraryModuleFormatter implements Formatter {
+  accept(object, config) => dart.getModuleName(object) != null;
+
+  bool hasChildren(object) => true;
+
+  String preview(object) {
+    var libraryNames = dart.getModuleName(object).split('/');
+    // Library names are received with a repeat directory name, so strip the
+    // last directory entry here to make the path cleaner. For example, the
+    // library "third_party/dart/utf/utf" shoud display as
+    // "third_party/dart/utf/".
+    if (libraryNames.length > 1 &&
+        libraryNames.last == libraryNames[libraryNames.length - 2]) {
+      libraryNames[libraryNames.length - 1] = '';
+    }
+    return 'Library Module: ${libraryNames.join('/')}';
+  }
+
+  List<NameValuePair> children(object) {
+    var children = LinkedHashSet<NameValuePair>();
+    for (var name in getOwnPropertyNames(object)) {
+      var value = safeGetProperty(object, name);
+      children.add(NameValuePair(
+          name: name, value: Library(name, value), hideName: true));
+    }
+    return children.toList();
+  }
+}
+
+class LibraryFormatter implements Formatter {
+  var genericParameters = HashMap<String, String>();
+
+  accept(object, config) => object is Library;
+
+  bool hasChildren(object) => true;
+
+  String preview(object) => object.name;
+
+  List<NameValuePair> children(object) {
+    // Maintain library member order rather than sorting members as is the
+    // case for class members.
+    var children = LinkedHashSet<NameValuePair>();
+    var objectProperties = safeProperties(object.object);
+    objectProperties.forEach((name, value) {
+      // Skip the generic constructors for each class as users are only
+      // interested in seeing the actual classes.
+      if (dart.getGenericTypeCtor(value) != null) return;
+
+      children.add(dart.isType(value)
+          ? classChild(name, value)
+          : NameValuePair(name: name, value: value));
+    });
+    return children.toList();
+  }
+
+  classChild(String name, Object child) {
+    var typeName = getTypeName(child);
+    return NameValuePair(
+        name: typeName, value: child, config: JsonMLConfig.asClass);
+  }
+}
+
+/// Formatter for Dart Function objects.
+/// Dart functions happen to be regular JavaScript Function objects but
+/// we can distinguish them based on whether they have been tagged with
+/// runtime type information.
+class FunctionFormatter implements Formatter {
+  accept(object, config) {
+    if (_typeof(object) != 'function') return false;
+    return dart.getReifiedType(object) != null;
+  }
+
+  bool hasChildren(object) => true;
+
+  String preview(object) {
+    // The debugger can createa a preview of a FunctionType while it's being
+    // constructed (before argument types exist), so we need to catch errors.
+    try {
+      return dart.typeName(dart.getReifiedType(object));
+    } catch (e) {
+      return safePreview(object, JsonMLConfig.none);
+    }
+  }
+
+  List<NameValuePair> children(object) => <NameValuePair>[
+        NameValuePair(name: 'signature', value: preview(object)),
+        NameValuePair(
+            name: 'JavaScript Function',
+            value: object,
+            config: JsonMLConfig.skipDart)
+      ];
+}
+
+/// Formatter for Objects that implement Map but are not system Maps.
+///
+/// This shows two sub-views, one for instance fields and one for
+/// Map key/value pairs.
+class MapOverviewFormatter implements Formatter {
+  // Because this comes after MapFormatter in the list, internal
+  // maps will be picked up by that formatter.
+  accept(object, config) => object is Map;
+
+  bool hasChildren(object) => true;
+
+  String preview(object) {
+    Map map = object;
+    try {
+      return '${getObjectTypeName(map)}';
+    } catch (e) {
+      return safePreview(object, JsonMLConfig.none);
+    }
+  }
+
+  List<NameValuePair> children(object) => [
+        NameValuePair(
+            name: "[[instance view]]",
+            value: object,
+            config: JsonMLConfig.asObject),
+        NameValuePair(
+            name: "[[entries]]", value: object, config: JsonMLConfig.asMap)
+      ];
+}
+
+/// Formatter for Dart Map objects.
+///
+/// This is only used for internal maps, or when shown as [[entries]]
+/// from MapOverViewFormatter.
+class MapFormatter implements Formatter {
+  accept(object, config) =>
+      object is InternalMap || config == JsonMLConfig.asMap;
+
+  bool hasChildren(object) => true;
+
+  String preview(object) {
+    Map map = object;
+    try {
+      return '${getObjectTypeName(map)} length ${map.length}';
+    } catch (e) {
+      return safePreview(object, JsonMLConfig.none);
+    }
+  }
+
+  List<NameValuePair> children(object) {
+    // TODO(jacobr): be lazier about enumerating contents of Maps that are not
+    // the build in LinkedHashMap class.
+    // TODO(jacobr): handle large Maps better.
+    Map map = object;
+    var entries = LinkedHashSet<NameValuePair>();
+    map.forEach((key, value) {
+      var entryWrapper = MapEntry(key: key, value: value);
+      entries.add(
+          NameValuePair(name: entries.length.toString(), value: entryWrapper));
+    });
+    addMetadataChildren(object, entries);
+    return entries.toList();
+  }
+}
+
+/// Formatter for Dart Iterable objects including List and Set.
+class IterableFormatter implements Formatter {
+  bool accept(object, config) => object is Iterable;
+
+  String preview(object) {
+    Iterable iterable = object;
+    try {
+      var length = iterable.length;
+      return '${getObjectTypeName(iterable)} length $length';
+    } catch (_) {
+      return '${getObjectTypeName(iterable)}';
+    }
+  }
+
+  bool hasChildren(object) => true;
+
+  List<NameValuePair> children(object) {
+    // TODO(jacobr): be lazier about enumerating contents of Iterables that
+    // are not the built in Set or List types.
+    // TODO(jacobr): handle large Iterables better.
+    // TODO(jacobr): consider only using numeric indices
+    var children = LinkedHashSet<NameValuePair>();
+    children.addAll(IterableSpan(0, object.length, object).children());
+    // TODO(jacobr): provide a link to show regular class properties here.
+    // required for subclasses of iterable, etc.
+    addMetadataChildren(object, children);
+    return children.toList();
+  }
+}
+
+class NamedConstructorFormatter implements Formatter {
+  accept(object, config) => object is NamedConstructor;
+
+  // TODO(bmilligan): Display the signature of the named constructor as the
+  // preview.
+  String preview(object) => 'Named Constructor';
+
+  bool hasChildren(object) => true;
+
+  List<NameValuePair> children(object) => <NameValuePair>[
+        NameValuePair(
+            name: 'JavaScript Function',
+            value: object,
+            config: JsonMLConfig.skipDart)
+      ];
+}
+
+/// Formatter for synthetic MapEntry objects used to display contents of a Map
+/// cleanly.
+class MapEntryFormatter implements Formatter {
+  accept(object, config) => object is MapEntry;
+
+  String preview(object) {
+    MapEntry entry = object;
+    return '${safePreview(entry.key, JsonMLConfig.none)} => ${safePreview(entry.value, JsonMLConfig.none)}';
+  }
+
+  bool hasChildren(object) => true;
+
+  List<NameValuePair> children(object) => <NameValuePair>[
+        NameValuePair(
+            name: 'key', value: object.key, config: JsonMLConfig.keyToString),
+        NameValuePair(name: 'value', value: object.value)
+      ];
+}
+
+/// Formatter for Dart Iterable objects including List and Set.
+class HeritageClauseFormatter implements Formatter {
+  bool accept(object, config) => object is HeritageClause;
+
+  String preview(object) {
+    HeritageClause clause = object;
+    var typeNames = clause.types.map(getTypeName);
+    return '${clause.name} ${typeNames.join(", ")}';
+  }
+
+  bool hasChildren(object) => true;
+
+  List<NameValuePair> children(object) {
+    HeritageClause clause = object;
+    var children = <NameValuePair>[];
+    for (var type in clause.types) {
+      children.add(NameValuePair(value: type, config: JsonMLConfig.asClass));
+    }
+    return children;
+  }
+}
+
+/// Formatter for synthetic IterableSpan objects used to display contents of
+/// an Iterable cleanly.
+class IterableSpanFormatter implements Formatter {
+  accept(object, config) => object is IterableSpan;
+
+  String preview(object) {
+    return '[${object.start}...${object.end - 1}]';
+  }
+
+  bool hasChildren(object) => true;
+
+  List<NameValuePair> children(object) => object.children();
+}
+
+/// Formatter for Dart Errors and Exceptions.
+class ErrorAndExceptionFormatter extends ObjectFormatter {
+  static final RegExp _pattern = RegExp(r'\d+\:\d+');
+
+  accept(object, config) => object is Error || object is Exception;
+
+  bool hasChildren(object) => true;
+
+  String preview(object) {
+    var trace = dart.stackTrace(object);
+    // TODO(vsm): Pull our stack mapping logic here.  We should aim to
+    // provide the first meaningful stack frame.
+    var line = '$trace'.split('\n').firstWhere(
+        (l) =>
+            l.contains(_pattern) &&
+            !l.contains('dart:sdk') &&
+            !l.contains('dart_sdk'),
+        orElse: () => null);
+    return line != null ? '${object} at ${line}' : '${object}';
+  }
+
+  List<NameValuePair> children(object) {
+    var trace = dart.stackTrace(object);
+    var entries = LinkedHashSet<NameValuePair>();
+    entries.add(NameValuePair(name: 'stackTrace', value: trace));
+    addInstanceMembers(object, entries);
+    addMetadataChildren(object, entries);
+    return entries.toList();
+  }
+
+  // Add an ObjectFormatter view underneath.
+  void addInstanceMembers(object, Set<NameValuePair> ret) {
+    ret.add(NameValuePair(
+        name: "[[instance members]]",
+        value: object,
+        config: JsonMLConfig.asObject));
+  }
+}
+
+class StackTraceFormatter implements Formatter {
+  accept(object, config) => object is StackTrace;
+
+  String preview(object) => 'StackTrace';
+
+  bool hasChildren(object) => true;
+
+  // Using the stack_trace formatting would be ideal, but adding the
+  // dependency or re-writing the code is too messy, so each line of the
+  // StackTrace will be added as its own child.
+  List<NameValuePair> children(object) => object
+      .toString()
+      .split('\n')
+      .map((line) => NameValuePair(
+          value: line.replaceFirst(RegExp(r'^\s+at\s'), ''), hideName: true))
+      .toList();
+}
+
+class ClassFormatter implements Formatter {
+  accept(object, config) => config == JsonMLConfig.asClass;
+
+  String preview(type) {
+    var implements = dart.getImplements(type);
+    var typeName = getTypeName(type);
+    if (implements != null) {
+      var typeNames = implements().map(getTypeName);
+      return '${typeName} implements ${typeNames.join(", ")}';
+    } else {
+      return typeName;
+    }
+  }
+
+  bool hasChildren(object) => true;
+
+  List<NameValuePair> children(type) {
+    // TODO(jacobr): add other entries describing the class such as
+    // implemented interfaces, and methods.
+    var ret = LinkedHashSet<NameValuePair>();
+
+    var staticProperties = Set<NameValuePair>();
+    var staticMethods = Set<NameValuePair>();
+    // Static fields and properties.
+    addPropertiesFromSignature(
+        dart.getStaticFields(type), staticProperties, type, false);
+    addPropertiesFromSignature(
+        dart.getStaticGetters(type), staticProperties, type, false);
+    // static methods.
+    addPropertiesFromSignature(
+        dart.getStaticMethods(type), staticMethods, type, false);
+
+    if (staticProperties.isNotEmpty || staticMethods.isNotEmpty) {
+      ret
+        ..add(NameValuePair(value: '[[Static members]]', hideName: true))
+        ..addAll(sortProperties(staticProperties))
+        ..addAll(sortProperties(staticMethods));
+    }
+
+    // instance methods.
+    var instanceMethods = Set<NameValuePair>();
+    // Instance methods are defined on the prototype not the constructor object.
+    addPropertiesFromSignature(dart.getMethods(type), instanceMethods,
+        JS('', '#.prototype', type), false,
+        tagTypes: true);
+    if (instanceMethods.isNotEmpty) {
+      ret
+        ..add(NameValuePair(value: '[[Instance Methods]]', hideName: true))
+        ..addAll(sortProperties(instanceMethods));
+    }
+
+    var mixin = dart.getMixin(type);
+    if (mixin != null) {
+      // TODO(jmesserly): this can only be one value.
+      ret.add(NameValuePair(
+          name: '[[Mixins]]', value: HeritageClause('mixins', [mixin])));
+    }
+
+    var baseProto = JS('', '#.__proto__', type);
+    if (baseProto != null && !dart.isJsInterop(baseProto)) {
+      ret.add(NameValuePair(
+          name: "[[base class]]",
+          value: baseProto,
+          config: JsonMLConfig.asClass));
+    }
+
+    // TODO(jacobr): add back fields for named constructors.
+    return ret.toList();
+  }
+}
+
+class TypeFormatter implements Formatter {
+  accept(object, config) => object is Type;
+
+  String preview(object) => object.toString();
+
+  bool hasChildren(object) => false;
+
+  List<NameValuePair> children(object) => [];
+}
+
+typedef String StackTraceMapper(String stackTrace);
+
+/// Hook for other parts of the SDK To use to map JS stack traces to Dart
+/// stack traces.
+///
+/// Raw JS stack traces are used if $dartStackTraceUtility has not been
+/// specified.
+StackTraceMapper get stackTraceMapper {
+  var _util = JS('', r'#.$dartStackTraceUtility', dart.global_);
+  return _util != null ? JS('!', '#.mapper', _util) : null;
+}
+
+/// This entry point is automatically invoked by the code generated by
+/// Dart Dev Compiler
+registerDevtoolsFormatter() {
+  JS('', '#.devtoolsFormatters = [#]', dart.global_, _devtoolsFormatter);
+}
+
+// These methods are exposed here for debugger tests.
+//
+// TODO(jmesserly): these are not exports because there is existing code that
+// calls into them from JS. Currently `dartdevc` always resolves exports at
+// compile time, so there is no need to make exports available at runtime by
+// copying properties. For that reason we cannot use re-export.
+//
+// If these methods are only for tests, we should move them here, or change the
+// tests to call the methods directly on dart:_runtime.
+List<String> getModuleNames() => dart.getModuleNames();
+getModuleLibraries(String name) => dart.getModuleLibraries(name);
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/private/foreign_helper.dart b/sdk_nnbd/lib/_internal/js_dev_runtime/private/foreign_helper.dart
new file mode 100644
index 0000000..588d789
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/private/foreign_helper.dart
@@ -0,0 +1,285 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library dart._foreign_helper;
+
+/**
+ * Emits a JavaScript code fragment parameterized by arguments.
+ *
+ * Hash characters `#` in the [codeTemplate] are replaced in left-to-right order
+ * with expressions that contain the values of, or evaluate to, the arguments.
+ * The number of hash marks must match the number or arguments.  Although
+ * declared with arguments [arg0] through [arg2], the form actually has no limit
+ * on the number of arguments.
+ *
+ * The [typeDescription] argument is interpreted as a description of the
+ * behavior of the JavaScript code.  Currently it describes the types that may
+ * be returned by the expression, with the additional behavior that the returned
+ * values may be fresh instances of the types.  The type information must be
+ * correct as it is trusted by the compiler in optimizations, and it must be
+ * precise as possible since it is used for native live type analysis to
+ * tree-shake large parts of the DOM libraries.  If poorly written, the
+ * [typeDescription] will cause unnecessarily bloated programs.  (You can check
+ * for this by compiling with `--verbose`; there is an info message describing
+ * the number of native (DOM) types that can be removed, which usually should be
+ * greater than zero.)
+ *
+ * The [typeDescription] is a [String] which contains a union of types separated
+ * by vertical bar `|` symbols, e.g.  `"num|String"` describes the union of
+ * numbers and Strings.  There is no type in Dart that is this precise.  The
+ * Dart alternative would be `Object` or `dynamic`, but these types imply that
+ * the JS-code might also be creating instances of all the DOM types.  If `null`
+ * is possible, it must be specified explicitly, e.g. `"String|Null"`.
+ * [typeDescription] has several extensions to help describe the behavior more
+ * accurately.  In addition to the union type already described:
+ *
+ *  + `=Object` is a plain JavaScript object.  Some DOM methods return instances
+ *     that have no corresponding Dart type (e.g. cross-frame documents),
+ *     `=Object` can be used to describe these untyped' values.
+ *
+ *  + `var` (or empty string).  If the entire [typeDescription] is `var` (or
+ *    empty string) then the type is `dynamic` but the code is known to not
+ *    create any instances.
+ *
+ * Examples:
+ *
+ *     // Parent window might be an opaque cross-frame window.
+ *     var thing = JS('=Object|Window', '#.parent', myWindow);
+ *
+ * Guidelines:
+ *
+ *  + Do not use any parameter, local, method or field names in the
+ *    [codeTemplate].  These names are all subject to arbitrary renaming by the
+ *    compiler.  Pass the values in via `#` substition, and test with the
+ *    `--minify` dart2js command-line option.
+ *
+ *  + The substituted expressions are values, not locations.
+ *
+ *        JS('void', '# += "x"', this.field);
+ *
+ *    `this.field` might not be a substituted as a reference to the field.  The
+ *    generated code might accidentally work as intended, but it also might be
+ *
+ *        var t1 = this.field;
+ *        t1 += "x";
+ *
+ *    or
+ *
+ *        this.get$field() += "x";
+ *
+ *    The remedy in this case is to expand the `+=` operator, leaving all
+ *    references to the Dart field as Dart code:
+ *
+ *        this.field = JS<String>('!', '# + "x"', this.field);
+ *
+ *  + Never use `#` in function bodies.
+ *
+ *    This is a variation on the previous guideline.  Since `#` is replaced with
+ *    an *expression* and the expression is only valid in the immediate context,
+ *    `#` should never appear in a function body.  Doing so might defer the
+ *    evaluation of the expression, and its side effects, until the function is
+ *    called.
+ *
+ *    For example,
+ *
+ *        var value = foo();
+ *        var f = JS('', 'function(){return #}', value)
+ *
+ *    might result in no immediate call to `foo` and a call to `foo` on every
+ *    call to the JavaScript function bound to `f`.  This is better:
+ *
+ *        var f = JS('',
+ *            '(function(val) { return function(){return val}; })(#)', value);
+ *
+ *    Since `#` occurs in the immediately evaluated expression, the expression
+ *    is immediately evaluated and bound to `val` in the immediate call.
+ *
+ *
+ * Additional notes.
+ *
+ * In the future we may extend [typeDescription] to include other aspects of the
+ * behavior, for example, separating the returned types from the instantiated
+ * types, or including effects to allow the compiler to perform more
+ * optimizations around the code.  This might be an extension of [JS] or a new
+ * function similar to [JS] with additional arguments for the new information.
+ */
+// Add additional optional arguments if needed. The method is treated internally
+// as a variable argument method.
+T JS<T extends Object>(String typeDescription, String codeTemplate,
+    [arg0,
+    arg1,
+    arg2,
+    arg3,
+    arg4,
+    arg5,
+    arg6,
+    arg7,
+    arg8,
+    arg9,
+    arg10,
+    arg11,
+    arg12,
+    arg13,
+    arg14,
+    arg15,
+    arg16,
+    arg17,
+    arg18,
+    arg19]) {}
+
+/// Annotates the compiled Js name for fields and methods.
+/// Similar behaviour to `JS` from `package:js/js.dart` (but usable from runtime
+/// files), and not to be confused with `JSName` from `js_helper` (which deals
+/// with names of externs).
+// TODO(jmesserly): remove this in favor of js_helper's `@JSName`
+// (Currently they have slightly different semantics, but they can be unified.)
+class JSExportName {
+  final String name;
+  const JSExportName(this.name);
+}
+
+/**
+ * Returns the JavaScript constructor function for Dart's Object class.
+ * This can be used for type tests, as in
+ *
+ *     if (JS<bool>('!', '# instanceof #', obj, JS_DART_OBJECT_CONSTRUCTOR()))
+ *       ...
+ */
+JS_DART_OBJECT_CONSTRUCTOR() {}
+
+/**
+ * Returns the interceptor for class [type].  The interceptor is the type's
+ * constructor's `prototype` property.  [type] will typically be the class, not
+ * an interface, e.g. `JS_INTERCEPTOR_CONSTANT(JSInt)`, not
+ * `JS_INTERCEPTOR_CONSTANT(int)`.
+ */
+JS_INTERCEPTOR_CONSTANT(Type type) {}
+
+/**
+ * Returns the prefix used for generated is checks on classes.
+ */
+String JS_OPERATOR_IS_PREFIX() {}
+
+/**
+ * Returns the prefix used for generated type argument substitutions on classes.
+ */
+String JS_OPERATOR_AS_PREFIX() {}
+
+/// Returns the name of the class `Object` in the generated code.
+String JS_OBJECT_CLASS_NAME() {}
+
+/// Returns the name of the class `Null` in the generated code.
+String JS_NULL_CLASS_NAME() {}
+
+/// Returns the name of the class `Function` in the generated code.
+String JS_FUNCTION_CLASS_NAME() {}
+
+/**
+ * Returns the field name used for determining if an object or its
+ * interceptor has JavaScript indexing behavior.
+ */
+String JS_IS_INDEXABLE_FIELD_NAME() {}
+
+/// Returns the name used for generated function types on classes and methods.
+String JS_SIGNATURE_NAME() {}
+
+/// Returns the name used to tag typedefs.
+String JS_TYPEDEF_TAG() {}
+
+/// Returns the name used to tag function type representations in JavaScript.
+String JS_FUNCTION_TYPE_TAG() {}
+
+/**
+ * Returns the name used to tag void return in function type representations
+ * in JavaScript.
+ */
+String JS_FUNCTION_TYPE_VOID_RETURN_TAG() {}
+
+/**
+ * Returns the name used to tag return types in function type representations
+ * in JavaScript.
+ */
+String JS_FUNCTION_TYPE_RETURN_TYPE_TAG() {}
+
+/**
+ * Returns the name used to tag required parameters in function type
+ * representations in JavaScript.
+ */
+String JS_FUNCTION_TYPE_REQUIRED_PARAMETERS_TAG() {}
+
+/**
+ * Returns the name used to tag optional parameters in function type
+ * representations in JavaScript.
+ */
+String JS_FUNCTION_TYPE_OPTIONAL_PARAMETERS_TAG() {}
+
+/**
+ * Returns the name used to tag named parameters in function type
+ * representations in JavaScript.
+ */
+String JS_FUNCTION_TYPE_NAMED_PARAMETERS_TAG() {}
+
+/// Returns the JS name for [name] from the Namer.
+String JS_GET_NAME(String name) {}
+
+/// Returns the state of a flag that is determined by the state of the compiler
+/// when the program has been analyzed.
+bool JS_GET_FLAG(String name) {}
+
+/**
+ * Pretend [code] is executed.  Generates no executable code.  This is used to
+ * model effects at some other point in external code.  For example, the
+ * following models an assignment to foo with an unknown value.
+ *
+ *     var foo;
+ *
+ *     main() {
+ *       JS_EFFECT((_){ foo = _; })
+ *     }
+ *
+ * TODO(sra): Replace this hack with something to mark the volatile or
+ * externally initialized elements.
+ */
+void JS_EFFECT(Function code) {
+  code(null);
+}
+
+/**
+ * Use this class for creating constants that hold JavaScript code.
+ * For example:
+ *
+ * const constant = JS_CONST('typeof window != "undefined");
+ *
+ * This code will generate:
+ * $.JS_CONST_1 = typeof window != "undefined";
+ */
+class JS_CONST {
+  final String code;
+  const JS_CONST(this.code);
+}
+
+/**
+ * JavaScript string concatenation. Inputs must be Strings.  Corresponds to the
+ * HStringConcat SSA instruction and may be constant-folded.
+ */
+String JS_STRING_CONCAT(String a, String b) {
+  // This body is unused, only here for type analysis.
+  return JS<String>('!', '# + #', a, b);
+}
+
+/// Same `@rest` annotation and `spread` function as in
+/// `package:js/src/varargs.dart`.
+///
+/// Runtime files cannot import packages, which is why we have an ad-hoc copy.
+
+class _Rest {
+  const _Rest();
+}
+
+const _Rest rest = _Rest();
+
+dynamic spread(args) {
+  throw StateError('The spread function cannot be called, '
+      'it should be compiled away.');
+}
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/private/identity_hash_map.dart b/sdk_nnbd/lib/_internal/js_dev_runtime/private/identity_hash_map.dart
new file mode 100644
index 0000000..04107cc
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/private/identity_hash_map.dart
@@ -0,0 +1,137 @@
+// 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.
+
+part of dart._js_helper;
+
+class IdentityMap<K, V> extends InternalMap<K, V> {
+  final _map = JS('', 'new Map()');
+
+  // We track the number of modifications done to the key set of the
+  // hash map to be able to throw when the map is modified while being
+  // iterated over.
+  //
+  // Value cycles after 2^30 modifications so that modification counts are
+  // always unboxed (Smi) values. Modification detection will be missed if you
+  // make exactly some multiple of 2^30 modifications between advances of an
+  // iterator.
+  @notNull
+  int _modifications = 0;
+
+  IdentityMap();
+  IdentityMap.from(JSArray entries) {
+    var map = _map;
+    for (int i = 0, n = JS<int>('!', '#.length', entries); i < n; i += 2) {
+      JS('', '#.set(#[#], #[#])', map, entries, i, entries, i + 1);
+    }
+  }
+
+  int get length => JS<int>('!', '#.size', _map);
+  bool get isEmpty => JS<bool>('!', '#.size == 0', _map);
+  bool get isNotEmpty => JS<bool>('!', '#.size != 0', _map);
+
+  Iterable<K> get keys => _JSMapIterable<K>(this, true);
+  Iterable<V> get values => _JSMapIterable<V>(this, false);
+
+  bool containsKey(Object key) {
+    return JS<bool>('!', '#.has(#)', _map, key);
+  }
+
+  bool containsValue(Object value) {
+    for (var v in JS('', '#.values()', _map)) {
+      if (v == value) return true;
+    }
+    return false;
+  }
+
+  void addAll(Map<K, V> other) {
+    if (other.isNotEmpty) {
+      var map = _map;
+      other.forEach((key, value) {
+        JS('', '#.set(#, #)', map, key, value);
+      });
+      _modifications = (_modifications + 1) & 0x3ffffff;
+    }
+  }
+
+  V operator [](Object key) {
+    V value = JS('', '#.get(#)', _map, key);
+    return value == null ? null : value; // coerce undefined to null.
+  }
+
+  void operator []=(K key, V value) {
+    var map = _map;
+    int length = JS('!', '#.size', map);
+    JS('', '#.set(#, #)', map, key, value);
+    if (length != JS<int>('!', '#.size', map)) {
+      _modifications = (_modifications + 1) & 0x3ffffff;
+    }
+  }
+
+  V putIfAbsent(K key, V ifAbsent()) {
+    if (JS<bool>('!', '#.has(#)', _map, key)) {
+      return JS('', '#.get(#)', _map, key);
+    }
+    V value = ifAbsent();
+    if (value == null) value = null; // coerce undefined to null.
+    JS('', '#.set(#, #)', _map, key, value);
+    _modifications = (_modifications + 1) & 0x3ffffff;
+    return value;
+  }
+
+  V remove(Object key) {
+    V value = JS('', '#.get(#)', _map, key);
+    if (JS<bool>('!', '#.delete(#)', _map, key)) {
+      _modifications = (_modifications + 1) & 0x3ffffff;
+    }
+    return value == null ? null : value; // coerce undefined to null.
+  }
+
+  void clear() {
+    if (JS<int>('!', '#.size', _map) > 0) {
+      JS('', '#.clear()', _map);
+      _modifications = (_modifications + 1) & 0x3ffffff;
+    }
+  }
+}
+
+class _JSMapIterable<E> extends EfficientLengthIterable<E> {
+  final InternalMap _map;
+  @notNull
+  final bool _isKeys;
+  _JSMapIterable(this._map, this._isKeys);
+
+  int get length => _map.length;
+  bool get isEmpty => _map.isEmpty;
+
+  @JSExportName('Symbol.iterator')
+  _jsIterator() {
+    var map = _map;
+    var iterator =
+        JS('', '# ? #.keys() : #.values()', _isKeys, map._map, map._map);
+    int modifications = map._modifications;
+    return JS(
+        '',
+        '''{
+      next() {
+        if (# != #) {
+          throw #;
+        }
+        return #.next();
+      }
+    }''',
+        modifications,
+        map._modifications,
+        ConcurrentModificationError(map),
+        iterator);
+  }
+
+  Iterator<E> get iterator => DartIterator<E>(_jsIterator());
+
+  bool contains(Object element) =>
+      _isKeys ? _map.containsKey(element) : _map.containsValue(element);
+
+  void forEach(void f(E element)) {
+    for (var entry in this) f(entry);
+  }
+}
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/private/interceptors.dart b/sdk_nnbd/lib/_internal/js_dev_runtime/private/interceptors.dart
new file mode 100644
index 0000000..6ddd96b
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/private/interceptors.dart
@@ -0,0 +1,233 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library dart._interceptors;
+
+import 'dart:collection';
+import 'dart:_internal' hide Symbol;
+import 'dart:_js_helper';
+import 'dart:_foreign_helper' show JS, JSExportName;
+import 'dart:math' show Random, ln2;
+import 'dart:_runtime' as dart;
+
+part 'js_array.dart';
+part 'js_number.dart';
+part 'js_string.dart';
+
+// TODO(jmesserly): remove, this doesn't do anything for us.
+abstract class Interceptor {
+  const Interceptor();
+
+  // Use native JS toString method instead of standard Dart Object.toString.
+  String toString() => JS<String>('!', '#.toString()', this);
+}
+
+// TODO(jmesserly): remove
+getInterceptor(obj) => obj;
+
+/**
+ * The interceptor class for [bool].
+ */
+@JsPeerInterface(name: 'Boolean')
+class JSBool extends Interceptor implements bool {
+  const JSBool();
+
+  // Note: if you change this, also change the function [S].
+  @notNull
+  String toString() => JS<String>('!', r'String(#)', this);
+
+  // The values here are SMIs, co-prime and differ about half of the bit
+  // positions, including the low bit, so they are different mod 2^k.
+  @notNull
+  int get hashCode => this ? (2 * 3 * 23 * 3761) : (269 * 811);
+
+  @notNull
+  bool operator &(@nullCheck bool other) =>
+      JS<bool>('!', "# && #", other, this);
+
+  @notNull
+  bool operator |(@nullCheck bool other) =>
+      JS<bool>('!', "# || #", other, this);
+
+  @notNull
+  bool operator ^(@nullCheck bool other) => !identical(this, other);
+
+  Type get runtimeType => bool;
+}
+
+/**
+ * The supertype for JSString and JSArray. Used by the backend as to
+ * have a type mask that contains the objects that we can use the
+ * native JS [] operator and length on.
+ */
+abstract class JSIndexable<E> {
+  int get length;
+  E operator [](int index);
+}
+
+/**
+ * The interface implemented by JavaScript objects.  These are methods in
+ * addition to the regular Dart Object methods like [Object.hashCode].
+ *
+ * This is the type that should be exported by a JavaScript interop library.
+ */
+abstract class JSObject {}
+
+/**
+ * Interceptor base class for JavaScript objects not recognized as some more
+ * specific native type.
+ */
+abstract class JavaScriptObject extends Interceptor implements JSObject {
+  const JavaScriptObject();
+
+  // It would be impolite to stash a property on the object.
+  int get hashCode => 0;
+
+  Type get runtimeType => JSObject;
+}
+
+/**
+ * Interceptor for plain JavaScript objects created as JavaScript object
+ * literals or `new Object()`.
+ */
+class PlainJavaScriptObject extends JavaScriptObject {
+  const PlainJavaScriptObject();
+}
+
+/**
+ * Interceptor for unclassified JavaScript objects, typically objects with a
+ * non-trivial prototype chain.
+ *
+ * This class also serves as a fallback for unknown JavaScript exceptions.
+ */
+class UnknownJavaScriptObject extends JavaScriptObject {
+  const UnknownJavaScriptObject();
+
+  String toString() => JS<String>('!', 'String(#)', this);
+}
+
+class NativeError extends Interceptor {
+  String dartStack() => JS<String>('!', '#.stack', this);
+}
+
+// Note that this needs to be in interceptors.dart in order for
+// it to be picked up as an extension type.
+@JsPeerInterface(name: 'TypeError')
+class JSNoSuchMethodError extends NativeError implements NoSuchMethodError {
+  static final _nullError = RegExp(r"^Cannot read property '(.+)' of null$");
+  static final _notAFunction = RegExp(r"^(.+) is not a function$");
+  static final _extensionName = RegExp(r"^Symbol\(dartx\.(.+)\)$");
+  static final _privateName = RegExp(r"^Symbol\((_.+)\)$");
+
+  String _fieldName(String message) {
+    var match = _nullError.firstMatch(message);
+    if (match == null) return null;
+    var name = match[1];
+    match = _extensionName.firstMatch(name) ?? _privateName.firstMatch(name);
+    return match != null ? match[1] : name;
+  }
+
+  String _functionCallTarget(String message) {
+    var match = _notAFunction.firstMatch(message);
+    return match != null ? match[1] : null;
+  }
+
+  String dartStack() {
+    var stack = super.dartStack();
+    // Strip TypeError from first line.
+    stack = toString() + '\n' + stack.split('\n').sublist(1).join('\n');
+    return stack;
+  }
+
+  StackTrace get stackTrace => dart.stackTrace(this);
+
+  String toString() {
+    String message = JS('!', '#.message', this);
+    var callTarget = _functionCallTarget(message);
+    if (callTarget != null) {
+      return "NoSuchMethodError: tried to call a non-function, such as null: "
+          "'$callTarget'";
+    }
+    // TODO(vsm): Distinguish between null reference errors and other
+    // TypeErrors.  We should not get non-null TypeErrors from DDC code,
+    // but we may from native JavaScript.
+    var name = _fieldName(message);
+    if (name == null) {
+      // Not a Null NSM error: fallback to JS.
+      return JS<String>('!', '#.toString()', this);
+    }
+    return "NoSuchMethodError: invalid member on null: '$name'";
+  }
+}
+
+@JsPeerInterface(name: 'Function')
+class JSFunction extends Interceptor {
+  toString() {
+    // If the function is a Type object, we should just display the type name.
+    //
+    // Regular Dart code should typically get wrapped type objects instead of
+    // raw type (aka JS constructor) objects, however raw type objects can be
+    // exposed to Dart code via JS interop or debugging tools.
+    if (dart.isType(this)) return dart.typeName(this);
+
+    return JS<String>('!', r'"Closure: " + # + " from: " + #',
+        dart.typeName(dart.getReifiedType(this)), this);
+  }
+
+  // TODO(jmesserly): remove these once we canonicalize tearoffs.
+  operator ==(other) {
+    if (other == null) return false;
+    var boundObj = JS<Object>('', '#._boundObject', this);
+    if (boundObj == null) return JS<bool>('!', '# === #', this, other);
+    return JS(
+        'bool',
+        '# === #._boundObject && #._boundMethod === #._boundMethod',
+        boundObj,
+        other,
+        this,
+        other);
+  }
+
+  get hashCode {
+    var boundObj = JS<Object>('', '#._boundObject', this);
+    if (boundObj == null) return identityHashCode(this);
+
+    var boundMethod = JS<Object>('!', '#._boundMethod', this);
+    int hash = (17 * 31 + boundObj.hashCode) & 0x1fffffff;
+    return (hash * 31 + identityHashCode(boundMethod)) & 0x1fffffff;
+  }
+
+  get runtimeType => dart.wrapType(dart.getReifiedType(this));
+}
+
+/// A class used for implementing `null` tear-offs.
+class JSNull {
+  toString() => 'null';
+  noSuchMethod(Invocation i) => dart.defaultNoSuchMethod(null, i);
+}
+
+final Object jsNull = JSNull();
+
+// Note that this needs to be in interceptors.dart in order for
+// it to be picked up as an extension type.
+@JsPeerInterface(name: 'RangeError')
+class JSRangeError extends Interceptor implements ArgumentError {
+  StackTrace get stackTrace => dart.stackTrace(this);
+
+  get invalidValue => null;
+  get name => null;
+  get message => JS<String>('!', '#.message', this);
+
+  String toString() => "Invalid argument: $message";
+}
+
+// Obsolete in dart dev compiler. Added only so that the same version of
+// dart:html can be used in dart2js an dev compiler.
+// Warning: calls to these methods need to be removed before custom elements
+// and cross-frame dom objects behave correctly in ddc.
+// See https://github.com/dart-lang/sdk/issues/28326
+findInterceptorConstructorForType(Type type) {}
+findConstructorForNativeSubclassType(Type type, String name) {}
+getNativeInterceptor(object) {}
+setDispatchProperty(object, value) {}
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/private/isolate_helper.dart b/sdk_nnbd/lib/_internal/js_dev_runtime/private/isolate_helper.dart
new file mode 100644
index 0000000..490c4b9
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/private/isolate_helper.dart
@@ -0,0 +1,101 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library dart._isolate_helper;
+
+import 'dart:_runtime' as dart;
+import 'dart:async';
+import 'dart:_foreign_helper' show JS;
+
+/// Deprecated way of initializing `main()` in DDC, typically called from JS.
+@deprecated
+void startRootIsolate(main, args) {
+  if (args == null) args = <String>[];
+  if (args is List) {
+    if (args is! List<String>) args = List<String>.from(args);
+    // DDC attaches signatures only when torn off, and the typical way of
+    // getting `main` via the JS ABI won't do this. So use JS to invoke main.
+    if (JS<bool>('!', 'typeof # == "function"', main)) {
+      // JS will ignore extra arguments.
+      JS('', '#(#, #)', main, args, null);
+    } else {
+      // Not a function. Use a dynamic call to throw an error.
+      (main as dynamic)(args);
+    }
+  } else {
+    throw ArgumentError("Arguments to main must be a List: $args");
+  }
+}
+
+// TODO(vsm): Other libraries import global from here.  Consider replacing
+// those uses to just refer to the one in dart:runtime.
+final global = dart.global_;
+
+class TimerImpl implements Timer {
+  final bool _once;
+  int _handle;
+  int _tick = 0;
+
+  TimerImpl(int milliseconds, void callback()) : _once = true {
+    if (hasTimer()) {
+      void internalCallback() {
+        _handle = null;
+        dart.removeAsyncCallback();
+        _tick = 1;
+        callback();
+      }
+
+      dart.addAsyncCallback();
+
+      _handle = JS(
+          'int', '#.setTimeout(#, #)', global, internalCallback, milliseconds);
+    } else {
+      throw UnsupportedError("`setTimeout()` not found.");
+    }
+  }
+
+  TimerImpl.periodic(int milliseconds, void callback(Timer timer))
+      : _once = false {
+    if (hasTimer()) {
+      dart.addAsyncCallback();
+      int start = JS<int>('!', 'Date.now()');
+      _handle = JS<int>('!', '#.setInterval(#, #)', global, () {
+        int tick = this._tick + 1;
+        if (milliseconds > 0) {
+          int duration = JS<int>('!', 'Date.now()') - start;
+          if (duration > (tick + 1) * milliseconds) {
+            tick = duration ~/ milliseconds;
+          }
+        }
+        this._tick = tick;
+        callback(this);
+      }, milliseconds);
+    } else {
+      throw UnsupportedError("Periodic timer.");
+    }
+  }
+
+  int get tick => _tick;
+
+  void cancel() {
+    if (hasTimer()) {
+      if (_handle == null) return;
+      dart.removeAsyncCallback();
+      if (_once) {
+        JS('void', '#.clearTimeout(#)', global, _handle);
+      } else {
+        JS('void', '#.clearInterval(#)', global, _handle);
+      }
+      _handle = null;
+    } else {
+      throw UnsupportedError("Canceling a timer.");
+    }
+  }
+
+  bool get isActive => _handle != null;
+}
+
+bool hasTimer() {
+  return JS('', '#.setTimeout', global) != null;
+}
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/private/js_array.dart b/sdk_nnbd/lib/_internal/js_dev_runtime/private/js_array.dart
new file mode 100644
index 0000000..f064b24
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/private/js_array.dart
@@ -0,0 +1,694 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart._interceptors;
+
+/**
+ * The interceptor class for [List]. The compiler recognizes this
+ * class as an interceptor, and changes references to [:this:] to
+ * actually use the receiver of the method, which is generated as an extra
+ * argument added to each member.
+ */
+@JsPeerInterface(name: 'Array')
+class JSArray<E> implements List<E>, JSIndexable<E> {
+  const JSArray();
+
+  /**
+   * Constructor for adding type parameters to an existing JavaScript
+   * Array. Used for creating literal lists.
+   */
+  factory JSArray.of(list) {
+    // TODO(sra): Move this to core.List for better readability.
+    //
+    // TODO(jmesserly): this uses special compiler magic to close over the
+    // parameterized ES6 'JSArray' class.
+    JS('', '#.__proto__ = JSArray.prototype', list);
+    return JS('-dynamic', '#', list);
+  }
+
+  // TODO(jmesserly): consider a fixed array subclass instead.
+  factory JSArray.fixed(list) {
+    JS('', '#.__proto__ = JSArray.prototype', list);
+    JS('', r'#.fixed$length = Array', list);
+    return JS('-dynamic', '#', list);
+  }
+
+  factory JSArray.unmodifiable(list) {
+    JS('', '#.__proto__ = JSArray.prototype', list);
+    JS('', r'#.fixed$length = Array', list);
+    JS('', r'#.immutable$list = Array', list);
+    return JS('-dynamic', '#', list);
+  }
+
+  static void markFixedList(list) {
+    // Functions are stored in the hidden class and not as properties in
+    // the object. We never actually look at the value, but only want
+    // to know if the property exists.
+    JS('', r'#.fixed$length = Array', list);
+  }
+
+  static void markUnmodifiableList(list) {
+    // Functions are stored in the hidden class and not as properties in
+    // the object. We never actually look at the value, but only want
+    // to know if the property exists.
+    JS('', r'#.fixed$length = Array', list);
+    JS('', r'#.immutable$list = Array', list);
+  }
+
+  checkMutable(reason) {
+    if (JS<bool>('!', r'#.immutable$list', this)) {
+      throw UnsupportedError(reason);
+    }
+  }
+
+  checkGrowable(reason) {
+    if (JS<bool>('!', r'#.fixed$length', this)) {
+      throw UnsupportedError(reason);
+    }
+  }
+
+  List<R> cast<R>() => List.castFrom<E, R>(this);
+  void add(E value) {
+    checkGrowable('add');
+    JS('void', r'#.push(#)', this, value);
+  }
+
+  E removeAt(@nullCheck int index) {
+    checkGrowable('removeAt');
+    if (index < 0 || index >= length) {
+      throw RangeError.value(index);
+    }
+    return JS('-dynamic', r'#.splice(#, 1)[0]', this, index);
+  }
+
+  void insert(@nullCheck int index, E value) {
+    checkGrowable('insert');
+    if (index < 0 || index > length) {
+      throw RangeError.value(index);
+    }
+    JS('void', r'#.splice(#, 0, #)', this, index, value);
+  }
+
+  void insertAll(@nullCheck int index, Iterable<E> iterable) {
+    checkGrowable('insertAll');
+    RangeError.checkValueInInterval(index, 0, this.length, "index");
+    if (iterable is! EfficientLengthIterable) {
+      iterable = iterable.toList();
+    }
+    @nullCheck
+    int insertionLength = iterable.length;
+    this.length += insertionLength;
+    int end = index + insertionLength;
+    this.setRange(end, this.length, this, index);
+    this.setRange(index, end, iterable);
+  }
+
+  void setAll(@nullCheck int index, Iterable<E> iterable) {
+    checkMutable('setAll');
+    RangeError.checkValueInInterval(index, 0, this.length, "index");
+    for (var element in iterable) {
+      this[index++] = element;
+    }
+  }
+
+  E removeLast() {
+    checkGrowable('removeLast');
+    if (length == 0) throw diagnoseIndexError(this, -1);
+    return JS('var', r'#.pop()', this);
+  }
+
+  bool remove(Object element) {
+    checkGrowable('remove');
+    var length = this.length;
+    for (int i = 0; i < length; i++) {
+      if (this[i] == element) {
+        JS('var', r'#.splice(#, 1)', this, i);
+        return true;
+      }
+    }
+    return false;
+  }
+
+  /**
+   * Removes elements matching [test] from [this] List.
+   */
+  void removeWhere(bool test(E element)) {
+    checkGrowable('removeWhere');
+    _removeWhere(test, true);
+  }
+
+  void retainWhere(bool test(E element)) {
+    checkGrowable('retainWhere');
+    _removeWhere(test, false);
+  }
+
+  void _removeWhere(bool test(E element), bool removeMatching) {
+    // Performed in two steps, to avoid exposing an inconsistent state
+    // to the [test] function. First the elements to retain are found, and then
+    // the original list is updated to contain those elements.
+
+    // TODO(sra): Replace this algorithm with one that retains a list of ranges
+    // to be removed.  Most real uses remove 0, 1 or a few clustered elements.
+
+    List retained = [];
+    int end = this.length;
+    for (int i = 0; i < end; i++) {
+      // TODO(22407): Improve bounds check elimination to allow this JS code to
+      // be replaced by indexing.
+      E element = JS('-dynamic', '#[#]', this, i);
+      // !test() ensures bool conversion in checked mode.
+      if (!test(element) == removeMatching) {
+        retained.add(element);
+      }
+      if (this.length != end) throw ConcurrentModificationError(this);
+    }
+    if (retained.length == end) return;
+    this.length = retained.length;
+    @nullCheck
+    var length = retained.length;
+    for (int i = 0; i < length; i++) {
+      JS('', '#[#] = #[#]', this, i, retained, i);
+    }
+  }
+
+  Iterable<E> where(bool f(E element)) {
+    return WhereIterable<E>(this, f);
+  }
+
+  Iterable<T> expand<T>(Iterable<T> f(E element)) {
+    return ExpandIterable<E, T>(this, f);
+  }
+
+  void addAll(Iterable<E> collection) {
+    int i = this.length;
+    checkGrowable('addAll');
+    for (E e in collection) {
+      assert(i == this.length || (throw ConcurrentModificationError(this)));
+      i++;
+      JS('void', r'#.push(#)', this, e);
+    }
+  }
+
+  void clear() {
+    length = 0;
+  }
+
+  void forEach(void f(E element)) {
+    int end = this.length;
+    for (int i = 0; i < end; i++) {
+      // TODO(22407): Improve bounds check elimination to allow this JS code to
+      // be replaced by indexing.
+      var/*=E*/ element = JS('', '#[#]', this, i);
+      f(element);
+      if (this.length != end) throw ConcurrentModificationError(this);
+    }
+  }
+
+  Iterable<T> map<T>(T f(E element)) {
+    return MappedListIterable<E, T>(this, f);
+  }
+
+  String join([String separator = ""]) {
+    var length = this.length;
+    var list = List(length);
+    for (int i = 0; i < length; i++) {
+      list[i] = "${this[i]}";
+    }
+    return JS<String>('!', "#.join(#)", list, separator);
+  }
+
+  Iterable<E> take(int n) {
+    return SubListIterable<E>(this, 0, n);
+  }
+
+  Iterable<E> takeWhile(bool test(E value)) {
+    return TakeWhileIterable<E>(this, test);
+  }
+
+  Iterable<E> skip(int n) {
+    return SubListIterable<E>(this, n, null);
+  }
+
+  Iterable<E> skipWhile(bool test(E value)) {
+    return SkipWhileIterable<E>(this, test);
+  }
+
+  E reduce(E combine(E previousValue, E element)) {
+    int length = this.length;
+    if (length == 0) throw IterableElementError.noElement();
+    E value = this[0];
+    for (int i = 1; i < length; i++) {
+      // TODO(22407): Improve bounds check elimination to allow this JS code to
+      // be replaced by indexing.
+      var/*=E*/ element = JS('', '#[#]', this, i);
+      value = combine(value, element);
+      if (length != this.length) throw ConcurrentModificationError(this);
+    }
+    return value;
+  }
+
+  T fold<T>(T initialValue, T combine(T previousValue, E element)) {
+    var value = initialValue;
+    int length = this.length;
+    for (int i = 0; i < length; i++) {
+      // TODO(22407): Improve bounds check elimination to allow this JS code to
+      // be replaced by indexing.
+      var/*=E*/ element = JS('', '#[#]', this, i);
+      value = combine(value, element);
+      if (this.length != length) throw ConcurrentModificationError(this);
+    }
+    return value;
+  }
+
+  E firstWhere(bool test(E value), {E orElse()}) {
+    int end = this.length;
+    for (int i = 0; i < end; ++i) {
+      // TODO(22407): Improve bounds check elimination to allow this JS code to
+      // be replaced by indexing.
+      var/*=E*/ element = JS('', '#[#]', this, i);
+      if (test(element)) return element;
+      if (this.length != end) throw ConcurrentModificationError(this);
+    }
+    if (orElse != null) return orElse();
+    throw IterableElementError.noElement();
+  }
+
+  E lastWhere(bool test(E element), {E orElse()}) {
+    int length = this.length;
+    for (int i = length - 1; i >= 0; i--) {
+      // TODO(22407): Improve bounds check elimination to allow this JS code to
+      // be replaced by indexing.
+      var/*=E*/ element = JS('', '#[#]', this, i);
+      if (test(element)) return element;
+      if (length != this.length) {
+        throw ConcurrentModificationError(this);
+      }
+    }
+    if (orElse != null) return orElse();
+    throw IterableElementError.noElement();
+  }
+
+  E singleWhere(bool test(E element), {E orElse()}) {
+    int length = this.length;
+    E match = null;
+    bool matchFound = false;
+    for (int i = 0; i < length; i++) {
+      // TODO(22407): Improve bounds check elimination to allow this JS code to
+      // be replaced by indexing.
+      E element = JS('-dynamic', '#[#]', this, i);
+      if (test(element)) {
+        if (matchFound) {
+          throw IterableElementError.tooMany();
+        }
+        matchFound = true;
+        match = element;
+      }
+      if (length != this.length) {
+        throw ConcurrentModificationError(this);
+      }
+    }
+    if (matchFound) return match;
+    if (orElse != null) return orElse();
+    throw IterableElementError.noElement();
+  }
+
+  E elementAt(int index) {
+    return this[index];
+  }
+
+  List<E> sublist(@nullCheck int start, [int end]) {
+    if (start < 0 || start > length) {
+      throw RangeError.range(start, 0, length, "start");
+    }
+    if (end == null) {
+      end = length;
+    } else {
+      @notNull
+      var _end = end;
+      if (_end < start || _end > length) {
+        throw RangeError.range(end, start, length, "end");
+      }
+    }
+    if (start == end) return <E>[];
+    return JSArray<E>.of(JS('', r'#.slice(#, #)', this, start, end));
+  }
+
+  Iterable<E> getRange(int start, int end) {
+    RangeError.checkValidRange(start, end, this.length);
+    return SubListIterable<E>(this, start, end);
+  }
+
+  E get first {
+    if (length > 0) return this[0];
+    throw IterableElementError.noElement();
+  }
+
+  E get last {
+    if (length > 0) return this[length - 1];
+    throw IterableElementError.noElement();
+  }
+
+  E get single {
+    if (length == 1) return this[0];
+    if (length == 0) throw IterableElementError.noElement();
+    throw IterableElementError.tooMany();
+  }
+
+  void removeRange(@nullCheck int start, @nullCheck int end) {
+    checkGrowable('removeRange');
+    RangeError.checkValidRange(start, end, this.length);
+    int deleteCount = end - start;
+    JS('', '#.splice(#, #)', this, start, deleteCount);
+  }
+
+  void setRange(@nullCheck int start, @nullCheck int end, Iterable<E> iterable,
+      [@nullCheck int skipCount = 0]) {
+    checkMutable('set range');
+
+    RangeError.checkValidRange(start, end, this.length);
+    int length = end - start;
+    if (length == 0) return;
+    RangeError.checkNotNegative(skipCount, "skipCount");
+
+    List<E> otherList;
+    int otherStart = 0;
+    // TODO(floitsch): Make this accept more.
+    if (iterable is List<E>) {
+      otherList = iterable;
+      otherStart = skipCount;
+    } else {
+      otherList = iterable.skip(skipCount).toList(growable: false);
+      otherStart = 0;
+    }
+    if (otherStart + length > otherList.length) {
+      throw IterableElementError.tooFew();
+    }
+    if (otherStart < start) {
+      // Copy backwards to ensure correct copy if [from] is this.
+      // TODO(sra): If [from] is the same Array as [this], we can copy without
+      // type annotation checks on the stores.
+      for (int i = length - 1; i >= 0; i--) {
+        // Use JS to avoid bounds check (the bounds check elimination
+        // optimzation is too weak). The 'E' type annotation is a store type
+        // check - we can't rely on iterable, it could be List<dynamic>.
+        E element = otherList[otherStart + i];
+        JS('', '#[#] = #', this, start + i, element);
+      }
+    } else {
+      for (int i = 0; i < length; i++) {
+        E element = otherList[otherStart + i];
+        JS('', '#[#] = #', this, start + i, element);
+      }
+    }
+  }
+
+  void fillRange(@nullCheck int start, @nullCheck int end, [E fillValue]) {
+    checkMutable('fill range');
+    RangeError.checkValidRange(start, end, this.length);
+    for (int i = start; i < end; i++) {
+      // Store is safe since [fillValue] type has been checked as parameter.
+      JS('', '#[#] = #', this, i, fillValue);
+    }
+  }
+
+  void replaceRange(
+      @nullCheck int start, @nullCheck int end, Iterable<E> replacement) {
+    checkGrowable('replace range');
+    RangeError.checkValidRange(start, end, this.length);
+    if (replacement is! EfficientLengthIterable) {
+      replacement = replacement.toList();
+    }
+    int removeLength = end - start;
+    @nullCheck
+    int insertLength = replacement.length;
+    if (removeLength >= insertLength) {
+      int delta = removeLength - insertLength;
+      int insertEnd = start + insertLength;
+      int newLength = this.length - delta;
+      this.setRange(start, insertEnd, replacement);
+      if (delta != 0) {
+        this.setRange(insertEnd, newLength, this, end);
+        this.length = newLength;
+      }
+    } else {
+      int delta = insertLength - removeLength;
+      int newLength = this.length + delta;
+      int insertEnd = start + insertLength; // aka. end + delta.
+      this.length = newLength;
+      this.setRange(insertEnd, newLength, this, end);
+      this.setRange(start, insertEnd, replacement);
+    }
+  }
+
+  bool any(bool test(E element)) {
+    int end = this.length;
+    for (int i = 0; i < end; i++) {
+      // TODO(22407): Improve bounds check elimination to allow this JS code to
+      // be replaced by indexing.
+      var/*=E*/ element = JS('', '#[#]', this, i);
+      if (test(element)) return true;
+      if (this.length != end) throw ConcurrentModificationError(this);
+    }
+    return false;
+  }
+
+  bool every(bool test(E element)) {
+    int end = this.length;
+    for (int i = 0; i < end; i++) {
+      // TODO(22407): Improve bounds check elimination to allow this JS code to
+      // be replaced by indexing.
+      E element = JS('-dynamic', '#[#]', this, i);
+      if (!test(element)) return false;
+      if (this.length != end) throw ConcurrentModificationError(this);
+    }
+    return true;
+  }
+
+  Iterable<E> get reversed => ReversedListIterable<E>(this);
+
+  void sort([int compare(E a, E b)]) {
+    checkMutable('sort');
+    if (compare == null) {
+      Sort.sort(this, (a, b) => Comparable.compare(a, b));
+    } else {
+      Sort.sort(this, compare);
+    }
+  }
+
+  void shuffle([Random random]) {
+    checkMutable('shuffle');
+    if (random == null) random = Random();
+    int length = this.length;
+    while (length > 1) {
+      int pos = random.nextInt(length);
+      length -= 1;
+      var tmp = this[length];
+      this[length] = this[pos];
+      this[pos] = tmp;
+    }
+  }
+
+  int indexOf(Object element, [@nullCheck int start = 0]) {
+    int length = this.length;
+    if (start >= length) {
+      return -1;
+    }
+    if (start < 0) {
+      start = 0;
+    }
+    for (int i = start; i < length; i++) {
+      if (this[i] == element) {
+        return i;
+      }
+    }
+    return -1;
+  }
+
+  int lastIndexOf(Object element, [int _startIndex]) {
+    @notNull
+    int startIndex = _startIndex ?? this.length - 1;
+    if (startIndex >= this.length) {
+      startIndex = this.length - 1;
+    } else if (startIndex < 0) {
+      return -1;
+    }
+    for (int i = startIndex; i >= 0; i--) {
+      if (this[i] == element) {
+        return i;
+      }
+    }
+    return -1;
+  }
+
+  bool contains(Object other) {
+    var length = this.length;
+    for (int i = 0; i < length; i++) {
+      E element = JS('Null', '#[#]', this, i);
+      if (element == other) return true;
+    }
+    return false;
+  }
+
+  @notNull
+  bool get isEmpty => length == 0;
+
+  @notNull
+  bool get isNotEmpty => !isEmpty;
+
+  String toString() => ListBase.listToString(this);
+
+  List<E> toList({@nullCheck bool growable = true}) {
+    var list = JS('', '#.slice()', this);
+    if (!growable) markFixedList(list);
+    return JSArray<E>.of(list);
+  }
+
+  Set<E> toSet() => Set<E>.from(this);
+
+  Iterator<E> get iterator => ArrayIterator<E>(this);
+
+  int get hashCode => identityHashCode(this);
+
+  @notNull
+  bool operator ==(other) => identical(this, other);
+
+  @notNull
+  int get length => JS<int>('!', r'#.length', this);
+
+  void set length(@nullCheck int newLength) {
+    checkGrowable('set length');
+    // TODO(sra): Remove this test and let JavaScript throw an error.
+    if (newLength < 0) {
+      throw RangeError.range(newLength, 0, null, 'newLength');
+    }
+    // JavaScript with throw a RangeError for numbers that are too big. The
+    // message does not contain the value.
+    JS('void', r'#.length = #', this, newLength);
+  }
+
+  E operator [](int index) {
+    // Suppress redundant null checks via JS.
+    if (index == null ||
+        JS<int>('!', '#', index) >= JS<int>('!', '#.length', this) ||
+        JS<int>('!', '#', index) < 0) {
+      throw diagnoseIndexError(this, index);
+    }
+    return JS('var', '#[#]', this, index);
+  }
+
+  void operator []=(int index, E value) {
+    checkMutable('indexed set');
+    if (index == null ||
+        JS<int>('!', '#', index) >= JS<int>('!', '#.length', this) ||
+        JS<int>('!', '#', index) < 0) {
+      throw diagnoseIndexError(this, index);
+    }
+    JS('void', r'#[#] = #', this, index, value);
+  }
+
+  Map<int, E> asMap() {
+    return ListMapView<E>(this);
+  }
+
+  Type get runtimeType =>
+      dart.wrapType(JS('', '#(#)', dart.getGenericClass(List), E));
+
+  Iterable<E> followedBy(Iterable<E> other) =>
+      FollowedByIterable<E>.firstEfficient(this, other);
+
+  Iterable<T> whereType<T>() => new WhereTypeIterable<T>(this);
+
+  List<E> operator +(List<E> other) {
+    int totalLength = this.length + other.length;
+    return <E>[]
+      ..length = totalLength
+      ..setRange(0, this.length, this)
+      ..setRange(this.length, totalLength, other);
+  }
+
+  int indexWhere(bool test(E element), [int start = 0]) {
+    if (start >= this.length) return -1;
+    if (start < 0) start = 0;
+    for (int i = start; i < this.length; i++) {
+      if (test(this[i])) return i;
+    }
+    return -1;
+  }
+
+  int lastIndexWhere(bool test(E element), [int start]) {
+    if (start == null) start = this.length - 1;
+    if (start < 0) return -1;
+    for (int i = start; i >= 0; i--) {
+      if (test(this[i])) return i;
+    }
+    return -1;
+  }
+
+  void set first(E element) {
+    if (this.isEmpty) throw RangeError.index(0, this);
+    this[0] = element;
+  }
+
+  void set last(E element) {
+    if (this.isEmpty) throw RangeError.index(0, this);
+    this[this.length - 1] = element;
+  }
+}
+
+/**
+ * Dummy subclasses that allow the backend to track more precise
+ * information about arrays through their type. The CPA type inference
+ * relies on the fact that these classes do not override [] nor []=.
+ *
+ * These classes are really a fiction, and can have no methods, since
+ * getInterceptor always returns JSArray.  We should consider pushing the
+ * 'isGrowable' and 'isMutable' checks into the getInterceptor implementation so
+ * these classes can have specialized implementations. Doing so will challenge
+ * many assumptions in the JS backend.
+ */
+class JSMutableArray<E> extends JSArray<E> {}
+
+class JSFixedArray<E> extends JSMutableArray<E> {}
+
+class JSExtendableArray<E> extends JSMutableArray<E> {}
+
+class JSUnmodifiableArray<E> extends JSArray<E> {} // Already is JSIndexable.
+
+/// An [Iterator] that iterates a JSArray.
+///
+class ArrayIterator<E> implements Iterator<E> {
+  final JSArray<E> _iterable;
+  @notNull
+  final int _length;
+  @notNull
+  int _index;
+  E _current;
+
+  ArrayIterator(JSArray<E> iterable)
+      : _iterable = iterable,
+        _length = iterable.length,
+        _index = 0;
+
+  E get current => _current;
+
+  bool moveNext() {
+    @notNull
+    int length = _iterable.length;
+
+    // We have to do the length check even on fixed length Arrays.  If we can
+    // inline moveNext() we might be able to GVN the length and eliminate this
+    // check on known fixed length JSArray.
+    if (_length != length) {
+      throw throwConcurrentModificationError(_iterable);
+    }
+
+    if (_index >= length) {
+      _current = null;
+      return false;
+    }
+    _current = _iterable[_index];
+    _index++;
+    return true;
+  }
+}
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/private/js_helper.dart b/sdk_nnbd/lib/_internal/js_dev_runtime/private/js_helper.dart
new file mode 100644
index 0000000..5d6b037
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/private/js_helper.dart
@@ -0,0 +1,826 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library dart._js_helper;
+
+import 'dart:collection';
+
+import 'dart:_foreign_helper' show JS, JS_STRING_CONCAT, JSExportName;
+
+import 'dart:_interceptors';
+import 'dart:_internal'
+    show
+        EfficientLengthIterable,
+        MappedIterable,
+        IterableElementError,
+        SubListIterable;
+
+import 'dart:_native_typed_data';
+import 'dart:_runtime' as dart;
+
+part 'annotations.dart';
+part 'linked_hash_map.dart';
+part 'identity_hash_map.dart';
+part 'custom_hash_map.dart';
+part 'native_helper.dart';
+part 'regexp_helper.dart';
+part 'string_helper.dart';
+part 'js_rti.dart';
+
+class _Patch {
+  const _Patch();
+}
+
+const _Patch patch = _Patch();
+
+/// Adapts a JS `[Symbol.iterator]` to a Dart `get iterator`.
+///
+/// This is the inverse of `JsIterator`, for classes where we can more
+/// efficiently obtain a JS iterator instead of a Dart one.
+///
+// TODO(jmesserly): this adapter is to work around
+// https://github.com/dart-lang/sdk/issues/28320
+class DartIterator<E> implements Iterator<E> {
+  final _jsIterator;
+  E _current;
+
+  DartIterator(this._jsIterator);
+
+  E get current => _current;
+
+  bool moveNext() {
+    final ret = JS('', '#.next()', _jsIterator);
+    _current = JS('', '#.value', ret);
+    return JS<bool>('!', '!#.done', ret);
+  }
+}
+
+/// Used to compile `sync*`.
+class SyncIterable<E> extends IterableBase<E> {
+  final Function() _initGenerator;
+  SyncIterable(this._initGenerator);
+
+  @JSExportName('Symbol.iterator')
+  _jsIterator() => _initGenerator();
+
+  get iterator => DartIterator(_initGenerator());
+}
+
+class Primitives {
+  @NoInline()
+  static int _parseIntError(String source, int handleError(String source)) {
+    if (handleError == null) throw FormatException(source);
+    return handleError(source);
+  }
+
+  static int parseInt(
+      @nullCheck String source, int _radix, int handleError(String source)) {
+    var re = JS('', r'/^\s*[+-]?((0x[a-f0-9]+)|(\d+)|([a-z0-9]+))\s*$/i');
+    // TODO(jmesserly): this isn't reified List<String>, but it's safe to use as
+    // long as we use it locally and don't expose it to user code.
+    List<String> match = JS('', '#.exec(#)', re, source);
+    int digitsIndex = 1;
+    int hexIndex = 2;
+    int decimalIndex = 3;
+    if (match == null) {
+      // TODO(sra): It might be that the match failed due to unrecognized U+0085
+      // spaces.  We could replace them with U+0020 spaces and try matching
+      // again.
+      return _parseIntError(source, handleError);
+    }
+    String decimalMatch = match[decimalIndex];
+    if (_radix == null) {
+      if (decimalMatch != null) {
+        // Cannot fail because we know that the digits are all decimal.
+        return JS<int>('!', r'parseInt(#, 10)', source);
+      }
+      if (match[hexIndex] != null) {
+        // Cannot fail because we know that the digits are all hex.
+        return JS<int>('!', r'parseInt(#, 16)', source);
+      }
+      return _parseIntError(source, handleError);
+    }
+    @notNull
+    var radix = _radix;
+    if (radix < 2 || radix > 36) {
+      throw RangeError.range(radix, 2, 36, 'radix');
+    }
+    if (radix == 10 && decimalMatch != null) {
+      // Cannot fail because we know that the digits are all decimal.
+      return JS<int>('!', r'parseInt(#, 10)', source);
+    }
+    // If radix >= 10 and we have only decimal digits the string is safe.
+    // Otherwise we need to check the digits.
+    if (radix < 10 || decimalMatch == null) {
+      // We know that the characters must be ASCII as otherwise the
+      // regexp wouldn't have matched. Lowercasing by doing `| 0x20` is thus
+      // guaranteed to be a safe operation, since it preserves digits
+      // and lower-cases ASCII letters.
+      int maxCharCode;
+      if (radix <= 10) {
+        // Allow all digits less than the radix. For example 0, 1, 2 for
+        // radix 3.
+        // "0".codeUnitAt(0) + radix - 1;
+        maxCharCode = (0x30 - 1) + radix;
+      } else {
+        // Letters are located after the digits in ASCII. Therefore we
+        // only check for the character code. The regexp above made already
+        // sure that the string does not contain anything but digits or
+        // letters.
+        // "a".codeUnitAt(0) + (radix - 10) - 1;
+        maxCharCode = (0x61 - 10 - 1) + radix;
+      }
+      assert(match[digitsIndex] is String);
+      String digitsPart = JS<String>('!', '#[#]', match, digitsIndex);
+      for (int i = 0; i < digitsPart.length; i++) {
+        int characterCode = digitsPart.codeUnitAt(i) | 0x20;
+        if (characterCode > maxCharCode) {
+          return _parseIntError(source, handleError);
+        }
+      }
+    }
+    // The above matching and checks ensures the source has at least one digits
+    // and all digits are suitable for the radix, so parseInt cannot return NaN.
+    return JS<int>('!', r'parseInt(#, #)', source, radix);
+  }
+
+  @NoInline()
+  static double _parseDoubleError(
+      String source, double handleError(String source)) {
+    if (handleError == null) {
+      throw FormatException('Invalid double', source);
+    }
+    return handleError(source);
+  }
+
+  static double parseDouble(
+      @nullCheck String source, double handleError(String source)) {
+    // Notice that JS parseFloat accepts garbage at the end of the string.
+    // Accept only:
+    // - [+/-]NaN
+    // - [+/-]Infinity
+    // - a Dart double literal
+    // We do allow leading or trailing whitespace.
+    if (!JS(
+        'bool',
+        r'/^\s*[+-]?(?:Infinity|NaN|'
+            r'(?:\.\d+|\d+(?:\.\d*)?)(?:[eE][+-]?\d+)?)\s*$/.test(#)',
+        source)) {
+      return _parseDoubleError(source, handleError);
+    }
+    num result = JS('!', r'parseFloat(#)', source);
+    if (result.isNaN) {
+      var trimmed = source.trim();
+      if (trimmed == 'NaN' || trimmed == '+NaN' || trimmed == '-NaN') {
+        return result;
+      }
+      return _parseDoubleError(source, handleError);
+    }
+    return result;
+  }
+
+  /** `r"$".codeUnitAt(0)` */
+  static const int DOLLAR_CHAR_VALUE = 36;
+
+  static int dateNow() => JS<int>('!', r'Date.now()');
+
+  static void initTicker() {
+    if (timerFrequency != null) return;
+    // Start with low-resolution. We overwrite the fields if we find better.
+    timerFrequency = 1000;
+    timerTicks = dateNow;
+    if (JS<bool>('!', 'typeof window == "undefined"')) return;
+    var jsWindow = JS('var', 'window');
+    if (jsWindow == null) return;
+    var performance = JS('var', '#.performance', jsWindow);
+    if (performance == null) return;
+    if (JS<bool>('!', 'typeof #.now != "function"', performance)) return;
+    timerFrequency = 1000000;
+    timerTicks = () => (1000 * JS<num>('!', '#.now()', performance)).floor();
+  }
+
+  static int timerFrequency;
+  static num Function() timerTicks;
+
+  static bool get isD8 {
+    return JS(
+        'bool',
+        'typeof version == "function"'
+            ' && typeof os == "object" && "system" in os');
+  }
+
+  static bool get isJsshell {
+    return JS(
+        'bool', 'typeof version == "function" && typeof system == "function"');
+  }
+
+  static String currentUri() {
+    // In a browser return self.location.href.
+    if (JS<bool>('!', '!!#.location', dart.global_)) {
+      return JS<String>('!', '#.location.href', dart.global_);
+    }
+
+    // TODO(vsm): Consider supporting properly in non-browser settings.
+    return '';
+  }
+
+  // This is to avoid stack overflows due to very large argument arrays in
+  // apply().  It fixes http://dartbug.com/6919
+  @notNull
+  static String _fromCharCodeApply(List<int> array) {
+    const kMaxApply = 500;
+    @nullCheck
+    int end = array.length;
+    if (end <= kMaxApply) {
+      return JS<String>('!', r'String.fromCharCode.apply(null, #)', array);
+    }
+    String result = '';
+    for (int i = 0; i < end; i += kMaxApply) {
+      int chunkEnd = (i + kMaxApply < end) ? i + kMaxApply : end;
+      result = JS(
+          'String',
+          r'# + String.fromCharCode.apply(null, #.slice(#, #))',
+          result,
+          array,
+          i,
+          chunkEnd);
+    }
+    return result;
+  }
+
+  @notNull
+  static String stringFromCodePoints(JSArray<int> codePoints) {
+    List<int> a = <int>[];
+    for (@nullCheck var i in codePoints) {
+      if (i <= 0xffff) {
+        a.add(i);
+      } else if (i <= 0x10ffff) {
+        a.add(0xd800 + ((((i - 0x10000) >> 10) & 0x3ff)));
+        a.add(0xdc00 + (i & 0x3ff));
+      } else {
+        throw argumentErrorValue(i);
+      }
+    }
+    return _fromCharCodeApply(a);
+  }
+
+  @notNull
+  static String stringFromCharCodes(JSArray<int> charCodes) {
+    for (@nullCheck var i in charCodes) {
+      if (i < 0) throw argumentErrorValue(i);
+      if (i > 0xffff) return stringFromCodePoints(charCodes);
+    }
+    return _fromCharCodeApply(charCodes);
+  }
+
+  // [start] and [end] are validated.
+  @notNull
+  static String stringFromNativeUint8List(
+      NativeUint8List charCodes, @nullCheck int start, @nullCheck int end) {
+    const kMaxApply = 500;
+    if (end <= kMaxApply && start == 0 && end == charCodes.length) {
+      return JS<String>('!', r'String.fromCharCode.apply(null, #)', charCodes);
+    }
+    String result = '';
+    for (int i = start; i < end; i += kMaxApply) {
+      int chunkEnd = (i + kMaxApply < end) ? i + kMaxApply : end;
+      result = JS(
+          'String',
+          r'# + String.fromCharCode.apply(null, #.subarray(#, #))',
+          result,
+          charCodes,
+          i,
+          chunkEnd);
+    }
+    return result;
+  }
+
+  @notNull
+  static String stringFromCharCode(@nullCheck int charCode) {
+    if (0 <= charCode) {
+      if (charCode <= 0xffff) {
+        return JS<String>('!', 'String.fromCharCode(#)', charCode);
+      }
+      if (charCode <= 0x10ffff) {
+        var bits = charCode - 0x10000;
+        var low = 0xDC00 | (bits & 0x3ff);
+        var high = 0xD800 | (bits >> 10);
+        return JS<String>('!', 'String.fromCharCode(#, #)', high, low);
+      }
+    }
+    throw RangeError.range(charCode, 0, 0x10ffff);
+  }
+
+  static String stringConcatUnchecked(String string1, String string2) {
+    return JS_STRING_CONCAT(string1, string2);
+  }
+
+  static String flattenString(String str) {
+    return JS<String>('!', "#.charCodeAt(0) == 0 ? # : #", str, str, str);
+  }
+
+  static String getTimeZoneName(DateTime receiver) {
+    // Firefox and Chrome emit the timezone in parenthesis.
+    // Example: "Wed May 16 2012 21:13:00 GMT+0200 (CEST)".
+    // We extract this name using a regexp.
+    var d = lazyAsJsDate(receiver);
+    List match = JS('JSArray|Null', r'/\((.*)\)/.exec(#.toString())', d);
+    if (match != null) return match[1];
+
+    // Internet Explorer 10+ emits the zone name without parenthesis:
+    // Example: Thu Oct 31 14:07:44 PDT 2013
+    match = JS(
+        'JSArray|Null',
+        // Thu followed by a space.
+        r'/^[A-Z,a-z]{3}\s'
+            // Oct 31 followed by space.
+            r'[A-Z,a-z]{3}\s\d+\s'
+            // Time followed by a space.
+            r'\d{2}:\d{2}:\d{2}\s'
+            // The time zone name followed by a space.
+            r'([A-Z]{3,5})\s'
+            // The year.
+            r'\d{4}$/'
+            '.exec(#.toString())',
+        d);
+    if (match != null) return match[1];
+
+    // IE 9 and Opera don't provide the zone name. We fall back to emitting the
+    // UTC/GMT offset.
+    // Example (IE9): Wed Nov 20 09:51:00 UTC+0100 2013
+    //       (Opera): Wed Nov 20 2013 11:03:38 GMT+0100
+    match = JS('JSArray|Null', r'/(?:GMT|UTC)[+-]\d{4}/.exec(#.toString())', d);
+    if (match != null) return match[0];
+    return "";
+  }
+
+  static int getTimeZoneOffsetInMinutes(DateTime receiver) {
+    // Note that JS and Dart disagree on the sign of the offset.
+    return -JS<int>('!', r'#.getTimezoneOffset()', lazyAsJsDate(receiver));
+  }
+
+  static num valueFromDecomposedDate(
+      @nullCheck int years,
+      @nullCheck int month,
+      @nullCheck int day,
+      @nullCheck int hours,
+      @nullCheck int minutes,
+      @nullCheck int seconds,
+      @nullCheck int milliseconds,
+      @nullCheck bool isUtc) {
+    final int MAX_MILLISECONDS_SINCE_EPOCH = 8640000000000000;
+    var jsMonth = month - 1;
+    num value;
+    if (isUtc) {
+      value = JS('!', r'Date.UTC(#, #, #, #, #, #, #)', years, jsMonth, day,
+          hours, minutes, seconds, milliseconds);
+    } else {
+      value = JS('!', r'new Date(#, #, #, #, #, #, #).valueOf()', years,
+          jsMonth, day, hours, minutes, seconds, milliseconds);
+    }
+    if (value.isNaN ||
+        value < -MAX_MILLISECONDS_SINCE_EPOCH ||
+        value > MAX_MILLISECONDS_SINCE_EPOCH) {
+      return null;
+    }
+    if (years <= 0 || years < 100) return patchUpY2K(value, years, isUtc);
+    return value;
+  }
+
+  static num patchUpY2K(value, years, isUtc) {
+    var date = JS('', r'new Date(#)', value);
+    if (isUtc) {
+      JS('', r'#.setUTCFullYear(#)', date, years);
+    } else {
+      JS('', r'#.setFullYear(#)', date, years);
+    }
+    return JS('!', r'#.valueOf()', date);
+  }
+
+  // Lazily keep a JS Date stored in the JS object.
+  static lazyAsJsDate(DateTime receiver) {
+    if (JS<bool>('!', r'#.date === (void 0)', receiver)) {
+      JS('void', r'#.date = new Date(#)', receiver,
+          receiver.millisecondsSinceEpoch);
+    }
+    return JS('var', r'#.date', receiver);
+  }
+
+  // The getters for date and time parts below add a positive integer to ensure
+  // that the result is really an integer, because the JavaScript implementation
+  // may return -0.0 instead of 0.
+
+  static int getYear(DateTime receiver) {
+    return (receiver.isUtc)
+        ? JS<int>('!', r'(#.getUTCFullYear() + 0)', lazyAsJsDate(receiver))
+        : JS<int>('!', r'(#.getFullYear() + 0)', lazyAsJsDate(receiver));
+  }
+
+  static int getMonth(DateTime receiver) {
+    return (receiver.isUtc)
+        ? JS<int>('!', r'#.getUTCMonth() + 1', lazyAsJsDate(receiver))
+        : JS<int>('!', r'#.getMonth() + 1', lazyAsJsDate(receiver));
+  }
+
+  static int getDay(DateTime receiver) {
+    return (receiver.isUtc)
+        ? JS<int>('!', r'(#.getUTCDate() + 0)', lazyAsJsDate(receiver))
+        : JS<int>('!', r'(#.getDate() + 0)', lazyAsJsDate(receiver));
+  }
+
+  static int getHours(DateTime receiver) {
+    return (receiver.isUtc)
+        ? JS<int>('!', r'(#.getUTCHours() + 0)', lazyAsJsDate(receiver))
+        : JS<int>('!', r'(#.getHours() + 0)', lazyAsJsDate(receiver));
+  }
+
+  static int getMinutes(DateTime receiver) {
+    return (receiver.isUtc)
+        ? JS<int>('!', r'(#.getUTCMinutes() + 0)', lazyAsJsDate(receiver))
+        : JS<int>('!', r'(#.getMinutes() + 0)', lazyAsJsDate(receiver));
+  }
+
+  static int getSeconds(DateTime receiver) {
+    return (receiver.isUtc)
+        ? JS<int>('!', r'(#.getUTCSeconds() + 0)', lazyAsJsDate(receiver))
+        : JS<int>('!', r'(#.getSeconds() + 0)', lazyAsJsDate(receiver));
+  }
+
+  static int getMilliseconds(DateTime receiver) {
+    return (receiver.isUtc)
+        ? JS<int>('!', r'(#.getUTCMilliseconds() + 0)', lazyAsJsDate(receiver))
+        : JS<int>('!', r'(#.getMilliseconds() + 0)', lazyAsJsDate(receiver));
+  }
+
+  static int getWeekday(DateTime receiver) {
+    int weekday = (receiver.isUtc)
+        ? JS<int>('!', r'#.getUTCDay() + 0', lazyAsJsDate(receiver))
+        : JS<int>('!', r'#.getDay() + 0', lazyAsJsDate(receiver));
+    // Adjust by one because JS weeks start on Sunday.
+    return (weekday + 6) % 7 + 1;
+  }
+
+  static num valueFromDateString(str) {
+    if (str is! String) throw argumentErrorValue(str);
+    num value = JS('!', r'Date.parse(#)', str);
+    if (value.isNaN) throw argumentErrorValue(str);
+    return value;
+  }
+
+  static getProperty(object, key) {
+    if (object == null || object is bool || object is num || object is String) {
+      throw argumentErrorValue(object);
+    }
+    return JS('var', '#[#]', object, key);
+  }
+
+  static void setProperty(object, key, value) {
+    if (object == null || object is bool || object is num || object is String) {
+      throw argumentErrorValue(object);
+    }
+    JS('void', '#[#] = #', object, key, value);
+  }
+}
+
+/**
+ * Diagnoses an indexing error. Returns the ArgumentError or RangeError that
+ * describes the problem.
+ */
+@NoInline()
+Error diagnoseIndexError(indexable, int index) {
+  int length = indexable.length;
+  // The following returns the same error that would be thrown by calling
+  // [RangeError.checkValidIndex] with no optional parameters provided.
+  if (index < 0 || index >= length) {
+    return RangeError.index(index, indexable, 'index', null, length);
+  }
+  // The above should always match, but if it does not, use the following.
+  return RangeError.value(index, 'index');
+}
+
+/**
+ * Diagnoses a range error. Returns the ArgumentError or RangeError that
+ * describes the problem.
+ */
+@NoInline()
+Error diagnoseRangeError(int start, int end, int length) {
+  if (start == null) {
+    return ArgumentError.value(start, 'start');
+  }
+  if (start < 0 || start > length) {
+    return RangeError.range(start, 0, length, 'start');
+  }
+  if (end != null) {
+    if (end < start || end > length) {
+      return RangeError.range(end, start, length, 'end');
+    }
+  }
+  // The above should always match, but if it does not, use the following.
+  return ArgumentError.value(end, "end");
+}
+
+@notNull
+int stringLastIndexOfUnchecked(receiver, element, start) =>
+    JS<int>('!', r'#.lastIndexOf(#, #)', receiver, element, start);
+
+/// 'factory' for constructing ArgumentError.value to keep the call sites small.
+@NoInline()
+ArgumentError argumentErrorValue(object) {
+  return ArgumentError.value(object);
+}
+
+void throwArgumentErrorValue(value) {
+  throw argumentErrorValue(value);
+}
+
+checkInt(value) {
+  if (value is! int) throw argumentErrorValue(value);
+  return value;
+}
+
+throwRuntimeError(message) {
+  throw RuntimeError(message);
+}
+
+throwAbstractClassInstantiationError(className) {
+  throw AbstractClassInstantiationError(className);
+}
+
+@NoInline()
+throwConcurrentModificationError(collection) {
+  throw ConcurrentModificationError(collection);
+}
+
+class JsNoSuchMethodError extends Error implements NoSuchMethodError {
+  final String _message;
+  final String _method;
+  final String _receiver;
+
+  JsNoSuchMethodError(this._message, match)
+      : _method = match == null ? null : JS('String|Null', '#.method', match),
+        _receiver =
+            match == null ? null : JS('String|Null', '#.receiver', match);
+
+  String toString() {
+    if (_method == null) return 'NoSuchMethodError: $_message';
+    if (_receiver == null) {
+      return "NoSuchMethodError: method not found: '$_method' ($_message)";
+    }
+    return "NoSuchMethodError: "
+        "method not found: '$_method' on '$_receiver' ($_message)";
+  }
+}
+
+class UnknownJsTypeError extends Error {
+  final String _message;
+
+  UnknownJsTypeError(this._message);
+
+  String toString() => _message.isEmpty ? 'Error' : 'Error: $_message';
+}
+
+/**
+ * Called by generated code to build a map literal. [keyValuePairs] is
+ * a list of key, value, key, value, ..., etc.
+ */
+fillLiteralMap(keyValuePairs, Map result) {
+  // TODO(johnniwinther): Use JSArray to optimize this code instead of calling
+  // [getLength] and [getIndex].
+  int index = 0;
+  int length = getLength(keyValuePairs);
+  while (index < length) {
+    var key = getIndex(keyValuePairs, index++);
+    var value = getIndex(keyValuePairs, index++);
+    result[key] = value;
+  }
+  return result;
+}
+
+bool jsHasOwnProperty(var jsObject, String property) {
+  return JS<bool>('!', r'#.hasOwnProperty(#)', jsObject, property);
+}
+
+jsPropertyAccess(var jsObject, String property) {
+  return JS('var', r'#[#]', jsObject, property);
+}
+
+/**
+ * Called at the end of unaborted switch cases to get the singleton
+ * FallThroughError exception that will be thrown.
+ */
+getFallThroughError() => FallThroughErrorImplementation();
+
+/**
+ * A metadata annotation describing the types instantiated by a native element.
+ *
+ * The annotation is valid on a native method and a field of a native class.
+ *
+ * By default, a field of a native class is seen as an instantiation point for
+ * all native classes that are a subtype of the field's type, and a native
+ * method is seen as an instantiation point fo all native classes that are a
+ * subtype of the method's return type, or the argument types of the declared
+ * type of the method's callback parameter.
+ *
+ * An @[Creates] annotation overrides the default set of instantiated types.  If
+ * one or more @[Creates] annotations are present, the type of the native
+ * element is ignored, and the union of @[Creates] annotations is used instead.
+ * The names in the strings are resolved and the program will fail to compile
+ * with dart2js if they do not name types.
+ *
+ * The argument to [Creates] is a string.  The string is parsed as the names of
+ * one or more types, separated by vertical bars `|`.  There are some special
+ * names:
+ *
+ * * `=Object`. This means 'exactly Object', which is a plain JavaScript object
+ *   with properties and none of the subtypes of Object.
+ *
+ * Example: we may know that a method always returns a specific implementation:
+ *
+ *     @Creates('_NodeList')
+ *     List<Node> getElementsByTagName(String tag) native;
+ *
+ * Useful trick: A method can be marked as not instantiating any native classes
+ * with the annotation `@Creates('Null')`.  This is useful for fields on native
+ * classes that are used only in Dart code.
+ *
+ *     @Creates('Null')
+ *     var _cachedFoo;
+ */
+class Creates {
+  final String types;
+  const Creates(this.types);
+}
+
+/**
+ * A metadata annotation describing the types returned or yielded by a native
+ * element.
+ *
+ * The annotation is valid on a native method and a field of a native class.
+ *
+ * By default, a native method or field is seen as returning or yielding all
+ * subtypes if the method return type or field type.  This annotation allows a
+ * more precise set of types to be specified.
+ *
+ * See [Creates] for the syntax of the argument.
+ *
+ * Example: IndexedDB keys are numbers, strings and JavaScript Arrays of keys.
+ *
+ *     @Returns('String|num|JSExtendableArray')
+ *     dynamic key;
+ *
+ *     // Equivalent:
+ *     @Returns('String') @Returns('num') @Returns('JSExtendableArray')
+ *     dynamic key;
+ */
+class Returns {
+  final String types;
+  const Returns(this.types);
+}
+
+/**
+ * A metadata annotation placed on native methods and fields of native classes
+ * to specify the JavaScript name.
+ *
+ * This example declares a Dart field + getter + setter called `$dom_title` that
+ * corresponds to the JavaScript property `title`.
+ *
+ *     class Document native "*Foo" {
+ *       @JSName('title')
+ *       String $dom_title;
+ *     }
+ */
+class JSName {
+  final String name;
+  const JSName(this.name);
+}
+
+/**
+ * Special interface recognized by the compiler and implemented by DOM
+ * objects that support integer indexing. This interface is not
+ * visible to anyone, and is only injected into special libraries.
+ */
+abstract class JavaScriptIndexingBehavior<E> {}
+
+// TODO(lrn): These exceptions should be implemented in core.
+// When they are, remove the 'Implementation' here.
+
+/// Thrown by type assertions that fail.
+class TypeErrorImpl extends Error implements TypeError {
+  final String message;
+
+  TypeErrorImpl(this.message);
+
+  String toString() => message;
+}
+
+/// Thrown by the 'as' operator if the cast isn't valid.
+class CastErrorImpl extends Error implements CastError {
+  final String message;
+
+  CastErrorImpl(this.message);
+
+  String toString() => message;
+}
+
+class FallThroughErrorImplementation extends FallThroughError {
+  String toString() => "Switch case fall-through.";
+}
+
+/**
+ * Error thrown when a runtime error occurs.
+ */
+class RuntimeError extends Error {
+  final message;
+  RuntimeError(this.message);
+  String toString() => "RuntimeError: $message";
+}
+
+/// Error thrown by DDC when an `assert()` fails (with or without a message).
+class AssertionErrorImpl extends AssertionError {
+  final String _fileUri;
+  final int _line;
+  final int _column;
+  final String _conditionSource;
+
+  AssertionErrorImpl(Object message,
+      [this._fileUri, this._line, this._column, this._conditionSource])
+      : super(message);
+
+  String toString() {
+    var failureMessage = "";
+    if (_fileUri != null &&
+        _line != null &&
+        _column != null &&
+        _conditionSource != null) {
+      failureMessage += "$_fileUri:${_line}:${_column}\n$_conditionSource\n";
+    }
+    failureMessage +=
+        message != null ? Error.safeToString(message) : "is not true";
+
+    return "Assertion failed: $failureMessage";
+  }
+}
+
+/**
+ * Creates a random number with 64 bits of randomness.
+ *
+ * This will be truncated to the 53 bits available in a double.
+ */
+int random64() {
+  // TODO(lrn): Use a secure random source.
+  int int32a = JS("int", "(Math.random() * 0x100000000) >>> 0");
+  int int32b = JS("int", "(Math.random() * 0x100000000) >>> 0");
+  return int32a + int32b * 0x100000000;
+}
+
+class BooleanConversionAssertionError extends AssertionError {
+  toString() => 'Failed assertion: boolean expression must not be null';
+}
+
+// Hook to register new global object.  This is invoked from dart:html
+// whenever a new window is accessed for the first time.
+void registerGlobalObject(object) {
+  try {
+    if (dart.polyfill(object)) {
+      dart.applyAllExtensions(object);
+    }
+  } catch (e) {
+    // This may fail due to cross-origin errors.  In that case, we shouldn't
+    // need to polyfill as we can't get objects from that frame.
+
+    // TODO(vsm): Detect this more robustly - ideally before we try to polyfill.
+  }
+}
+
+/// Expose browser JS classes.
+void applyExtension(name, nativeObject) {
+  dart.applyExtension(name, nativeObject);
+}
+
+/// Used internally by DDC to map ES6 symbols to Dart.
+class PrivateSymbol implements Symbol {
+  // TODO(jmesserly): could also get this off the native symbol instead of
+  // storing it. Mirrors already does this conversion.
+  final String _name;
+  final Object _nativeSymbol;
+
+  const PrivateSymbol(this._name, this._nativeSymbol);
+
+  static String getName(Symbol symbol) => (symbol as PrivateSymbol)._name;
+
+  static Object getNativeSymbol(Symbol symbol) {
+    if (symbol is PrivateSymbol) return symbol._nativeSymbol;
+    return null;
+  }
+
+  bool operator ==(other) =>
+      other is PrivateSymbol &&
+      _name == other._name &&
+      identical(_nativeSymbol, other._nativeSymbol);
+
+  get hashCode => _name.hashCode;
+
+  // TODO(jmesserly): is this equivalent to _nativeSymbol toString?
+  toString() => 'Symbol("$_name")';
+}
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/private/js_mirrors.dart b/sdk_nnbd/lib/_internal/js_dev_runtime/private/js_mirrors.dart
new file mode 100644
index 0000000..a93f5fb
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/private/js_mirrors.dart
@@ -0,0 +1,598 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library dart._js_mirrors;
+
+import 'dart:mirrors';
+import 'dart:_runtime' as dart;
+import 'dart:_foreign_helper' show JS;
+import 'dart:_internal' as _internal show Symbol;
+import 'dart:_js_helper' show PrivateSymbol;
+
+String getName(Symbol symbol) {
+  if (symbol is PrivateSymbol) {
+    return PrivateSymbol.getName(symbol);
+  } else {
+    return _internal.Symbol.getName(symbol as _internal.Symbol);
+  }
+}
+
+Symbol getSymbol(name, library) =>
+    throw UnimplementedError("MirrorSystem.getSymbol unimplemented");
+
+final currentJsMirrorSystem = JsMirrorSystem();
+
+final _typeMirror = JS('', 'Symbol("_typeMirror")');
+
+InstanceMirror reflect(reflectee) {
+  // TODO(vsm): Consider caching the mirror here.  Unlike the type below,
+  // reflectee may be a primitive - i.e., we can't just add an expando.
+  if (reflectee is Function) {
+    return JsClosureMirror._(reflectee);
+  } else {
+    return JsInstanceMirror._(reflectee);
+  }
+}
+
+TypeMirror reflectType(Type key) {
+  var unwrapped = dart.unwrapType(key);
+  var property =
+      JS('', 'Object.getOwnPropertyDescriptor(#, #)', unwrapped, _typeMirror);
+  if (property != null) {
+    return JS('', '#.value', property);
+  }
+  // TODO(vsm): Might not be a class.
+  var mirror = JsClassMirror._(key);
+  JS('', '#[#] = #', unwrapped, _typeMirror, mirror);
+  return mirror;
+}
+
+typedef T _Lazy<T>();
+
+dynamic _getESSymbol(Symbol symbol) => PrivateSymbol.getNativeSymbol(symbol);
+
+dynamic _getMember(Symbol symbol) {
+  var privateSymbol = _getESSymbol(symbol);
+  if (privateSymbol != null) {
+    return privateSymbol;
+  }
+  var name = getName(symbol);
+  // TODO(jacobr): this code is duplicated in code_generator.dart
+  switch (name) {
+    case '[]':
+      name = '_get';
+      break;
+    case '[]=':
+      name = '_set';
+      break;
+    case 'unary-':
+      name = '_negate';
+      break;
+    case 'constructor':
+    case 'prototype':
+      name = '_$name';
+      break;
+  }
+  return name;
+}
+
+String _getNameForESSymbol(member) {
+  // Convert private JS symbol "Symbol(_foo)" to string "_foo".
+  assert(JS<bool>('!', 'typeof # == "symbol"', member));
+  var str = member.toString();
+  assert(str.startsWith('Symbol(') && str.endsWith(')'));
+  return str.substring(7, str.length - 1);
+}
+
+Symbol _getSymbolForESSymbol(member) {
+  var name = _getNameForESSymbol(member);
+  return PrivateSymbol(name, member);
+}
+
+// The [member] must be either a string (public) or an ES6 symbol (private).
+Symbol _getSymbolForMember(member) {
+  if (member is String) {
+    return Symbol(member);
+  } else {
+    var name = _getNameForESSymbol(member);
+    return PrivateSymbol(name, member);
+  }
+}
+
+Map<Symbol, dynamic> _toDartMap(data) {
+  if (data == null) return {};
+  var map = Map<Symbol, dynamic>();
+  // Note: we recorded a map from fields/methods to their type and metadata.
+  // The key is a string name for public members but an ES6 symbol for private
+  // ones.  That's works nicely for dynamic operations, but dart:mirrors expects
+  // Dart symbols, so we convert here.
+  var publicMembers = JS('', 'Object.getOwnPropertyNames(#)', data);
+  for (var member in publicMembers) {
+    var symbol = Symbol(member);
+    map[symbol] = JS('', '#[#]', data, member);
+  }
+
+  var privateMembers = JS('', 'Object.getOwnPropertySymbols(#)', data);
+  for (var member in privateMembers) {
+    var symbol = _getSymbolForESSymbol(member);
+    map[symbol] = JS('', '#[#]', data, member);
+  }
+  return map;
+}
+
+dynamic _runtimeType(obj) => dart.wrapType(dart.getReifiedType(obj));
+
+_unimplemented(Type t, Invocation i) {
+  throw UnimplementedError('$t.${getName(i.memberName)} unimplemented');
+}
+
+dynamic _toJsMap(Map<Symbol, dynamic> map) {
+  if (map == null) return null;
+  var obj = JS('', '{}');
+  map.forEach((Symbol key, value) {
+    JS('', '#[#] = #', obj, getName(key), value);
+  });
+  return obj;
+}
+
+class JsMirrorSystem implements MirrorSystem {
+  get libraries => const {};
+
+  noSuchMethod(Invocation i) {
+    _unimplemented(this.runtimeType, i);
+  }
+}
+
+class JsMirror implements Mirror {
+  noSuchMethod(Invocation i) {
+    _unimplemented(this.runtimeType, i);
+  }
+}
+
+class JsCombinatorMirror extends JsMirror implements CombinatorMirror {}
+
+class JsDeclarationMirror extends JsMirror implements DeclarationMirror {}
+
+class JsIsolateMirror extends JsMirror implements IsolateMirror {}
+
+class JsLibraryDependencyMirror extends JsMirror
+    implements LibraryDependencyMirror {}
+
+class JsObjectMirror extends JsMirror implements ObjectMirror {}
+
+class JsInstanceMirror extends JsObjectMirror implements InstanceMirror {
+  // Reflected object
+  final reflectee;
+  bool get hasReflectee => true;
+
+  ClassMirror get type {
+    // The spec guarantees that `null` is the singleton instance of the `Null`
+    // class.
+    if (reflectee == null) return reflectClass(Null);
+    return reflectType(_runtimeType(reflectee));
+  }
+
+  JsInstanceMirror._(this.reflectee);
+
+  bool operator ==(Object other) {
+    return (other is JsInstanceMirror) && identical(reflectee, other.reflectee);
+  }
+
+  int get hashCode {
+    // Avoid hash collisions with the reflectee. This constant is in Smi range
+    // and happens to be the inner padding from RFC 2104.
+    return identityHashCode(reflectee) ^ 0x36363636;
+  }
+
+  InstanceMirror getField(Symbol symbol) {
+    var name = _getMember(symbol);
+    var field = dart.dloadMirror(reflectee, name);
+    return reflect(field);
+  }
+
+  InstanceMirror setField(Symbol symbol, Object value) {
+    var name = _getMember(symbol);
+    dart.dputMirror(reflectee, name, value);
+    return reflect(value);
+  }
+
+  InstanceMirror invoke(Symbol symbol, List<dynamic> args,
+      [Map<Symbol, dynamic> namedArgs]) {
+    var name = _getMember(symbol);
+    var result =
+        dart.callMethod(reflectee, name, null, args, _toJsMap(namedArgs), name);
+    return reflect(result);
+  }
+
+  String toString() => "InstanceMirror on '$reflectee'";
+}
+
+class JsClosureMirror extends JsInstanceMirror implements ClosureMirror {
+  JsClosureMirror._(reflectee) : super._(reflectee);
+
+  InstanceMirror apply(List<dynamic> args, [Map<Symbol, dynamic> namedArgs]) {
+    var result = dart.dcall(reflectee, args, _toJsMap(namedArgs));
+    return reflect(result);
+  }
+}
+
+// For generic classes, mirrors uses the same representation, [ClassMirror],
+// for the instantiated and uninstantiated type.  Somewhat awkwardly, most APIs
+// (e.g., [newInstance]) treat the uninstantiated type as if instantiated
+// with all dynamic.  The representation below is correspondingly a bit wonky.
+// For an uninstantiated generic class, [_cls] is the instantiated type (with
+// dynamic) and [_raw] is null.  For an instantiated generic class, [_cls] is
+// the instantiated type (with the corresponding type parameters), and [_raw]
+// is the generic factory.
+class JsClassMirror extends JsMirror implements ClassMirror {
+  final Type _cls;
+  final Symbol simpleName;
+  // Generic class factory for instantiated types.
+  final dynamic _raw;
+
+  ClassMirror _originalDeclaration;
+
+  // TODO(vsm): Do this properly
+  ClassMirror _mixin = null;
+  List<TypeMirror> _typeArguments;
+
+  List<InstanceMirror> _metadata;
+  Map<Symbol, DeclarationMirror> _declarations;
+
+  List<InstanceMirror> get metadata {
+    if (_metadata == null) {
+      // Load metadata.
+      var unwrapped = dart.unwrapType(_cls);
+      // Only get metadata directly embedded on this class, not its
+      // superclasses.
+      Function fn = JS(
+          '',
+          'Object.hasOwnProperty.call(#, dart.metadata) ? #[dart.metadata] : null',
+          unwrapped,
+          unwrapped);
+      _metadata = (fn == null)
+          ? const <InstanceMirror>[]
+          : List<InstanceMirror>.unmodifiable(fn().map((i) => reflect(i)));
+    }
+    return _metadata;
+  }
+
+  Map<Symbol, DeclarationMirror> get declarations {
+    if (_declarations == null) {
+      // Load declarations.
+      // TODO(vsm): This is only populating the default constructor right now.
+      _declarations = Map<Symbol, DeclarationMirror>();
+      var unwrapped = dart.unwrapType(_cls);
+      var constructors = _toDartMap(dart.getConstructors(unwrapped));
+      constructors.forEach((symbol, ft) {
+        var name = getName(symbol);
+        _declarations[symbol] = JsMethodMirror._constructor(this, symbol, ft);
+      });
+      if (constructors.isEmpty) {
+        // Add a default
+        var name = 'new';
+        var ft = dart.fnType(dart.unwrapType(_cls), []);
+        var symbol = Symbol(name);
+        _declarations[symbol] = JsMethodMirror._constructor(this, symbol, ft);
+      }
+      var fields = _toDartMap(dart.getFields(unwrapped));
+      fields.forEach((symbol, t) {
+        _declarations[symbol] = JsVariableMirror._fromField(symbol, t);
+      });
+      var methods = _toDartMap(dart.getMethods(unwrapped));
+      methods.forEach((symbol, ft) {
+        var name = getName(symbol);
+        _declarations[symbol] =
+            JsMethodMirror._instanceMethod(this, symbol, ft);
+      });
+
+      getterType(type) {
+        if (JS<bool>('!', '# instanceof Array', type)) {
+          var array = JS('', '#.slice()', type);
+          type = JS('', '#[0]', array);
+          JS('', '#[0] = #', array, dart.fnType(type, []));
+          return array;
+        } else {
+          return dart.fnType(type, []);
+        }
+      }
+
+      var getters = _toDartMap(dart.getGetters(unwrapped));
+      getters.forEach((symbol, type) {
+        _declarations[symbol] =
+            JsMethodMirror._instanceMethod(this, symbol, getterType(type));
+      });
+
+      setterType(type) {
+        if (JS<bool>('!', '# instanceof Array', type)) {
+          var array = JS('', '#.slice()', type);
+          type = JS('', '#[0]', array);
+          JS('', '#[0] = #', array, dart.fnType(dart.void_, [type]));
+          return array;
+        } else {
+          return dart.fnType(dart.void_, [type]);
+        }
+      }
+
+      var setters = _toDartMap(dart.getSetters(unwrapped));
+      setters.forEach((symbol, type) {
+        var name = getName(symbol) + '=';
+        // Create a separate symbol for the setter.
+        symbol = PrivateSymbol(name, _getESSymbol(symbol));
+        _declarations[symbol] =
+            JsMethodMirror._instanceMethod(this, symbol, setterType(type));
+      });
+
+      var staticFields = _toDartMap(dart.getStaticFields(unwrapped));
+      staticFields.forEach((symbol, t) {
+        _declarations[symbol] = JsVariableMirror._fromField(symbol, t);
+      });
+      var statics = _toDartMap(dart.getStaticMethods(unwrapped));
+      statics.forEach((symbol, ft) {
+        _declarations[symbol] = JsMethodMirror._staticMethod(this, symbol, ft);
+      });
+
+      var staticGetters = _toDartMap(dart.getStaticGetters(unwrapped));
+      staticGetters.forEach((symbol, type) {
+        _declarations[symbol] =
+            JsMethodMirror._staticMethod(this, symbol, getterType(type));
+      });
+
+      var staticSetters = _toDartMap(dart.getStaticSetters(unwrapped));
+      staticSetters.forEach((symbol, type) {
+        _declarations[symbol] =
+            JsMethodMirror._staticMethod(this, symbol, setterType(type));
+      });
+      _declarations =
+          Map<Symbol, DeclarationMirror>.unmodifiable(_declarations);
+    }
+    return _declarations;
+  }
+
+  JsClassMirror._(Type cls, {bool instantiated = true})
+      : _cls = cls,
+        _raw = instantiated ? dart.getGenericClass(dart.unwrapType(cls)) : null,
+        simpleName = Symbol(JS<String>('!', '#.name', dart.unwrapType(cls))) {
+    var typeArgs = dart.getGenericArgs(dart.unwrapType(_cls));
+    if (typeArgs == null) {
+      _typeArguments = const [];
+    } else {
+      _typeArguments =
+          List.unmodifiable(typeArgs.map((t) => reflectType(dart.wrapType(t))));
+    }
+  }
+
+  InstanceMirror newInstance(Symbol constructorName, List args,
+      [Map<Symbol, dynamic> namedArgs]) {
+    // TODO(vsm): Support named arguments.
+    var name = getName(constructorName);
+    assert(namedArgs == null || namedArgs.isEmpty);
+    // Default constructors are mapped to new.
+    if (name == '') name = 'new';
+    var cls = dart.unwrapType(_cls);
+    var ctr = JS('', '#.#', cls, name);
+    // Only generative Dart constructors are wired up as real JS constructors.
+    var instance = JS<bool>('!', '#.prototype == #.prototype', cls, ctr)
+        // Generative
+        ? JS('', 'new #(...#)', ctr, args)
+        // Factory
+        : JS('', '#(...#)', ctr, args);
+    return reflect(instance);
+  }
+
+  // TODO(vsm): Need to check for NSM, types on accessors below.  Unlike the
+  // InstanceMirror case, there is no dynamic helper to delegate to - we never
+  // need a dload, etc. on a static.
+
+  InstanceMirror getField(Symbol symbol) {
+    var name = getName(symbol);
+    return reflect(JS('', '#[#]', dart.unwrapType(_cls), name));
+  }
+
+  InstanceMirror setField(Symbol symbol, Object value) {
+    var name = getName(symbol);
+    JS('', '#[#] = #', dart.unwrapType(_cls), name, value);
+    return reflect(value);
+  }
+
+  InstanceMirror invoke(Symbol symbol, List<dynamic> args,
+      [Map<Symbol, dynamic> namedArgs]) {
+    var name = getName(symbol);
+    if (namedArgs != null) {
+      args = List.from(args);
+      args.add(_toJsMap(namedArgs));
+    }
+    var result = JS('', '#.#(...#)', dart.unwrapType(_cls), name, args);
+    return reflect(result);
+  }
+
+  List<ClassMirror> get superinterfaces {
+    _Lazy<List<Type>> interfaceThunk =
+        JS('', '#[dart.implements]', dart.unwrapType(_cls));
+    if (interfaceThunk == null) {
+      return [];
+    } else {
+      List<Type> interfaces = interfaceThunk();
+      return interfaces.map((t) => reflectType(t)).toList();
+    }
+  }
+
+  bool get hasReflectedType => true;
+  Type get reflectedType {
+    return _cls;
+  }
+
+  bool get isOriginalDeclaration => _raw == null;
+
+  List<TypeMirror> get typeArguments => _typeArguments;
+
+  TypeMirror get originalDeclaration {
+    if (_raw == null) {
+      return this;
+    }
+    if (_originalDeclaration != null) {
+      return _originalDeclaration;
+    }
+    _originalDeclaration = JsClassMirror._(dart.wrapType(JS('', '#()', _raw)),
+        instantiated: false);
+    return _originalDeclaration;
+  }
+
+  ClassMirror get superclass {
+    if (_cls == Object) {
+      return null;
+    } else {
+      return reflectType(
+          dart.wrapType(JS<Type>('!', '#.__proto__', dart.unwrapType(_cls))));
+    }
+  }
+
+  ClassMirror get mixin {
+    if (_mixin != null) {
+      return _mixin;
+    }
+    var mixin = dart.getMixin(dart.unwrapType(_cls));
+    if (mixin == null) {
+      // If there is no mixin, return this mirror per API.
+      _mixin = this;
+      return _mixin;
+    }
+    _mixin = reflectType(dart.wrapType(mixin));
+    return _mixin;
+  }
+
+  String toString() => "ClassMirror on '$_cls'";
+}
+
+class JsVariableMirror extends JsMirror implements VariableMirror {
+  final Symbol _symbol;
+  final String _name;
+  final TypeMirror type;
+  final List<InstanceMirror> metadata;
+  final bool isFinal;
+
+  // TODO(vsm): Refactor this out.
+  Symbol get simpleName => _symbol;
+
+  // TODO(vsm): Fix this
+  final bool isStatic = false;
+
+  JsVariableMirror._(Symbol symbol, Type t, List annotations,
+      {this.isFinal = false})
+      : _symbol = symbol,
+        _name = getName(symbol),
+        type = reflectType(t),
+        metadata =
+            List<InstanceMirror>.unmodifiable(annotations?.map(reflect) ?? []);
+
+  JsVariableMirror._fromField(Symbol symbol, fieldInfo)
+      : this._(symbol, dart.wrapType(JS('', '#.type', fieldInfo)),
+            JS('', '#.metadata', fieldInfo),
+            isFinal: JS<bool>('!', '#.isFinal', fieldInfo));
+
+  String toString() => "VariableMirror on '$_name'";
+}
+
+class JsParameterMirror extends JsVariableMirror implements ParameterMirror {
+  JsParameterMirror._(Symbol member, Type t, List annotations)
+      : super._(member, t, annotations);
+
+  String toString() => "ParameterMirror on '$_name'";
+}
+
+class JsMethodMirror extends JsMirror implements MethodMirror {
+  final Symbol _symbol;
+  final String _name;
+  List<ParameterMirror> _params;
+  List<InstanceMirror> _metadata;
+  final bool isConstructor;
+  final bool isStatic;
+
+  // TODO(vsm): Fix this
+  final bool isFinal = false;
+  bool get isSetter => _name.endsWith('=');
+  bool get isPrivate => _name.startsWith('_');
+
+  // TODO(vsm): Refactor this out.
+  Symbol get simpleName => _symbol;
+
+  JsMethodMirror._constructor(JsClassMirror cls, Symbol symbol, ftype)
+      : _symbol = symbol,
+        _name = getName(symbol),
+        isConstructor = true,
+        isStatic = false {
+    _createParameterMirrorList(ftype);
+  }
+
+  JsMethodMirror._instanceMethod(JsClassMirror cls, Symbol symbol, ftype)
+      : _symbol = symbol,
+        _name = getName(symbol),
+        isConstructor = false,
+        isStatic = false {
+    _createParameterMirrorList(ftype);
+  }
+
+  JsMethodMirror._staticMethod(JsClassMirror cls, Symbol symbol, ftype)
+      : _symbol = symbol,
+        _name = getName(symbol),
+        isConstructor = false,
+        isStatic = true {
+    _createParameterMirrorList(ftype);
+  }
+
+  // TODO(vsm): Support named constructors.
+  Symbol get constructorName => isConstructor ? _symbol : null;
+  List<ParameterMirror> get parameters => _params;
+  List<InstanceMirror> get metadata => _metadata;
+
+  void _createParameterMirrorList(ftype) {
+    if (ftype == null) {
+      // TODO(vsm): No explicit constructor.  Verify this.
+      _params = const [];
+      _metadata = const [];
+      return;
+    }
+
+    // TODO(vsm): Why does generic function type trigger true for List?
+    if (ftype is! Function && ftype is List) {
+      // Record metadata
+      _metadata = List<InstanceMirror>.unmodifiable(
+          ftype.skip(1).map((a) => reflect(a)));
+      ftype = ftype[0];
+    } else {
+      _metadata = const [];
+    }
+
+    // TODO(vsm): Handle generic function types properly.  Or deprecate mirrors
+    // before we need to!
+    ftype = dart.getFunctionTypeMirror(ftype);
+
+    // TODO(vsm): Add named args.
+    List args = ftype.args;
+    List opts = ftype.optionals;
+    var params = List<ParameterMirror>(args.length + opts.length);
+
+    for (var i = 0; i < args.length; ++i) {
+      var type = args[i];
+      var metadata = ftype.metadata[i];
+      // TODO(vsm): Recover the param name.
+      var param =
+          JsParameterMirror._(Symbol(''), dart.wrapType(type), metadata);
+      params[i] = param;
+    }
+
+    for (var i = 0; i < opts.length; ++i) {
+      var type = opts[i];
+      var metadata = ftype.metadata[args.length + i];
+      // TODO(vsm): Recover the param name.
+      var param =
+          JsParameterMirror._(Symbol(''), dart.wrapType(type), metadata);
+      params[i + args.length] = param;
+    }
+
+    _params = List.unmodifiable(params);
+  }
+
+  String toString() => "MethodMirror on '$_name'";
+}
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/private/js_number.dart b/sdk_nnbd/lib/_internal/js_dev_runtime/private/js_number.dart
new file mode 100644
index 0000000..5f8c7e0
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/private/js_number.dart
@@ -0,0 +1,627 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart._interceptors;
+
+/**
+ * The implementation of Dart's int & double methods.
+ * These are made available as extension methods on `Number` in JS.
+ */
+@JsPeerInterface(name: 'Number')
+class JSNumber extends Interceptor implements int, double {
+  const JSNumber();
+
+  @notNull
+  int compareTo(@nullCheck num b) {
+    if (this < b) {
+      return -1;
+    } else if (this > b) {
+      return 1;
+    } else if (this == b) {
+      if (this == 0) {
+        bool bIsNegative = b.isNegative;
+        if (isNegative == bIsNegative) return 0;
+        if (isNegative) return -1;
+        return 1;
+      }
+      return 0;
+    } else if (isNaN) {
+      if (b.isNaN) {
+        return 0;
+      }
+      return 1;
+    } else {
+      return -1;
+    }
+  }
+
+  @notNull
+  bool get isNegative => (this == 0) ? (1 / this) < 0 : this < 0;
+
+  @notNull
+  bool get isNaN => JS<bool>('!', r'isNaN(#)', this);
+
+  @notNull
+  bool get isInfinite {
+    return JS<bool>('!', r'# == (1/0)', this) ||
+        JS<bool>('!', r'# == (-1/0)', this);
+  }
+
+  @notNull
+  bool get isFinite => JS<bool>('!', r'isFinite(#)', this);
+
+  @notNull
+  JSNumber remainder(@nullCheck num b) {
+    return JS<num>('!', r'# % #', this, b);
+  }
+
+  @notNull
+  JSNumber abs() => JS<num>('!', r'Math.abs(#)', this);
+
+  @notNull
+  JSNumber get sign => this > 0 ? 1 : this < 0 ? -1 : this;
+
+  @notNull
+  static const int _MIN_INT32 = -0x80000000;
+  @notNull
+  static const int _MAX_INT32 = 0x7FFFFFFF;
+
+  @notNull
+  int toInt() {
+    if (this >= _MIN_INT32 && this <= _MAX_INT32) {
+      return JS<int>('!', '# | 0', this);
+    }
+    if (JS<bool>('!', r'isFinite(#)', this)) {
+      return JS<int>(
+          '!', r'# + 0', truncateToDouble()); // Converts -0.0 to +0.0.
+    }
+    // This is either NaN, Infinity or -Infinity.
+    throw UnsupportedError(JS("String", '"" + #', this));
+  }
+
+  @notNull
+  int truncate() => toInt();
+
+  @notNull
+  int ceil() => ceilToDouble().toInt();
+
+  @notNull
+  int floor() => floorToDouble().toInt();
+
+  @notNull
+  int round() {
+    if (this > 0) {
+      // This path excludes the special cases -0.0, NaN and -Infinity, leaving
+      // only +Infinity, for which a direct test is faster than [isFinite].
+      if (JS<bool>('!', r'# !== (1/0)', this)) {
+        return JS<int>('!', r'Math.round(#)', this);
+      }
+    } else if (JS<bool>('!', '# > (-1/0)', this)) {
+      // This test excludes NaN and -Infinity, leaving only -0.0.
+      //
+      // Subtraction from zero rather than negation forces -0.0 to 0.0 so code
+      // inside Math.round and code to handle result never sees -0.0, which on
+      // some JavaScript VMs can be a slow path.
+      return JS<int>('!', r'0 - Math.round(0 - #)', this);
+    }
+    // This is either NaN, Infinity or -Infinity.
+    throw UnsupportedError(JS("String", '"" + #', this));
+  }
+
+  @notNull
+  double ceilToDouble() => JS<num>('!', r'Math.ceil(#)', this);
+
+  @notNull
+  double floorToDouble() => JS<num>('!', r'Math.floor(#)', this);
+
+  @notNull
+  double roundToDouble() {
+    if (this < 0) {
+      return JS<num>('!', r'-Math.round(-#)', this);
+    } else {
+      return JS<num>('!', r'Math.round(#)', this);
+    }
+  }
+
+  @notNull
+  double truncateToDouble() => this < 0 ? ceilToDouble() : floorToDouble();
+
+  @notNull
+  num clamp(@nullCheck num lowerLimit, @nullCheck num upperLimit) {
+    if (lowerLimit.compareTo(upperLimit) > 0) {
+      throw argumentErrorValue(lowerLimit);
+    }
+    if (this.compareTo(lowerLimit) < 0) return lowerLimit;
+    if (this.compareTo(upperLimit) > 0) return upperLimit;
+    return this;
+  }
+
+  @notNull
+  double toDouble() => this;
+
+  @notNull
+  String toStringAsFixed(@notNull int fractionDigits) {
+    if (fractionDigits < 0 || fractionDigits > 20) {
+      throw RangeError.range(fractionDigits, 0, 20, "fractionDigits");
+    }
+    String result = JS<String>('!', r'#.toFixed(#)', this, fractionDigits);
+    if (this == 0 && isNegative) return "-$result";
+    return result;
+  }
+
+  @notNull
+  String toStringAsExponential([int fractionDigits]) {
+    String result;
+    if (fractionDigits != null) {
+      @notNull
+      var _fractionDigits = fractionDigits;
+      if (_fractionDigits < 0 || _fractionDigits > 20) {
+        throw RangeError.range(_fractionDigits, 0, 20, "fractionDigits");
+      }
+      result = JS<String>('!', r'#.toExponential(#)', this, _fractionDigits);
+    } else {
+      result = JS<String>('!', r'#.toExponential()', this);
+    }
+    if (this == 0 && isNegative) return "-$result";
+    return result;
+  }
+
+  @notNull
+  String toStringAsPrecision(@nullCheck int precision) {
+    if (precision < 1 || precision > 21) {
+      throw RangeError.range(precision, 1, 21, "precision");
+    }
+    String result = JS<String>('!', r'#.toPrecision(#)', this, precision);
+    if (this == 0 && isNegative) return "-$result";
+    return result;
+  }
+
+  @notNull
+  String toRadixString(@nullCheck int radix) {
+    if (radix < 2 || radix > 36) {
+      throw RangeError.range(radix, 2, 36, "radix");
+    }
+    String result = JS<String>('!', r'#.toString(#)', this, radix);
+    const int rightParenCode = 0x29;
+    if (result.codeUnitAt(result.length - 1) != rightParenCode) {
+      return result;
+    }
+    return _handleIEtoString(result);
+  }
+
+  @notNull
+  static String _handleIEtoString(String result) {
+    // Result is probably IE's untraditional format for large numbers,
+    // e.g., "8.0000000000008(e+15)" for 0x8000000000000800.toString(16).
+    var match = JS<List>(
+        '', r'/^([\da-z]+)(?:\.([\da-z]+))?\(e\+(\d+)\)$/.exec(#)', result);
+    if (match == null) {
+      // Then we don't know how to handle it at all.
+      throw UnsupportedError("Unexpected toString result: $result");
+    }
+    result = JS('!', '#', match[1]);
+    int exponent = JS("!", "+#", match[3]);
+    if (match[2] != null) {
+      result = JS('!', '# + #', result, match[2]);
+      exponent -= JS<int>('!', '#.length', match[2]);
+    }
+    return result + "0" * exponent;
+  }
+
+  // Note: if you change this, also change the function [S].
+  @notNull
+  String toString() {
+    if (this == 0 && JS<bool>('!', '(1 / #) < 0', this)) {
+      return '-0.0';
+    } else {
+      return JS<String>('!', r'"" + (#)', this);
+    }
+  }
+
+  @notNull
+  int get hashCode {
+    int intValue = JS<int>('!', '# | 0', this);
+    // Fast exit for integers in signed 32-bit range. Masking converts -0.0 to 0
+    // and ensures that result fits in JavaScript engine's Smi range.
+    if (this == intValue) return 0x1FFFFFFF & intValue;
+
+    // We would like to access the exponent and mantissa as integers but there
+    // are no JavaScript operations that do this, so use log2-floor-pow-divide
+    // to extract the values.
+    num absolute = JS<num>('!', 'Math.abs(#)', this);
+    num lnAbsolute = JS<num>('!', 'Math.log(#)', absolute);
+    num log2 = lnAbsolute / ln2;
+    // Floor via '# | 0' converts NaN to zero so the final result is not NaN.
+    int floorLog2 = JS<int>('!', '# | 0', log2);
+    num factor = JS<num>('!', 'Math.pow(2, #)', floorLog2);
+    num scaled = absolute < 1 ? absolute / factor : factor / absolute;
+    // [scaled] is in the range [0.5, 1].
+
+    // Multiply and truncate to pick up all the mantissa bits. Multiplying by
+    // 0x20000000000000 (which has 53 zero bits) converts the mantissa into an
+    // integer. There are interesting subsets where all the bit variance is in
+    // the most significant bits of the mantissa (e.g. 0.5, 0.625, 0.75), so we
+    // need to mix in the most significant bits. We do this by scaling with a
+    // constant that has many bits set to use the multiplier to mix in bits from
+    // all over the mantissa into low positions.
+    num rescaled1 = scaled * 0x20000000000000;
+    num rescaled2 = scaled * 0x0C95A6C285A6C9;
+    int d1 = JS<int>('!', '# | 0', rescaled1);
+    int d2 = JS<int>('!', '# | 0', rescaled2);
+    // Mix in exponent to distinguish e.g. 1.25 from 2.5.
+    int d3 = floorLog2;
+    int h = 0x1FFFFFFF & ((d1 + d2) * (601 * 997) + d3 * (1259));
+    return h;
+  }
+
+  @notNull
+  JSNumber operator -() => JS<num>('!', r'-#', this);
+
+  @notNull
+  JSNumber operator +(@nullCheck num other) {
+    return JS<num>('!', '# + #', this, other);
+  }
+
+  @notNull
+  JSNumber operator -(@nullCheck num other) {
+    return JS<num>('!', '# - #', this, other);
+  }
+
+  @notNull
+  double operator /(@nullCheck num other) {
+    return JS<num>('!', '# / #', this, other);
+  }
+
+  @notNull
+  JSNumber operator *(@nullCheck num other) {
+    return JS<num>('!', '# * #', this, other);
+  }
+
+  @notNull
+  JSNumber operator %(@nullCheck num other) {
+    // Euclidean Modulo.
+    num result = JS<num>('!', r'# % #', this, other);
+    if (result == 0) return (0 as JSNumber); // Make sure we don't return -0.0.
+    if (result > 0) return result;
+    if (JS<num>('!', '#', other) < 0) {
+      return result - JS<num>('!', '#', other);
+    } else {
+      return result + JS<num>('!', '#', other);
+    }
+  }
+
+  @notNull
+  bool _isInt32(@notNull num value) =>
+      JS<bool>('!', '(# | 0) === #', value, value);
+
+  @notNull
+  int operator ~/(@nullCheck num other) {
+    if (_isInt32(this) && _isInt32(other) && 0 != other && -1 != other) {
+      return JS<int>('!', r'(# / #) | 0', this, other);
+    } else {
+      return _tdivSlow(other);
+    }
+  }
+
+  @notNull
+  int _tdivSlow(num other) {
+    return (JS<num>('!', r'# / #', this, other)).toInt();
+  }
+
+  // TODO(ngeoffray): Move the bit operations below to [JSInt] and
+  // make them take an int. Because this will make operations slower,
+  // we define these methods on number for now but we need to decide
+  // the grain at which we do the type checks.
+
+  @notNull
+  int operator <<(@nullCheck num other) {
+    if (other < 0) throwArgumentErrorValue(other);
+    return _shlPositive(other);
+  }
+
+  @notNull
+  int _shlPositive(@notNull num other) {
+    // JavaScript only looks at the last 5 bits of the shift-amount. Shifting
+    // by 33 is hence equivalent to a shift by 1.
+    return JS<bool>('!', r'# > 31', other)
+        ? 0
+        : JS<int>('!', r'(# << #) >>> 0', this, other);
+  }
+
+  @notNull
+  int operator >>(@nullCheck num other) {
+    if (JS<num>('!', '#', other) < 0) throwArgumentErrorValue(other);
+    return _shrOtherPositive(other);
+  }
+
+  @notNull
+  int _shrOtherPositive(@notNull num other) {
+    return JS<num>('!', '#', this) > 0
+        ? _shrBothPositive(other)
+        // For negative numbers we just clamp the shift-by amount.
+        // `this` could be negative but not have its 31st bit set.
+        // The ">>" would then shift in 0s instead of 1s. Therefore
+        // we cannot simply return 0xFFFFFFFF.
+        : JS<int>('!', r'(# >> #) >>> 0', this, other > 31 ? 31 : other);
+  }
+
+  @notNull
+  int _shrBothPositive(@notNull num other) {
+    return JS<bool>('!', r'# > 31', other)
+        // JavaScript only looks at the last 5 bits of the shift-amount. In JS
+        // shifting by 33 is hence equivalent to a shift by 1. Shortcut the
+        // computation when that happens.
+        ? 0
+        // Given that `this` is positive we must not use '>>'. Otherwise a
+        // number that has the 31st bit set would be treated as negative and
+        // shift in ones.
+        : JS<int>('!', r'# >>> #', this, other);
+  }
+
+  @notNull
+  int operator &(@nullCheck num other) {
+    return JS<int>('!', r'(# & #) >>> 0', this, other);
+  }
+
+  @notNull
+  int operator |(@nullCheck num other) {
+    return JS<int>('!', r'(# | #) >>> 0', this, other);
+  }
+
+  @notNull
+  int operator ^(@nullCheck num other) {
+    return JS<int>('!', r'(# ^ #) >>> 0', this, other);
+  }
+
+  @notNull
+  bool operator <(@nullCheck num other) {
+    return JS<bool>('!', '# < #', this, other);
+  }
+
+  @notNull
+  bool operator >(@nullCheck num other) {
+    return JS<bool>('!', '# > #', this, other);
+  }
+
+  @notNull
+  bool operator <=(@nullCheck num other) {
+    return JS<bool>('!', '# <= #', this, other);
+  }
+
+  @notNull
+  bool operator >=(@nullCheck num other) {
+    return JS<bool>('!', '# >= #', this, other);
+  }
+
+  // int members.
+  // TODO(jmesserly): all numbers will have these in dynamic dispatch.
+  // We can fix by checking it at dispatch time but we'd need to structure them
+  // differently.
+
+  @notNull
+  bool get isEven => (this & 1) == 0;
+
+  @notNull
+  bool get isOdd => (this & 1) == 1;
+
+  @notNull
+  int toUnsigned(@nullCheck int width) {
+    return this & ((1 << width) - 1);
+  }
+
+  @notNull
+  int toSigned(@nullCheck int width) {
+    int signMask = 1 << (width - 1);
+    return (this & (signMask - 1)) - (this & signMask);
+  }
+
+  @notNull
+  int get bitLength {
+    int nonneg = this < 0 ? -this - 1 : this;
+    int wordBits = 32;
+    while (nonneg >= 0x100000000) {
+      nonneg = nonneg ~/ 0x100000000;
+      wordBits += 32;
+    }
+    return wordBits - _clz32(nonneg);
+  }
+
+  @notNull
+  static int _clz32(@notNull int uint32) {
+    // TODO(sra): Use `Math.clz32(uint32)` (not available on IE11).
+    return 32 - _bitCount(_spread(uint32));
+  }
+
+  // Returns pow(this, e) % m.
+  @notNull
+  int modPow(@nullCheck int e, @nullCheck int m) {
+    if (e < 0) throw RangeError.range(e, 0, null, "exponent");
+    if (m <= 0) throw RangeError.range(m, 1, null, "modulus");
+    if (e == 0) return 1;
+
+    const int maxPreciseInteger = 9007199254740991;
+
+    // Reject inputs that are outside the range of integer values that can be
+    // represented precisely as a Number (double).
+    if (this < -maxPreciseInteger || this > maxPreciseInteger) {
+      throw RangeError.range(
+          this, -maxPreciseInteger, maxPreciseInteger, 'receiver');
+    }
+    if (e > maxPreciseInteger) {
+      throw RangeError.range(e, 0, maxPreciseInteger, 'exponent');
+    }
+    if (m > maxPreciseInteger) {
+      throw RangeError.range(e, 1, maxPreciseInteger, 'modulus');
+    }
+
+    // This is floor(sqrt(maxPreciseInteger)).
+    const int maxValueThatCanBeSquaredWithoutTruncation = 94906265;
+    if (m > maxValueThatCanBeSquaredWithoutTruncation) {
+      // Use BigInt version to avoid truncation in multiplications below. The
+      // 'maxPreciseInteger' check on [m] ensures that toInt() does not round.
+      return BigInt.from(this).modPow(BigInt.from(e), BigInt.from(m)).toInt();
+    }
+
+    int b = this;
+    if (b < 0 || b > m) {
+      b %= m;
+    }
+    int r = 1;
+    while (e > 0) {
+      if (e.isOdd) {
+        r = (r * b) % m;
+      }
+      e ~/= 2;
+      b = (b * b) % m;
+    }
+    return r;
+  }
+
+  // If inv is false, returns gcd(x, y).
+  // If inv is true and gcd(x, y) = 1, returns d, so that c*x + d*y = 1.
+  // If inv is true and gcd(x, y) != 1, throws Exception("Not coprime").
+  @notNull
+  static int _binaryGcd(@notNull int x, @notNull int y, @notNull bool inv) {
+    int s = 1;
+    if (!inv) {
+      while (x.isEven && y.isEven) {
+        x ~/= 2;
+        y ~/= 2;
+        s *= 2;
+      }
+      if (y.isOdd) {
+        var t = x;
+        x = y;
+        y = t;
+      }
+    }
+    final bool ac = x.isEven;
+    int u = x;
+    int v = y;
+    int a = 1, b = 0, c = 0, d = 1;
+    do {
+      while (u.isEven) {
+        u ~/= 2;
+        if (ac) {
+          if (!a.isEven || !b.isEven) {
+            a += y;
+            b -= x;
+          }
+          a ~/= 2;
+        } else if (!b.isEven) {
+          b -= x;
+        }
+        b ~/= 2;
+      }
+      while (v.isEven) {
+        v ~/= 2;
+        if (ac) {
+          if (!c.isEven || !d.isEven) {
+            c += y;
+            d -= x;
+          }
+          c ~/= 2;
+        } else if (!d.isEven) {
+          d -= x;
+        }
+        d ~/= 2;
+      }
+      if (u >= v) {
+        u -= v;
+        if (ac) a -= c;
+        b -= d;
+      } else {
+        v -= u;
+        if (ac) c -= a;
+        d -= b;
+      }
+    } while (u != 0);
+    if (!inv) return s * v;
+    if (v != 1) throw Exception("Not coprime");
+    if (d < 0) {
+      d += x;
+      if (d < 0) d += x;
+    } else if (d > x) {
+      d -= x;
+      if (d > x) d -= x;
+    }
+    return d;
+  }
+
+  // Returns 1/this % m, with m > 0.
+  @notNull
+  int modInverse(@nullCheck int m) {
+    if (m <= 0) throw RangeError.range(m, 1, null, "modulus");
+    if (m == 1) return 0;
+    int t = this;
+    if ((t < 0) || (t >= m)) t %= m;
+    if (t == 1) return 1;
+    if ((t == 0) || (t.isEven && m.isEven)) {
+      throw Exception("Not coprime");
+    }
+    return _binaryGcd(m, t, true);
+  }
+
+  // Returns gcd of abs(this) and abs(other).
+  @notNull
+  int gcd(@nullCheck int other) {
+    int x = this.abs();
+    int y = other.abs();
+    if (x == 0) return y;
+    if (y == 0) return x;
+    if ((x == 1) || (y == 1)) return 1;
+    return _binaryGcd(x, y, false);
+  }
+
+  // Assumes i is <= 32-bit and unsigned.
+  @notNull
+  static int _bitCount(@notNull int i) {
+    // See "Hacker's Delight", section 5-1, "Counting 1-Bits".
+
+    // The basic strategy is to use "divide and conquer" to
+    // add pairs (then quads, etc.) of bits together to obtain
+    // sub-counts.
+    //
+    // A straightforward approach would look like:
+    //
+    // i = (i & 0x55555555) + ((i >>  1) & 0x55555555);
+    // i = (i & 0x33333333) + ((i >>  2) & 0x33333333);
+    // i = (i & 0x0F0F0F0F) + ((i >>  4) & 0x0F0F0F0F);
+    // i = (i & 0x00FF00FF) + ((i >>  8) & 0x00FF00FF);
+    // i = (i & 0x0000FFFF) + ((i >> 16) & 0x0000FFFF);
+    //
+    // The code below removes unnecessary &'s and uses a
+    // trick to remove one instruction in the first line.
+
+    i = _shru(i, 0) - (_shru(i, 1) & 0x55555555);
+    i = (i & 0x33333333) + (_shru(i, 2) & 0x33333333);
+    i = 0x0F0F0F0F & (i + _shru(i, 4));
+    i += _shru(i, 8);
+    i += _shru(i, 16);
+    return (i & 0x0000003F);
+  }
+
+  @notNull
+  static int _shru(int value, int shift) =>
+      JS<int>('!', '# >>> #', value, shift);
+  @notNull
+  static int _shrs(int value, int shift) =>
+      JS<int>('!', '# >> #', value, shift);
+  @notNull
+  static int _ors(int a, int b) => JS<int>('!', '# | #', a, b);
+
+  // Assumes i is <= 32-bit
+  @notNull
+  static int _spread(@notNull int i) {
+    i = _ors(i, _shrs(i, 1));
+    i = _ors(i, _shrs(i, 2));
+    i = _ors(i, _shrs(i, 4));
+    i = _ors(i, _shrs(i, 8));
+    i = _shru(_ors(i, _shrs(i, 16)), 0);
+    return i;
+  }
+
+  @notNull
+  int operator ~() => JS<int>('!', r'(~#) >>> 0', this);
+}
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/private/js_primitives.dart b/sdk_nnbd/lib/_internal/js_dev_runtime/private/js_primitives.dart
new file mode 100644
index 0000000..1347b62
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/private/js_primitives.dart
@@ -0,0 +1,49 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// dart2js "primitives", that is, features that cannot be implemented without
+/// access to JavaScript features.
+library dart2js._js_primitives;
+
+import 'dart:_foreign_helper' show JS;
+
+/**
+ * This is the low-level method that is used to implement [print].  It is
+ * possible to override this function from JavaScript by defining a function in
+ * JavaScript called "dartPrint".
+ *
+ * Notice that it is also possible to intercept calls to [print] from within a
+ * Dart program using zones. This means that there is no guarantee that a call
+ * to print ends in this method.
+ */
+void printString(String string) {
+  if (JS<bool>('!', r'typeof dartPrint == "function"')) {
+    // Support overriding print from JavaScript.
+    JS('void', r'dartPrint(#)', string);
+    return;
+  }
+
+  // Inside browser or nodejs.
+  if (JS<bool>('!', r'typeof console == "object"') &&
+      JS<bool>('!', r'typeof console.log != "undefined"')) {
+    JS('void', r'console.log(#)', string);
+    return;
+  }
+
+  // Don't throw inside IE, the console is only defined if dev tools is open.
+  if (JS<bool>('!', r'typeof window == "object"')) {
+    return;
+  }
+
+  // Running in d8, the V8 developer shell, or in Firefox' js-shell.
+  if (JS<bool>('!', r'typeof print == "function"')) {
+    JS('void', r'print(#)', string);
+    return;
+  }
+
+  // This is somewhat nasty, but we don't want to drag in a bunch of
+  // dependencies to handle a situation that cannot happen. So we
+  // avoid using Dart [:throw:] and Dart [toString].
+  JS('void', 'throw "Unable to print message: " + String(#)', string);
+}
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/private/js_rti.dart b/sdk_nnbd/lib/_internal/js_dev_runtime/private/js_rti.dart
new file mode 100644
index 0000000..015c83e
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/private/js_rti.dart
@@ -0,0 +1,27 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart._js_helper;
+
+// TODO(leafp): Maybe get rid of this?  Currently used by the interceptors
+// library, but that should probably be culled as well.
+Type getRuntimeType(var object) =>
+    JS('Type|null', 'dart.getReifiedType(#)', object);
+
+/// Returns the property [index] of the JavaScript array [array].
+getIndex(var array, int index) {
+  assert(isJsArray(array));
+  return JS('var', r'#[#]', array, index);
+}
+
+/// Returns the length of the JavaScript array [array].
+int getLength(var array) {
+  assert(isJsArray(array));
+  return JS<int>('!', r'#.length', array);
+}
+
+/// Returns whether [value] is a JavaScript array.
+bool isJsArray(var value) {
+  return value is JSArray;
+}
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/private/js_string.dart b/sdk_nnbd/lib/_internal/js_dev_runtime/private/js_string.dart
new file mode 100644
index 0000000..4271d34
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/private/js_string.dart
@@ -0,0 +1,507 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart._interceptors;
+
+/**
+ * The interceptor class for [String]. The compiler recognizes this
+ * class as an interceptor, and changes references to [:this:] to
+ * actually use the receiver of the method, which is generated as an extra
+ * argument added to each member.
+ */
+@JsPeerInterface(name: 'String')
+class JSString extends Interceptor implements String, JSIndexable<String> {
+  const JSString();
+
+  @notNull
+  int codeUnitAt(@nullCheck int index) {
+    // Suppress 2nd null check on index and null check on length
+    // (JS String.length cannot be null).
+    final len = this.length;
+    if (index < 0 || index >= len) {
+      throw RangeError.index(index, this, 'index', null, len);
+    }
+    return JS<int>('!', r'#.charCodeAt(#)', this, index);
+  }
+
+  @notNull
+  Iterable<Match> allMatches(@nullCheck String string,
+      [@nullCheck int start = 0]) {
+    final len = string.length;
+    if (0 > start || start > len) {
+      throw RangeError.range(start, 0, len);
+    }
+    return allMatchesInStringUnchecked(this, string, start);
+  }
+
+  Match matchAsPrefix(@nullCheck String string, [@nullCheck int start = 0]) {
+    int stringLength = JS('!', '#.length', string);
+    if (start < 0 || start > stringLength) {
+      throw RangeError.range(start, 0, stringLength);
+    }
+    int thisLength = JS('!', '#.length', this);
+    if (start + thisLength > stringLength) return null;
+    for (int i = 0; i < thisLength; i++) {
+      if (string.codeUnitAt(start + i) != this.codeUnitAt(i)) {
+        return null;
+      }
+    }
+    return StringMatch(start, string, this);
+  }
+
+  @notNull
+  String operator +(@nullCheck String other) {
+    return JS<String>('!', r'# + #', this, other);
+  }
+
+  @notNull
+  bool endsWith(@nullCheck String other) {
+    var otherLength = other.length;
+    var thisLength = this.length;
+    if (otherLength > thisLength) return false;
+    return other == substring(thisLength - otherLength);
+  }
+
+  @notNull
+  String replaceAll(Pattern from, @nullCheck String to) {
+    return stringReplaceAllUnchecked(this, from, to);
+  }
+
+  @notNull
+  String replaceAllMapped(Pattern from, String convert(Match match)) {
+    return this.splitMapJoin(from, onMatch: convert);
+  }
+
+  @notNull
+  String splitMapJoin(Pattern from,
+      {String onMatch(Match match), String onNonMatch(String nonMatch)}) {
+    return stringReplaceAllFuncUnchecked(this, from, onMatch, onNonMatch);
+  }
+
+  @notNull
+  String replaceFirst(Pattern from, @nullCheck String to,
+      [@nullCheck int startIndex = 0]) {
+    RangeError.checkValueInInterval(startIndex, 0, this.length, "startIndex");
+    return stringReplaceFirstUnchecked(this, from, to, startIndex);
+  }
+
+  @notNull
+  String replaceFirstMapped(
+      Pattern from, @nullCheck String replace(Match match),
+      [@nullCheck int startIndex = 0]) {
+    RangeError.checkValueInInterval(startIndex, 0, this.length, "startIndex");
+    return stringReplaceFirstMappedUnchecked(this, from, replace, startIndex);
+  }
+
+  @notNull
+  List<String> split(@nullCheck Pattern pattern) {
+    if (pattern is String) {
+      return JSArray.of(JS('', r'#.split(#)', this, pattern));
+    } else if (pattern is JSSyntaxRegExp && regExpCaptureCount(pattern) == 0) {
+      var re = regExpGetNative(pattern);
+      return JSArray.of(JS('', r'#.split(#)', this, re));
+    } else {
+      return _defaultSplit(pattern);
+    }
+  }
+
+  @notNull
+  String replaceRange(
+      @nullCheck int start, int end, @nullCheck String replacement) {
+    end = RangeError.checkValidRange(start, end, this.length);
+    return stringReplaceRangeUnchecked(this, start, end, replacement);
+  }
+
+  @notNull
+  List<String> _defaultSplit(Pattern pattern) {
+    List<String> result = <String>[];
+    // End of most recent match. That is, start of next part to add to result.
+    int start = 0;
+    // Length of most recent match.
+    // Set >0, so no match on the empty string causes the result to be [""].
+    int length = 1;
+    for (var match in pattern.allMatches(this)) {
+      @notNull
+      int matchStart = match.start;
+      @notNull
+      int matchEnd = match.end;
+      length = matchEnd - matchStart;
+      if (length == 0 && start == matchStart) {
+        // An empty match right after another match is ignored.
+        // This includes an empty match at the start of the string.
+        continue;
+      }
+      int end = matchStart;
+      result.add(this.substring(start, end));
+      start = matchEnd;
+    }
+    if (start < this.length || length > 0) {
+      // An empty match at the end of the string does not cause a "" at the end.
+      // A non-empty match ending at the end of the string does add a "".
+      result.add(this.substring(start));
+    }
+    return result;
+  }
+
+  @notNull
+  bool startsWith(Pattern pattern, [@nullCheck int index = 0]) {
+    // Suppress null check on length and all but the first
+    // reference to index.
+    int length = JS<int>('!', '#.length', this);
+    if (index < 0 || JS<int>('!', '#', index) > length) {
+      throw RangeError.range(index, 0, this.length);
+    }
+    if (pattern is String) {
+      String other = pattern;
+      int otherLength = JS<int>('!', '#.length', other);
+      int endIndex = index + otherLength;
+      if (endIndex > length) return false;
+      return other ==
+          JS<String>('!', r'#.substring(#, #)', this, index, endIndex);
+    }
+    return pattern.matchAsPrefix(this, index) != null;
+  }
+
+  @notNull
+  String substring(@nullCheck int startIndex, [int _endIndex]) {
+    var length = this.length;
+    final endIndex = _endIndex ?? length;
+    if (startIndex < 0) throw RangeError.value(startIndex);
+    if (startIndex > endIndex) throw RangeError.value(startIndex);
+    if (endIndex > length) throw RangeError.value(endIndex);
+    return JS<String>('!', r'#.substring(#, #)', this, startIndex, endIndex);
+  }
+
+  @notNull
+  String toLowerCase() {
+    return JS<String>('!', r'#.toLowerCase()', this);
+  }
+
+  @notNull
+  String toUpperCase() {
+    return JS<String>('!', r'#.toUpperCase()', this);
+  }
+
+  // Characters with Whitespace property (Unicode 6.3).
+  // 0009..000D    ; White_Space # Cc       <control-0009>..<control-000D>
+  // 0020          ; White_Space # Zs       SPACE
+  // 0085          ; White_Space # Cc       <control-0085>
+  // 00A0          ; White_Space # Zs       NO-BREAK SPACE
+  // 1680          ; White_Space # Zs       OGHAM SPACE MARK
+  // 2000..200A    ; White_Space # Zs       EN QUAD..HAIR SPACE
+  // 2028          ; White_Space # Zl       LINE SEPARATOR
+  // 2029          ; White_Space # Zp       PARAGRAPH SEPARATOR
+  // 202F          ; White_Space # Zs       NARROW NO-BREAK SPACE
+  // 205F          ; White_Space # Zs       MEDIUM MATHEMATICAL SPACE
+  // 3000          ; White_Space # Zs       IDEOGRAPHIC SPACE
+  //
+  // BOM: 0xFEFF
+  @notNull
+  static bool _isWhitespace(@notNull int codeUnit) {
+    // Most codeUnits should be less than 256. Special case with a smaller
+    // switch.
+    if (codeUnit < 256) {
+      switch (codeUnit) {
+        case 0x09:
+        case 0x0A:
+        case 0x0B:
+        case 0x0C:
+        case 0x0D:
+        case 0x20:
+        case 0x85:
+        case 0xA0:
+          return true;
+        default:
+          return false;
+      }
+    }
+    switch (codeUnit) {
+      case 0x1680:
+      case 0x2000:
+      case 0x2001:
+      case 0x2002:
+      case 0x2003:
+      case 0x2004:
+      case 0x2005:
+      case 0x2006:
+      case 0x2007:
+      case 0x2008:
+      case 0x2009:
+      case 0x200A:
+      case 0x2028:
+      case 0x2029:
+      case 0x202F:
+      case 0x205F:
+      case 0x3000:
+      case 0xFEFF:
+        return true;
+      default:
+        return false;
+    }
+  }
+
+  /// Finds the index of the first non-whitespace character, or the
+  /// end of the string. Start looking at position [index].
+  @notNull
+  static int _skipLeadingWhitespace(String string, @nullCheck int index) {
+    const int SPACE = 0x20;
+    const int CARRIAGE_RETURN = 0x0D;
+    var stringLength = string.length;
+    while (index < stringLength) {
+      int codeUnit = string.codeUnitAt(index);
+      if (codeUnit != SPACE &&
+          codeUnit != CARRIAGE_RETURN &&
+          !_isWhitespace(codeUnit)) {
+        break;
+      }
+      index++;
+    }
+    return index;
+  }
+
+  /// Finds the index after the last non-whitespace character, or 0.
+  /// Start looking at position [index - 1].
+  @notNull
+  static int _skipTrailingWhitespace(String string, @nullCheck int index) {
+    const int SPACE = 0x20;
+    const int CARRIAGE_RETURN = 0x0D;
+    while (index > 0) {
+      int codeUnit = string.codeUnitAt(index - 1);
+      if (codeUnit != SPACE &&
+          codeUnit != CARRIAGE_RETURN &&
+          !_isWhitespace(codeUnit)) {
+        break;
+      }
+      index--;
+    }
+    return index;
+  }
+
+  // Dart2js can't use JavaScript trim directly,
+  // because JavaScript does not trim
+  // the NEXT LINE (NEL) character (0x85).
+  @notNull
+  String trim() {
+    const int NEL = 0x85;
+
+    // Start by doing JS trim. Then check if it leaves a NEL at
+    // either end of the string.
+    String result = JS('!', '#.trim()', this);
+    final length = result.length;
+    if (length == 0) return result;
+    int firstCode = result.codeUnitAt(0);
+    int startIndex = 0;
+    if (firstCode == NEL) {
+      startIndex = _skipLeadingWhitespace(result, 1);
+      if (startIndex == length) return "";
+    }
+
+    int endIndex = length;
+    // We know that there is at least one character that is non-whitespace.
+    // Therefore we don't need to verify that endIndex > startIndex.
+    int lastCode = result.codeUnitAt(endIndex - 1);
+    if (lastCode == NEL) {
+      endIndex = _skipTrailingWhitespace(result, endIndex - 1);
+    }
+    if (startIndex == 0 && endIndex == length) return result;
+    return JS<String>('!', r'#.substring(#, #)', result, startIndex, endIndex);
+  }
+
+  // Dart2js can't use JavaScript trimLeft directly,
+  // because it is not in ES5, so not every browser implements it,
+  // and because those that do will not trim the NEXT LINE character (0x85).
+  @notNull
+  String trimLeft() {
+    const int NEL = 0x85;
+
+    // Start by doing JS trim. Then check if it leaves a NEL at
+    // the beginning of the string.
+    String result;
+    int startIndex = 0;
+    if (JS<bool>('!', 'typeof #.trimLeft != "undefined"', this)) {
+      result = JS<String>('!', '#.trimLeft()', this);
+      if (result.length == 0) return result;
+      int firstCode = result.codeUnitAt(0);
+      if (firstCode == NEL) {
+        startIndex = _skipLeadingWhitespace(result, 1);
+      }
+    } else {
+      result = this;
+      startIndex = _skipLeadingWhitespace(this, 0);
+    }
+    if (startIndex == 0) return result;
+    if (startIndex == result.length) return "";
+    return JS<String>('!', r'#.substring(#)', result, startIndex);
+  }
+
+  // Dart2js can't use JavaScript trimRight directly,
+  // because it is not in ES5 and because JavaScript does not trim
+  // the NEXT LINE character (0x85).
+  @notNull
+  String trimRight() {
+    const int NEL = 0x85;
+
+    // Start by doing JS trim. Then check if it leaves a NEL or BOM at
+    // the end of the string.
+    String result;
+    @notNull
+    int endIndex = 0;
+    // trimRight is implemented by Firefox and Chrome/Blink,
+    // so use it if it is there.
+    if (JS<bool>('!', 'typeof #.trimRight != "undefined"', this)) {
+      result = JS<String>('!', '#.trimRight()', this);
+      endIndex = result.length;
+      if (endIndex == 0) return result;
+      int lastCode = result.codeUnitAt(endIndex - 1);
+      if (lastCode == NEL) {
+        endIndex = _skipTrailingWhitespace(result, endIndex - 1);
+      }
+    } else {
+      result = this;
+      endIndex = _skipTrailingWhitespace(this, this.length);
+    }
+
+    if (endIndex == result.length) return result;
+    if (endIndex == 0) return "";
+    return JS<String>('!', r'#.substring(#, #)', result, 0, endIndex);
+  }
+
+  @notNull
+  String operator *(@nullCheck int times) {
+    if (0 >= times) return '';
+    if (times == 1 || this.length == 0) return this;
+    if (times != JS<int>('!', '# >>> 0', times)) {
+      // times >= 2^32. We can't create a string that big.
+      throw const OutOfMemoryError();
+    }
+    var result = '';
+    String s = this;
+    while (true) {
+      if (times & 1 == 1) result = s + result;
+      times = JS<int>('!', '# >>> 1', times);
+      if (times == 0) break;
+      s += s;
+    }
+    return result;
+  }
+
+  @notNull
+  String padLeft(@nullCheck int width, [String padding = ' ']) {
+    int delta = width - this.length;
+    if (delta <= 0) return this;
+    return padding * delta + this;
+  }
+
+  @notNull
+  String padRight(@nullCheck int width, [String padding = ' ']) {
+    int delta = width - this.length;
+    if (delta <= 0) return this;
+    return this + padding * delta;
+  }
+
+  @notNull
+  List<int> get codeUnits => CodeUnits(this);
+
+  @notNull
+  Runes get runes => Runes(this);
+
+  @notNull
+  int indexOf(@nullCheck Pattern pattern, [@nullCheck int start = 0]) {
+    if (start < 0 || start > this.length) {
+      throw RangeError.range(start, 0, this.length);
+    }
+    if (pattern is String) {
+      return stringIndexOfStringUnchecked(this, pattern, start);
+    }
+    if (pattern is JSSyntaxRegExp) {
+      JSSyntaxRegExp re = pattern;
+      Match match = firstMatchAfter(re, this, start);
+      return (match == null) ? -1 : match.start;
+    }
+    var length = this.length;
+    for (int i = start; i <= length; i++) {
+      if (pattern.matchAsPrefix(this, i) != null) return i;
+    }
+    return -1;
+  }
+
+  @notNull
+  int lastIndexOf(@nullCheck Pattern pattern, [int _start]) {
+    var length = this.length;
+    var start = _start ?? length;
+    if (start < 0 || start > length) {
+      throw RangeError.range(start, 0, length);
+    }
+    if (pattern is String) {
+      String other = pattern;
+      if (start + other.length > length) {
+        start = length - other.length;
+      }
+      return stringLastIndexOfUnchecked(this, other, start);
+    }
+    for (int i = start; i >= 0; i--) {
+      if (pattern.matchAsPrefix(this, i) != null) return i;
+    }
+    return -1;
+  }
+
+  @notNull
+  bool contains(@nullCheck Pattern other, [@nullCheck int startIndex = 0]) {
+    if (startIndex < 0 || startIndex > this.length) {
+      throw RangeError.range(startIndex, 0, this.length);
+    }
+    return stringContainsUnchecked(this, other, startIndex);
+  }
+
+  @notNull
+  bool get isEmpty => JS<int>('!', '#.length', this) == 0;
+
+  @notNull
+  bool get isNotEmpty => !isEmpty;
+
+  @notNull
+  int compareTo(@nullCheck String other) {
+    return this == other ? 0 : JS<bool>('!', r'# < #', this, other) ? -1 : 1;
+  }
+
+  // Note: if you change this, also change the function [S].
+  @notNull
+  String toString() => this;
+
+  /**
+   * This is the [Jenkins hash function][1] but using masking to keep
+   * values in SMI range.
+   *
+   * [1]: http://en.wikipedia.org/wiki/Jenkins_hash_function
+   */
+  @notNull
+  int get hashCode {
+    // TODO(ahe): This method shouldn't have to use JS. Update when our
+    // optimizations are smarter.
+    int hash = 0;
+    int length = JS('!', '#.length', this);
+    for (int i = 0; i < length; i++) {
+      hash = 0x1fffffff & (hash + JS<int>('!', r'#.charCodeAt(#)', this, i));
+      hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10));
+      hash = JS<int>('!', '# ^ (# >> 6)', hash, hash);
+    }
+    hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3));
+    hash = JS<int>('!', '# ^ (# >> 11)', hash, hash);
+    return 0x1fffffff & (hash + ((0x00003fff & hash) << 15));
+  }
+
+  @notNull
+  Type get runtimeType => String;
+
+  @notNull
+  final int length;
+
+  @notNull
+  String operator [](@nullCheck int index) {
+    if (index >= JS<int>('!', '#.length', this) || index < 0) {
+      throw diagnoseIndexError(this, index);
+    }
+    return JS<String>('!', '#[#]', this, index);
+  }
+}
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/private/linked_hash_map.dart b/sdk_nnbd/lib/_internal/js_dev_runtime/private/linked_hash_map.dart
new file mode 100644
index 0000000..1c03db8
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/private/linked_hash_map.dart
@@ -0,0 +1,278 @@
+// 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.
+
+// Efficient JavaScript based implementation of a linked hash map used as a
+// backing map for constant maps and the [LinkedHashMap] patch
+
+part of dart._js_helper;
+
+abstract class InternalMap<K, V> extends MapBase<K, V>
+    implements LinkedHashMap<K, V>, HashMap<K, V> {
+  @notNull
+  get _map;
+
+  @notNull
+  int get _modifications;
+
+  void forEach(void action(K key, V value)) {
+    int modifications = _modifications;
+    for (var entry in JS('Iterable', '#.entries()', _map)) {
+      action(JS('', '#[0]', entry), JS('', '#[1]', entry));
+      if (modifications != _modifications) {
+        throw ConcurrentModificationError(this);
+      }
+    }
+  }
+}
+
+/// A linked hash map implementation based on ES6 Map.
+///
+/// Items that can use identity semantics are stored directly in the backing
+/// map.
+///
+/// Items that have a custom equality/hashCode are first canonicalized by
+/// looking up the canonical key by its hashCode.
+class LinkedMap<K, V> extends InternalMap<K, V> {
+  /// The backing store for this map.
+  ///
+  /// Keys that use identity equality are stored directly. For other types of
+  /// keys, we first look them up (by hashCode) in the [_keyMap] map, then
+  /// we lookup the key in this map.
+  @notNull
+  final _map = JS('', 'new Map()');
+
+  /// Items that use custom equality semantics.
+  ///
+  /// This maps from the item's hashCode to the canonical key, which is then
+  /// used to lookup the item in [_map]. Keeping the data in our primary backing
+  /// map gives us the ordering semantics requred by [LinkedHashMap], while
+  /// also providing convenient access to keys/values.
+  @notNull
+  final _keyMap = JS('', 'new Map()');
+
+  // We track the number of modifications done to the key set of the
+  // hash map to be able to throw when the map is modified while being
+  // iterated over.
+  //
+  // Value cycles after 2^30 modifications so that modification counts are
+  // always unboxed (Smi) values. Modification detection will be missed if you
+  // make exactly some multiple of 2^30 modifications between advances of an
+  // iterator.
+  @notNull
+  int _modifications = 0;
+
+  LinkedMap();
+
+  /// Called by generated code for a map literal.
+  LinkedMap.from(JSArray entries) {
+    var map = _map;
+    var keyMap = _keyMap;
+    for (int i = 0, n = JS('!', '#.length', entries); i < n; i += 2) {
+      K key = JS('', '#[#]', entries, i);
+      V value = JS('', '#[#]', entries, i + 1);
+      if (key == null) {
+        key = null;
+      } else if (JS<bool>('!', '#[#] !== #', key,
+          dart.extensionSymbol('_equals'), dart.identityEquals)) {
+        key = putLinkedMapKey(key, keyMap);
+      }
+      JS('', '#.set(#, #)', map, key, value);
+    }
+  }
+
+  @notNull
+  int get length => JS<int>('!', '#.size', _map);
+
+  @notNull
+  bool get isEmpty => JS<bool>('!', '#.size == 0', _map);
+
+  @notNull
+  bool get isNotEmpty => JS<bool>('!', '#.size != 0', _map);
+
+  Iterable<K> get keys => _JSMapIterable<K>(this, true);
+  Iterable<V> get values => _JSMapIterable<V>(this, false);
+
+  @notNull
+  bool containsKey(Object key) {
+    if (key == null) {
+      key = null;
+    } else if (JS<bool>('!', '#[#] !== #', key, dart.extensionSymbol('_equals'),
+        dart.identityEquals)) {
+      @notNull
+      var k = key;
+      var buckets = JS('', '#.get(# & 0x3ffffff)', _keyMap, k.hashCode);
+      if (buckets != null) {
+        for (int i = 0, n = JS('!', '#.length', buckets); i < n; i++) {
+          k = JS('', '#[#]', buckets, i);
+          if (k == key) return true;
+        }
+      }
+      return false;
+    }
+    return JS<bool>('!', '#.has(#)', _map, key);
+  }
+
+  bool containsValue(Object value) {
+    for (var v in JS('', '#.values()', _map)) {
+      if (v == value) return true;
+    }
+    return false;
+  }
+
+  void addAll(Map<K, V> other) {
+    var map = _map;
+    int length = JS('', '#.size', map);
+    other.forEach((K key, V value) {
+      if (key == null) {
+        key = null;
+      } else if (JS<bool>('!', '#[#] !== #', key,
+          dart.extensionSymbol('_equals'), dart.identityEquals)) {
+        key = putLinkedMapKey(key, _keyMap);
+      }
+      JS('', '#.set(#, #)', _map, key, value);
+    });
+    if (length != JS<int>('!', '#.size', map)) {
+      _modifications = (_modifications + 1) & 0x3ffffff;
+    }
+  }
+
+  V operator [](Object key) {
+    if (key == null) {
+      key = null;
+    } else if (JS<bool>('!', '#[#] !== #', key, dart.extensionSymbol('_equals'),
+        dart.identityEquals)) {
+      @notNull
+      var k = key;
+      var buckets = JS('', '#.get(# & 0x3ffffff)', _keyMap, k.hashCode);
+      if (buckets != null) {
+        for (int i = 0, n = JS('!', '#.length', buckets); i < n; i++) {
+          k = JS('', '#[#]', buckets, i);
+          if (k == key) return JS('', '#.get(#)', _map, k);
+        }
+      }
+      return null;
+    }
+    V value = JS('', '#.get(#)', _map, key);
+    return value == null ? null : value; // coerce undefined to null.
+  }
+
+  void operator []=(K key, V value) {
+    if (key == null) {
+      key = null;
+    } else if (JS<bool>('!', '#[#] !== #', key, dart.extensionSymbol('_equals'),
+        dart.identityEquals)) {
+      key = putLinkedMapKey(key, _keyMap);
+    }
+    var map = _map;
+    int length = JS('', '#.size', map);
+    JS('', '#.set(#, #)', map, key, value);
+    if (length != JS<int>('!', '#.size', map)) {
+      _modifications = (_modifications + 1) & 0x3ffffff;
+    }
+  }
+
+  V putIfAbsent(K key, V ifAbsent()) {
+    var map = _map;
+    if (key == null) {
+      key = null;
+      if (JS<bool>('!', '#.has(null)', map)) return JS('', '#.get(null)', map);
+    } else if (JS<bool>('!', '#[#] !== #', key, dart.extensionSymbol('_equals'),
+        dart.identityEquals)) {
+      @notNull
+      K k = key;
+      var hash = JS<int>('!', '# & 0x3ffffff', k.hashCode);
+      var buckets = JS('', '#.get(#)', _keyMap, hash);
+      if (buckets == null) {
+        JS('', '#.set(#, [#])', _keyMap, hash, key);
+      } else {
+        for (int i = 0, n = JS('!', '#.length', buckets); i < n; i++) {
+          k = JS('', '#[#]', buckets, i);
+          if (k == key) return JS('', '#.get(#)', map, k);
+        }
+        JS('', '#.push(#)', buckets, key);
+      }
+    } else if (JS<bool>('!', '#.has(#)', map, key)) {
+      return JS('', '#.get(#)', map, key);
+    }
+    V value = ifAbsent();
+    if (value == null) value = null; // coerce undefined to null.
+    JS('', '#.set(#, #)', map, key, value);
+    _modifications = (_modifications + 1) & 0x3ffffff;
+    return value;
+  }
+
+  V remove(Object key) {
+    if (key == null) {
+      key = null;
+    } else if (JS<bool>('!', '#[#] !== #', key, dart.extensionSymbol('_equals'),
+        dart.identityEquals)) {
+      @notNull
+      var k = key;
+      var hash = JS<int>('!', '# & 0x3ffffff', k.hashCode);
+      var buckets = JS('', '#.get(#)', _keyMap, hash);
+      if (buckets == null) return null; // not found
+      for (int i = 0, n = JS('!', '#.length', buckets);;) {
+        k = JS('', '#[#]', buckets, i);
+        if (k == key) {
+          key = k;
+          if (n == 1) {
+            JS('', '#.delete(#)', _keyMap, hash);
+          } else {
+            JS('', '#.splice(#, 1)', buckets, i);
+          }
+          break;
+        }
+        if (++i >= n) return null; // not found
+      }
+    }
+    var map = _map;
+    V value = JS('', '#.get(#)', map, key);
+    if (JS<bool>('!', '#.delete(#)', map, key)) {
+      _modifications = (_modifications + 1) & 0x3ffffff;
+    }
+    return value == null ? null : value; // coerce undefined to null.
+  }
+
+  void clear() {
+    var map = _map;
+    if (JS<int>('!', '#.size', map) > 0) {
+      JS('', '#.clear()', map);
+      JS('', '#.clear()', _keyMap);
+      _modifications = (_modifications + 1) & 0x3ffffff;
+    }
+  }
+}
+
+@NoReifyGeneric()
+K putLinkedMapKey<K>(@notNull K key, keyMap) {
+  var hash = JS<int>('!', '# & 0x3ffffff', key.hashCode);
+  var buckets = JS('', '#.get(#)', keyMap, hash);
+  if (buckets == null) {
+    JS('', '#.set(#, [#])', keyMap, hash, key);
+    return key;
+  }
+  for (int i = 0, n = JS('!', '#.length', buckets); i < n; i++) {
+    @notNull
+    K k = JS('', '#[#]', buckets, i);
+    if (k == key) return k;
+  }
+  JS('', '#.push(#)', buckets, key);
+  return key;
+}
+
+class ImmutableMap<K, V> extends LinkedMap<K, V> {
+  ImmutableMap.from(JSArray entries) : super.from(entries);
+
+  void operator []=(Object key, Object value) {
+    throw _unsupported();
+  }
+
+  void addAll(Object other) => throw _unsupported();
+  void clear() => throw _unsupported();
+  V remove(Object key) => throw _unsupported();
+  V putIfAbsent(Object key, Object ifAbsent()) => throw _unsupported();
+
+  static Error _unsupported() =>
+      UnsupportedError("Cannot modify unmodifiable map");
+}
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/private/mirror_helper.dart b/sdk_nnbd/lib/_internal/js_dev_runtime/private/mirror_helper.dart
new file mode 100644
index 0000000..f78926a
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/private/mirror_helper.dart
@@ -0,0 +1,8 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+/**
+ * Helps dealing with reflection in the case that the source code has been
+ * changed as a result of compiling with dart2dart.
+ */
+library dart._mirror_helper;
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/private/native_helper.dart b/sdk_nnbd/lib/_internal/js_dev_runtime/private/native_helper.dart
new file mode 100644
index 0000000..cc214e8
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/private/native_helper.dart
@@ -0,0 +1,18 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart._js_helper;
+
+// Obsolete in dart dev compiler. Added only so that the same version of
+// dart:html can be used in dart2js an dev compiler.
+F convertDartClosureToJS<F>(F closure, int arity) {
+  return closure;
+}
+
+// Warning: calls to these methods need to be removed before custom elements
+// and cross-frame dom objects behave correctly in ddc
+// https://github.com/dart-lang/sdk/issues/28326
+setNativeSubclassDispatchRecord(proto, interceptor) {}
+findDispatchTagForInterceptorClass(interceptorClassConstructor) {}
+makeLeafDispatchRecord(interceptor) {}
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/private/native_typed_data.dart b/sdk_nnbd/lib/_internal/js_dev_runtime/private/native_typed_data.dart
new file mode 100644
index 0000000..2a7a621
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/private/native_typed_data.dart
@@ -0,0 +1,1902 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/**
+ * Specialized integers and floating point numbers,
+ * with SIMD support and efficient lists.
+ */
+library dart.typed_data.implementation;
+
+import 'dart:collection';
+import 'dart:_internal';
+import 'dart:_interceptors' show JSIndexable;
+import 'dart:_js_helper'
+    show
+        Creates,
+        JavaScriptIndexingBehavior,
+        JSName,
+        Native,
+        Null,
+        Returns,
+        diagnoseIndexError,
+        diagnoseRangeError;
+import 'dart:_foreign_helper' show JS;
+import 'dart:math' as Math;
+
+import 'dart:typed_data';
+
+@Native("ArrayBuffer")
+class NativeByteBuffer implements ByteBuffer {
+  @JSName('byteLength')
+  external int get lengthInBytes;
+
+  Type get runtimeType => ByteBuffer;
+
+  Uint8List asUint8List([int offsetInBytes = 0, int length]) {
+    return NativeUint8List.view(this, offsetInBytes, length);
+  }
+
+  Int8List asInt8List([int offsetInBytes = 0, int length]) {
+    return NativeInt8List.view(this, offsetInBytes, length);
+  }
+
+  Uint8ClampedList asUint8ClampedList([int offsetInBytes = 0, int length]) {
+    return NativeUint8ClampedList.view(this, offsetInBytes, length);
+  }
+
+  Uint16List asUint16List([int offsetInBytes = 0, int length]) {
+    return NativeUint16List.view(this, offsetInBytes, length);
+  }
+
+  Int16List asInt16List([int offsetInBytes = 0, int length]) {
+    return NativeInt16List.view(this, offsetInBytes, length);
+  }
+
+  Uint32List asUint32List([int offsetInBytes = 0, int length]) {
+    return NativeUint32List.view(this, offsetInBytes, length);
+  }
+
+  Int32List asInt32List([int offsetInBytes = 0, int length]) {
+    return NativeInt32List.view(this, offsetInBytes, length);
+  }
+
+  Uint64List asUint64List([int offsetInBytes = 0, int length]) {
+    throw UnsupportedError("Uint64List not supported by dart2js.");
+  }
+
+  Int64List asInt64List([int offsetInBytes = 0, int length]) {
+    throw UnsupportedError("Int64List not supported by dart2js.");
+  }
+
+  Int32x4List asInt32x4List([int offsetInBytes = 0, int length]) {
+    NativeInt32List storage =
+        this.asInt32List(offsetInBytes, length != null ? length * 4 : null);
+    return NativeInt32x4List._externalStorage(storage);
+  }
+
+  Float32List asFloat32List([int offsetInBytes = 0, int length]) {
+    return NativeFloat32List.view(this, offsetInBytes, length);
+  }
+
+  Float64List asFloat64List([int offsetInBytes = 0, int length]) {
+    return NativeFloat64List.view(this, offsetInBytes, length);
+  }
+
+  Float32x4List asFloat32x4List([int offsetInBytes = 0, int length]) {
+    NativeFloat32List storage =
+        this.asFloat32List(offsetInBytes, length != null ? length * 4 : null);
+    return NativeFloat32x4List._externalStorage(storage);
+  }
+
+  Float64x2List asFloat64x2List([int offsetInBytes = 0, int length]) {
+    NativeFloat64List storage =
+        this.asFloat64List(offsetInBytes, length != null ? length * 2 : null);
+    return NativeFloat64x2List._externalStorage(storage);
+  }
+
+  ByteData asByteData([int offsetInBytes = 0, int length]) {
+    return NativeByteData.view(this, offsetInBytes, length);
+  }
+}
+
+/**
+ * A fixed-length list of Float32x4 numbers that is viewable as a
+ * [TypedData]. For long lists, this implementation will be considerably more
+ * space- and time-efficient than the default [List] implementation.
+ */
+class NativeFloat32x4List extends Object
+    with ListMixin<Float32x4>, FixedLengthListMixin<Float32x4>
+    implements Float32x4List {
+  final NativeFloat32List _storage;
+
+  /**
+   * Creates a [Float32x4List] of the specified length (in elements),
+   * all of whose elements are initially zero.
+   */
+  NativeFloat32x4List(int length) : _storage = NativeFloat32List(length * 4);
+
+  NativeFloat32x4List._externalStorage(this._storage);
+
+  NativeFloat32x4List._slowFromList(List<Float32x4> list)
+      : _storage = NativeFloat32List(list.length * 4) {
+    for (int i = 0; i < list.length; i++) {
+      var e = list[i];
+      _storage[(i * 4) + 0] = e.x;
+      _storage[(i * 4) + 1] = e.y;
+      _storage[(i * 4) + 2] = e.z;
+      _storage[(i * 4) + 3] = e.w;
+    }
+  }
+
+  Type get runtimeType => Float32x4List;
+
+  /**
+   * Creates a [Float32x4List] with the same size as the [elements] list
+   * and copies over the elements.
+   */
+  factory NativeFloat32x4List.fromList(List<Float32x4> list) {
+    if (list is NativeFloat32x4List) {
+      return NativeFloat32x4List._externalStorage(
+          NativeFloat32List.fromList(list._storage));
+    } else {
+      return NativeFloat32x4List._slowFromList(list);
+    }
+  }
+
+  ByteBuffer get buffer => _storage.buffer;
+
+  int get lengthInBytes => _storage.lengthInBytes;
+
+  int get offsetInBytes => _storage.offsetInBytes;
+
+  int get elementSizeInBytes => Float32x4List.bytesPerElement;
+
+  int get length => _storage.length ~/ 4;
+
+  Float32x4 operator [](int index) {
+    _checkValidIndex(index, this, this.length);
+    double _x = _storage[(index * 4) + 0];
+    double _y = _storage[(index * 4) + 1];
+    double _z = _storage[(index * 4) + 2];
+    double _w = _storage[(index * 4) + 3];
+    return NativeFloat32x4._truncated(_x, _y, _z, _w);
+  }
+
+  void operator []=(int index, Float32x4 value) {
+    _checkValidIndex(index, this, this.length);
+    _storage[(index * 4) + 0] = value.x;
+    _storage[(index * 4) + 1] = value.y;
+    _storage[(index * 4) + 2] = value.z;
+    _storage[(index * 4) + 3] = value.w;
+  }
+
+  Float32x4List sublist(int start, [int end]) {
+    end = _checkValidRange(start, end, this.length);
+    return NativeFloat32x4List._externalStorage(
+        _storage.sublist(start * 4, end * 4));
+  }
+}
+
+/**
+ * A fixed-length list of Int32x4 numbers that is viewable as a
+ * [TypedData]. For long lists, this implementation will be considerably more
+ * space- and time-efficient than the default [List] implementation.
+ */
+class NativeInt32x4List extends Object
+    with ListMixin<Int32x4>, FixedLengthListMixin<Int32x4>
+    implements Int32x4List {
+  final Int32List _storage;
+
+  /**
+   * Creates a [Int32x4List] of the specified length (in elements),
+   * all of whose elements are initially zero.
+   */
+  NativeInt32x4List(int length) : _storage = NativeInt32List(length * 4);
+
+  NativeInt32x4List._externalStorage(Int32List storage) : _storage = storage;
+
+  NativeInt32x4List._slowFromList(List<Int32x4> list)
+      : _storage = NativeInt32List(list.length * 4) {
+    for (int i = 0; i < list.length; i++) {
+      var e = list[i];
+      _storage[(i * 4) + 0] = e.x;
+      _storage[(i * 4) + 1] = e.y;
+      _storage[(i * 4) + 2] = e.z;
+      _storage[(i * 4) + 3] = e.w;
+    }
+  }
+
+  Type get runtimeType => Int32x4List;
+
+  /**
+   * Creates a [Int32x4List] with the same size as the [elements] list
+   * and copies over the elements.
+   */
+  factory NativeInt32x4List.fromList(List<Int32x4> list) {
+    if (list is NativeInt32x4List) {
+      return NativeInt32x4List._externalStorage(
+          NativeInt32List.fromList(list._storage));
+    } else {
+      return NativeInt32x4List._slowFromList(list);
+    }
+  }
+
+  ByteBuffer get buffer => _storage.buffer;
+
+  int get lengthInBytes => _storage.lengthInBytes;
+
+  int get offsetInBytes => _storage.offsetInBytes;
+
+  int get elementSizeInBytes => Int32x4List.bytesPerElement;
+
+  int get length => _storage.length ~/ 4;
+
+  Int32x4 operator [](int index) {
+    _checkValidIndex(index, this, this.length);
+    int _x = _storage[(index * 4) + 0];
+    int _y = _storage[(index * 4) + 1];
+    int _z = _storage[(index * 4) + 2];
+    int _w = _storage[(index * 4) + 3];
+    return NativeInt32x4._truncated(_x, _y, _z, _w);
+  }
+
+  void operator []=(int index, Int32x4 value) {
+    _checkValidIndex(index, this, this.length);
+    _storage[(index * 4) + 0] = value.x;
+    _storage[(index * 4) + 1] = value.y;
+    _storage[(index * 4) + 2] = value.z;
+    _storage[(index * 4) + 3] = value.w;
+  }
+
+  Int32x4List sublist(int start, [int end]) {
+    end = _checkValidRange(start, end, this.length);
+    return NativeInt32x4List._externalStorage(
+        _storage.sublist(start * 4, end * 4));
+  }
+}
+
+/**
+ * A fixed-length list of Float64x2 numbers that is viewable as a
+ * [TypedData]. For long lists, this implementation will be considerably more
+ * space- and time-efficient than the default [List] implementation.
+ */
+class NativeFloat64x2List extends Object
+    with ListMixin<Float64x2>, FixedLengthListMixin<Float64x2>
+    implements Float64x2List {
+  final NativeFloat64List _storage;
+
+  /**
+   * Creates a [Float64x2List] of the specified length (in elements),
+   * all of whose elements are initially zero.
+   */
+  NativeFloat64x2List(int length) : _storage = NativeFloat64List(length * 2);
+
+  NativeFloat64x2List._externalStorage(this._storage);
+
+  NativeFloat64x2List._slowFromList(List<Float64x2> list)
+      : _storage = NativeFloat64List(list.length * 2) {
+    for (int i = 0; i < list.length; i++) {
+      var e = list[i];
+      _storage[(i * 2) + 0] = e.x;
+      _storage[(i * 2) + 1] = e.y;
+    }
+  }
+
+  /**
+   * Creates a [Float64x2List] with the same size as the [elements] list
+   * and copies over the elements.
+   */
+  factory NativeFloat64x2List.fromList(List<Float64x2> list) {
+    if (list is NativeFloat64x2List) {
+      return NativeFloat64x2List._externalStorage(
+          NativeFloat64List.fromList(list._storage));
+    } else {
+      return NativeFloat64x2List._slowFromList(list);
+    }
+  }
+
+  Type get runtimeType => Float64x2List;
+
+  ByteBuffer get buffer => _storage.buffer;
+
+  int get lengthInBytes => _storage.lengthInBytes;
+
+  int get offsetInBytes => _storage.offsetInBytes;
+
+  int get elementSizeInBytes => Float64x2List.bytesPerElement;
+
+  int get length => _storage.length ~/ 2;
+
+  Float64x2 operator [](int index) {
+    _checkValidIndex(index, this, this.length);
+    double _x = _storage[(index * 2) + 0];
+    double _y = _storage[(index * 2) + 1];
+    return Float64x2(_x, _y);
+  }
+
+  void operator []=(int index, Float64x2 value) {
+    _checkValidIndex(index, this, this.length);
+    _storage[(index * 2) + 0] = value.x;
+    _storage[(index * 2) + 1] = value.y;
+  }
+
+  Float64x2List sublist(int start, [int end]) {
+    end = _checkValidRange(start, end, this.length);
+    return NativeFloat64x2List._externalStorage(
+        _storage.sublist(start * 2, end * 2));
+  }
+}
+
+@Native("ArrayBufferView")
+class NativeTypedData implements TypedData {
+  /**
+   * Returns the byte buffer associated with this object.
+   */
+  @Creates('NativeByteBuffer')
+  // May be Null for IE's CanvasPixelArray.
+  @Returns('NativeByteBuffer|Null')
+  external ByteBuffer get buffer;
+
+  /**
+   * Returns the length of this view, in bytes.
+   */
+  @JSName('byteLength')
+  external int get lengthInBytes;
+
+  /**
+   * Returns the offset in bytes into the underlying byte buffer of this view.
+   */
+  @JSName('byteOffset')
+  external int get offsetInBytes;
+
+  /**
+   * Returns the number of bytes in the representation of each element in this
+   * list.
+   */
+  @JSName('BYTES_PER_ELEMENT')
+  external int get elementSizeInBytes;
+
+  void _invalidPosition(int position, int length, String name) {
+    if (position is! int) {
+      throw ArgumentError.value(position, name, 'Invalid list position');
+    } else {
+      throw RangeError.range(position, 0, length, name);
+    }
+  }
+
+  void _checkPosition(int position, int length, String name) {
+    if (JS<bool>('!', '(# >>> 0) !== #', position, position) ||
+        JS<int>('!', '#', position) > length) {
+      // 'int' guaranteed by above test.
+      _invalidPosition(position, length, name);
+    }
+  }
+}
+
+// Validates the unnamed constructor length argument.  Checking is necessary
+// because passing unvalidated values to the native constructors can cause
+// conversions or create views.
+int _checkLength(length) {
+  if (length is! int) throw ArgumentError('Invalid length $length');
+  return length;
+}
+
+// Validates `.view` constructor arguments.  Checking is necessary because
+// passing unvalidated values to the native constructors can cause conversions
+// (e.g. String arguments) or create typed data objects that are not actually
+// views of the input.
+void _checkViewArguments(buffer, offsetInBytes, length) {
+  if (buffer is! NativeByteBuffer) {
+    throw ArgumentError('Invalid view buffer');
+  }
+  if (offsetInBytes is! int) {
+    throw ArgumentError('Invalid view offsetInBytes $offsetInBytes');
+  }
+  if (length != null && length is! int) {
+    throw ArgumentError('Invalid view length $length');
+  }
+}
+
+// Ensures that [list] is a JavaScript Array or a typed array.  If necessary,
+// returns a copy of the list.
+List _ensureNativeList(List list) {
+  if (list is JSIndexable) return list;
+  List result = List(list.length);
+  for (int i = 0; i < list.length; i++) {
+    result[i] = list[i];
+  }
+  return result;
+}
+
+@Native("DataView")
+class NativeByteData extends NativeTypedData implements ByteData {
+  /**
+   * Creates a [ByteData] of the specified length (in elements), all of
+   * whose elements are initially zero.
+   */
+  factory NativeByteData(int length) => _create1(_checkLength(length));
+
+  /**
+   * Creates an [ByteData] _view_ of the specified region in the specified
+   * byte buffer. Changes in the [ByteData] will be visible in the byte
+   * buffer and vice versa. If the [offsetInBytes] index of the region is not
+   * specified, it defaults to zero (the first byte in the byte buffer).
+   * If the length is not specified, it defaults to null, which indicates
+   * that the view extends to the end of the byte buffer.
+   *
+   * Throws [RangeError] if [offsetInBytes] or [length] are negative, or
+   * if [offsetInBytes] + ([length] * elementSizeInBytes) is greater than
+   * the length of [buffer].
+   */
+  factory NativeByteData.view(
+      ByteBuffer buffer, int offsetInBytes, int length) {
+    _checkViewArguments(buffer, offsetInBytes, length);
+    return length == null
+        ? _create2(buffer, offsetInBytes)
+        : _create3(buffer, offsetInBytes, length);
+  }
+
+  Type get runtimeType => ByteData;
+
+  int get elementSizeInBytes => 1;
+
+  /**
+   * Returns the floating point number represented by the four bytes at
+   * the specified [byteOffset] in this object, in IEEE 754
+   * single-precision binary floating-point format (binary32).
+   *
+   * Throws [RangeError] if [byteOffset] is negative, or
+   * `byteOffset + 4` is greater than the length of this object.
+   */
+  double getFloat32(int byteOffset, [Endian endian = Endian.big]) =>
+      _getFloat32(byteOffset, Endian.little == endian);
+
+  @JSName('getFloat32')
+  @Returns('double')
+  double _getFloat32(int byteOffset, [bool littleEndian]) native;
+
+  /**
+   * Returns the floating point number represented by the eight bytes at
+   * the specified [byteOffset] in this object, in IEEE 754
+   * double-precision binary floating-point format (binary64).
+   *
+   * Throws [RangeError] if [byteOffset] is negative, or
+   * `byteOffset + 8` is greater than the length of this object.
+   */
+  double getFloat64(int byteOffset, [Endian endian = Endian.big]) =>
+      _getFloat64(byteOffset, Endian.little == endian);
+
+  @JSName('getFloat64')
+  @Returns('double')
+  double _getFloat64(int byteOffset, [bool littleEndian]) native;
+
+  /**
+   * Returns the (possibly negative) integer represented by the two bytes at
+   * the specified [byteOffset] in this object, in two's complement binary
+   * form.
+   * The return value will be between 2<sup>15</sup> and 2<sup>15</sup> - 1,
+   * inclusive.
+   *
+   * Throws [RangeError] if [byteOffset] is negative, or
+   * `byteOffset + 2` is greater than the length of this object.
+   */
+  int getInt16(int byteOffset, [Endian endian = Endian.big]) =>
+      _getInt16(byteOffset, Endian.little == endian);
+
+  @JSName('getInt16')
+  @Returns('int')
+  int _getInt16(int byteOffset, [bool littleEndian]) native;
+
+  /**
+   * Returns the (possibly negative) integer represented by the four bytes at
+   * the specified [byteOffset] in this object, in two's complement binary
+   * form.
+   * The return value will be between 2<sup>31</sup> and 2<sup>31</sup> - 1,
+   * inclusive.
+   *
+   * Throws [RangeError] if [byteOffset] is negative, or
+   * `byteOffset + 4` is greater than the length of this object.
+   */
+  int getInt32(int byteOffset, [Endian endian = Endian.big]) =>
+      _getInt32(byteOffset, Endian.little == endian);
+
+  @JSName('getInt32')
+  @Returns('int')
+  int _getInt32(int byteOffset, [bool littleEndian]) native;
+
+  /**
+   * Returns the (possibly negative) integer represented by the eight bytes at
+   * the specified [byteOffset] in this object, in two's complement binary
+   * form.
+   * The return value will be between 2<sup>63</sup> and 2<sup>63</sup> - 1,
+   * inclusive.
+   *
+   * Throws [RangeError] if [byteOffset] is negative, or
+   * `byteOffset + 8` is greater than the length of this object.
+   */
+  int getInt64(int byteOffset, [Endian endian = Endian.big]) {
+    throw UnsupportedError('Int64 accessor not supported by dart2js.');
+  }
+
+  /**
+   * Returns the (possibly negative) integer represented by the byte at the
+   * specified [byteOffset] in this object, in two's complement binary
+   * representation. The return value will be between -128 and 127, inclusive.
+   *
+   * Throws [RangeError] if [byteOffset] is negative, or
+   * greater than or equal to the length of this object.
+   */
+  int getInt8(int byteOffset) native;
+
+  /**
+   * Returns the positive integer represented by the two bytes starting
+   * at the specified [byteOffset] in this object, in unsigned binary
+   * form.
+   * The return value will be between 0 and  2<sup>16</sup> - 1, inclusive.
+   *
+   * Throws [RangeError] if [byteOffset] is negative, or
+   * `byteOffset + 2` is greater than the length of this object.
+   */
+  int getUint16(int byteOffset, [Endian endian = Endian.big]) =>
+      _getUint16(byteOffset, Endian.little == endian);
+
+  @JSName('getUint16')
+  @Returns('int')
+  int _getUint16(int byteOffset, [bool littleEndian]) native;
+
+  /**
+   * Returns the positive integer represented by the four bytes starting
+   * at the specified [byteOffset] in this object, in unsigned binary
+   * form.
+   * The return value will be between 0 and  2<sup>32</sup> - 1, inclusive.
+   *
+   * Throws [RangeError] if [byteOffset] is negative, or
+   * `byteOffset + 4` is greater than the length of this object.
+   */
+  int getUint32(int byteOffset, [Endian endian = Endian.big]) =>
+      _getUint32(byteOffset, Endian.little == endian);
+
+  @JSName('getUint32')
+  @Returns('int')
+  int _getUint32(int byteOffset, [bool littleEndian]) native;
+
+  /**
+   * Returns the positive integer represented by the eight bytes starting
+   * at the specified [byteOffset] in this object, in unsigned binary
+   * form.
+   * The return value will be between 0 and  2<sup>64</sup> - 1, inclusive.
+   *
+   * Throws [RangeError] if [byteOffset] is negative, or
+   * `byteOffset + 8` is greater than the length of this object.
+   */
+  int getUint64(int byteOffset, [Endian endian = Endian.big]) {
+    throw UnsupportedError('Uint64 accessor not supported by dart2js.');
+  }
+
+  /**
+   * Returns the positive integer represented by the byte at the specified
+   * [byteOffset] in this object, in unsigned binary form. The
+   * return value will be between 0 and 255, inclusive.
+   *
+   * Throws [RangeError] if [byteOffset] is negative, or
+   * greater than or equal to the length of this object.
+   */
+  int getUint8(int byteOffset) native;
+
+  /**
+   * Sets the four bytes starting at the specified [byteOffset] in this
+   * object to the IEEE 754 single-precision binary floating-point
+   * (binary32) representation of the specified [value].
+   *
+   * **Note that this method can lose precision.** The input [value] is
+   * a 64-bit floating point value, which will be converted to 32-bit
+   * floating point value by IEEE 754 rounding rules before it is stored.
+   * If [value] cannot be represented exactly as a binary32, it will be
+   * converted to the nearest binary32 value.  If two binary32 values are
+   * equally close, the one whose least significant bit is zero will be used.
+   * Note that finite (but large) values can be converted to infinity, and
+   * small non-zero values can be converted to zero.
+   *
+   * Throws [RangeError] if [byteOffset] is negative, or
+   * `byteOffset + 4` is greater than the length of this object.
+   */
+  void setFloat32(int byteOffset, num value, [Endian endian = Endian.big]) =>
+      _setFloat32(byteOffset, value, Endian.little == endian);
+
+  @JSName('setFloat32')
+  void _setFloat32(int byteOffset, num value, [bool littleEndian]) native;
+
+  /**
+   * Sets the eight bytes starting at the specified [byteOffset] in this
+   * object to the IEEE 754 double-precision binary floating-point
+   * (binary64) representation of the specified [value].
+   *
+   * Throws [RangeError] if [byteOffset] is negative, or
+   * `byteOffset + 8` is greater than the length of this object.
+   */
+  void setFloat64(int byteOffset, num value, [Endian endian = Endian.big]) =>
+      _setFloat64(byteOffset, value, Endian.little == endian);
+
+  @JSName('setFloat64')
+  void _setFloat64(int byteOffset, num value, [bool littleEndian]) native;
+
+  /**
+   * Sets the two bytes starting at the specified [byteOffset] in this
+   * object to the two's complement binary representation of the specified
+   * [value], which must fit in two bytes. In other words, [value] must lie
+   * between 2<sup>15</sup> and 2<sup>15</sup> - 1, inclusive.
+   *
+   * Throws [RangeError] if [byteOffset] is negative, or
+   * `byteOffset + 2` is greater than the length of this object.
+   */
+  void setInt16(int byteOffset, int value, [Endian endian = Endian.big]) =>
+      _setInt16(byteOffset, value, Endian.little == endian);
+
+  @JSName('setInt16')
+  void _setInt16(int byteOffset, int value, [bool littleEndian]) native;
+
+  /**
+   * Sets the four bytes starting at the specified [byteOffset] in this
+   * object to the two's complement binary representation of the specified
+   * [value], which must fit in four bytes. In other words, [value] must lie
+   * between 2<sup>31</sup> and 2<sup>31</sup> - 1, inclusive.
+   *
+   * Throws [RangeError] if [byteOffset] is negative, or
+   * `byteOffset + 4` is greater than the length of this object.
+   */
+  void setInt32(int byteOffset, int value, [Endian endian = Endian.big]) =>
+      _setInt32(byteOffset, value, Endian.little == endian);
+
+  @JSName('setInt32')
+  void _setInt32(int byteOffset, int value, [bool littleEndian]) native;
+
+  /**
+   * Sets the eight bytes starting at the specified [byteOffset] in this
+   * object to the two's complement binary representation of the specified
+   * [value], which must fit in eight bytes. In other words, [value] must lie
+   * between 2<sup>63</sup> and 2<sup>63</sup> - 1, inclusive.
+   *
+   * Throws [RangeError] if [byteOffset] is negative, or
+   * `byteOffset + 8` is greater than the length of this object.
+   */
+  void setInt64(int byteOffset, int value, [Endian endian = Endian.big]) {
+    throw UnsupportedError('Int64 accessor not supported by dart2js.');
+  }
+
+  /**
+   * Sets the byte at the specified [byteOffset] in this object to the
+   * two's complement binary representation of the specified [value], which
+   * must fit in a single byte. In other words, [value] must be between
+   * -128 and 127, inclusive.
+   *
+   * Throws [RangeError] if [byteOffset] is negative, or
+   * greater than or equal to the length of this object.
+   */
+  void setInt8(int byteOffset, int value) native;
+
+  /**
+   * Sets the two bytes starting at the specified [byteOffset] in this object
+   * to the unsigned binary representation of the specified [value],
+   * which must fit in two bytes. in other words, [value] must be between
+   * 0 and 2<sup>16</sup> - 1, inclusive.
+   *
+   * Throws [RangeError] if [byteOffset] is negative, or
+   * `byteOffset + 2` is greater than the length of this object.
+   */
+  void setUint16(int byteOffset, int value, [Endian endian = Endian.big]) =>
+      _setUint16(byteOffset, value, Endian.little == endian);
+
+  @JSName('setUint16')
+  void _setUint16(int byteOffset, int value, [bool littleEndian]) native;
+
+  /**
+   * Sets the four bytes starting at the specified [byteOffset] in this object
+   * to the unsigned binary representation of the specified [value],
+   * which must fit in four bytes. in other words, [value] must be between
+   * 0 and 2<sup>32</sup> - 1, inclusive.
+   *
+   * Throws [RangeError] if [byteOffset] is negative, or
+   * `byteOffset + 4` is greater than the length of this object.
+   */
+  void setUint32(int byteOffset, int value, [Endian endian = Endian.big]) =>
+      _setUint32(byteOffset, value, Endian.little == endian);
+
+  @JSName('setUint32')
+  void _setUint32(int byteOffset, int value, [bool littleEndian]) native;
+
+  /**
+   * Sets the eight bytes starting at the specified [byteOffset] in this object
+   * to the unsigned binary representation of the specified [value],
+   * which must fit in eight bytes. in other words, [value] must be between
+   * 0 and 2<sup>64</sup> - 1, inclusive.
+   *
+   * Throws [RangeError] if [byteOffset] is negative, or
+   * `byteOffset + 8` is greater than the length of this object.
+   */
+  void setUint64(int byteOffset, int value, [Endian endian = Endian.big]) {
+    throw UnsupportedError('Uint64 accessor not supported by dart2js.');
+  }
+
+  /**
+   * Sets the byte at the specified [byteOffset] in this object to the
+   * unsigned binary representation of the specified [value], which must fit
+   * in a single byte. in other words, [value] must be between 0 and 255,
+   * inclusive.
+   *
+   * Throws [RangeError] if [byteOffset] is negative,
+   * or greater than or equal to the length of this object.
+   */
+  void setUint8(int byteOffset, int value) native;
+
+  static NativeByteData _create1(arg) =>
+      JS('NativeByteData', 'new DataView(new ArrayBuffer(#))', arg);
+
+  static NativeByteData _create2(arg1, arg2) =>
+      JS('NativeByteData', 'new DataView(#, #)', arg1, arg2);
+
+  static NativeByteData _create3(arg1, arg2, arg3) =>
+      JS('NativeByteData', 'new DataView(#, #, #)', arg1, arg2, arg3);
+}
+
+abstract class NativeTypedArray extends NativeTypedData
+    implements JavaScriptIndexingBehavior {
+  int get length;
+
+  void _setRangeFast(
+      int start, int end, NativeTypedArray source, int skipCount) {
+    int targetLength = this.length;
+    _checkPosition(start, targetLength, "start");
+    _checkPosition(end, targetLength, "end");
+    if (start > end) throw RangeError.range(start, 0, end);
+    int count = end - start;
+
+    if (skipCount < 0) throw ArgumentError(skipCount);
+
+    int sourceLength = source.length;
+    if (sourceLength - skipCount < count) {
+      throw StateError('Not enough elements');
+    }
+
+    if (skipCount != 0 || sourceLength != count) {
+      // Create a view of the exact subrange that is copied from the source.
+      source = JS('', '#.subarray(#, #)', source, skipCount, skipCount + count);
+    }
+    JS('void', '#.set(#, #)', this, source, start);
+  }
+}
+
+abstract class NativeTypedArrayOfDouble extends NativeTypedArray
+    with ListMixin<double>, FixedLengthListMixin<double> {
+  int get length => JS<int>('!', '#.length', this);
+
+  double operator [](int index) {
+    _checkValidIndex(index, this, this.length);
+    return JS<double>('!', '#[#]', this, index);
+  }
+
+  void operator []=(int index, num value) {
+    _checkValidIndex(index, this, this.length);
+    JS('void', '#[#] = #', this, index, value);
+  }
+
+  void setRange(int start, int end, Iterable<double> iterable,
+      [int skipCount = 0]) {
+    if (iterable is NativeTypedArrayOfDouble) {
+      _setRangeFast(start, end, iterable, skipCount);
+      return;
+    }
+    super.setRange(start, end, iterable, skipCount);
+  }
+}
+
+abstract class NativeTypedArrayOfInt extends NativeTypedArray
+    with ListMixin<int>, FixedLengthListMixin<int>
+    implements List<int> {
+  int get length => JS<int>('!', '#.length', this);
+
+  // operator[]() is not here since different versions have different return
+  // types
+
+  void operator []=(int index, int value) {
+    _checkValidIndex(index, this, this.length);
+    JS('void', '#[#] = #', this, index, value);
+  }
+
+  void setRange(int start, int end, Iterable<int> iterable,
+      [int skipCount = 0]) {
+    if (iterable is NativeTypedArrayOfInt) {
+      _setRangeFast(start, end, iterable, skipCount);
+      return;
+    }
+    super.setRange(start, end, iterable, skipCount);
+  }
+}
+
+@Native("Float32Array")
+class NativeFloat32List extends NativeTypedArrayOfDouble
+    implements Float32List {
+  factory NativeFloat32List(int length) => _create1(_checkLength(length));
+
+  factory NativeFloat32List.fromList(List<double> elements) =>
+      _create1(_ensureNativeList(elements));
+
+  factory NativeFloat32List.view(
+      ByteBuffer buffer, int offsetInBytes, int length) {
+    _checkViewArguments(buffer, offsetInBytes, length);
+    return length == null
+        ? _create2(buffer, offsetInBytes)
+        : _create3(buffer, offsetInBytes, length);
+  }
+
+  Type get runtimeType => Float32List;
+
+  Float32List sublist(int start, [int end]) {
+    end = _checkValidRange(start, end, this.length);
+    var source =
+        JS<NativeFloat32List>('!', '#.subarray(#, #)', this, start, end);
+    return _create1(source);
+  }
+
+  static NativeFloat32List _create1(arg) =>
+      JS<NativeFloat32List>('!', 'new Float32Array(#)', arg);
+
+  static NativeFloat32List _create2(arg1, arg2) =>
+      JS<NativeFloat32List>('!', 'new Float32Array(#, #)', arg1, arg2);
+
+  static NativeFloat32List _create3(arg1, arg2, arg3) =>
+      JS<NativeFloat32List>('!', 'new Float32Array(#, #, #)', arg1, arg2, arg3);
+}
+
+@Native("Float64Array")
+class NativeFloat64List extends NativeTypedArrayOfDouble
+    implements Float64List {
+  factory NativeFloat64List(int length) => _create1(_checkLength(length));
+
+  factory NativeFloat64List.fromList(List<double> elements) =>
+      _create1(_ensureNativeList(elements));
+
+  factory NativeFloat64List.view(
+      ByteBuffer buffer, int offsetInBytes, int length) {
+    _checkViewArguments(buffer, offsetInBytes, length);
+    return length == null
+        ? _create2(buffer, offsetInBytes)
+        : _create3(buffer, offsetInBytes, length);
+  }
+
+  Type get runtimeType => Float64List;
+
+  Float64List sublist(int start, [int end]) {
+    end = _checkValidRange(start, end, this.length);
+    var source = JS('NativeFloat64List', '#.subarray(#, #)', this, start, end);
+    return _create1(source);
+  }
+
+  static NativeFloat64List _create1(arg) =>
+      JS('NativeFloat64List', 'new Float64Array(#)', arg);
+
+  static NativeFloat64List _create2(arg1, arg2) =>
+      JS('NativeFloat64List', 'new Float64Array(#, #)', arg1, arg2);
+
+  static NativeFloat64List _create3(arg1, arg2, arg3) =>
+      JS('NativeFloat64List', 'new Float64Array(#, #, #)', arg1, arg2, arg3);
+}
+
+@Native("Int16Array")
+class NativeInt16List extends NativeTypedArrayOfInt implements Int16List {
+  factory NativeInt16List(int length) => _create1(_checkLength(length));
+
+  factory NativeInt16List.fromList(List<int> elements) =>
+      _create1(_ensureNativeList(elements));
+
+  factory NativeInt16List.view(
+      NativeByteBuffer buffer, int offsetInBytes, int length) {
+    _checkViewArguments(buffer, offsetInBytes, length);
+    return length == null
+        ? _create2(buffer, offsetInBytes)
+        : _create3(buffer, offsetInBytes, length);
+  }
+
+  Type get runtimeType => Int16List;
+
+  int operator [](int index) {
+    _checkValidIndex(index, this, this.length);
+    return JS<int>('!', '#[#]', this, index);
+  }
+
+  Int16List sublist(int start, [int end]) {
+    end = _checkValidRange(start, end, this.length);
+    var source = JS('NativeInt16List', '#.subarray(#, #)', this, start, end);
+    return _create1(source);
+  }
+
+  static NativeInt16List _create1(arg) =>
+      JS('NativeInt16List', 'new Int16Array(#)', arg);
+
+  static NativeInt16List _create2(arg1, arg2) =>
+      JS('NativeInt16List', 'new Int16Array(#, #)', arg1, arg2);
+
+  static NativeInt16List _create3(arg1, arg2, arg3) =>
+      JS('NativeInt16List', 'new Int16Array(#, #, #)', arg1, arg2, arg3);
+}
+
+@Native("Int32Array")
+class NativeInt32List extends NativeTypedArrayOfInt implements Int32List {
+  factory NativeInt32List(int length) => _create1(_checkLength(length));
+
+  factory NativeInt32List.fromList(List<int> elements) =>
+      _create1(_ensureNativeList(elements));
+
+  factory NativeInt32List.view(
+      ByteBuffer buffer, int offsetInBytes, int length) {
+    _checkViewArguments(buffer, offsetInBytes, length);
+    return length == null
+        ? _create2(buffer, offsetInBytes)
+        : _create3(buffer, offsetInBytes, length);
+  }
+
+  Type get runtimeType => Int32List;
+
+  int operator [](int index) {
+    _checkValidIndex(index, this, this.length);
+    return JS<int>('!', '#[#]', this, index);
+  }
+
+  Int32List sublist(int start, [int end]) {
+    end = _checkValidRange(start, end, this.length);
+    var source = JS<NativeInt32List>('!', '#.subarray(#, #)', this, start, end);
+    return _create1(source);
+  }
+
+  static NativeInt32List _create1(arg) =>
+      JS<NativeInt32List>('!', 'new Int32Array(#)', arg);
+
+  static NativeInt32List _create2(arg1, arg2) =>
+      JS<NativeInt32List>('!', 'new Int32Array(#, #)', arg1, arg2);
+
+  static NativeInt32List _create3(arg1, arg2, arg3) =>
+      JS<NativeInt32List>('!', 'new Int32Array(#, #, #)', arg1, arg2, arg3);
+}
+
+@Native("Int8Array")
+class NativeInt8List extends NativeTypedArrayOfInt implements Int8List {
+  factory NativeInt8List(int length) => _create1(_checkLength(length));
+
+  factory NativeInt8List.fromList(List<int> elements) =>
+      _create1(_ensureNativeList(elements));
+
+  factory NativeInt8List.view(
+      ByteBuffer buffer, int offsetInBytes, int length) {
+    _checkViewArguments(buffer, offsetInBytes, length);
+    return length == null
+        ? _create2(buffer, offsetInBytes)
+        : _create3(buffer, offsetInBytes, length);
+  }
+
+  Type get runtimeType => Int8List;
+
+  int operator [](int index) {
+    _checkValidIndex(index, this, this.length);
+    return JS<int>('!', '#[#]', this, index);
+  }
+
+  Int8List sublist(int start, [int end]) {
+    end = _checkValidRange(start, end, this.length);
+    var source = JS<NativeInt8List>('!', '#.subarray(#, #)', this, start, end);
+    return _create1(source);
+  }
+
+  static NativeInt8List _create1(arg) =>
+      JS<NativeInt8List>('!', 'new Int8Array(#)', arg);
+
+  static NativeInt8List _create2(arg1, arg2) =>
+      JS<NativeInt8List>('!', 'new Int8Array(#, #)', arg1, arg2);
+
+  static Int8List _create3(arg1, arg2, arg3) =>
+      JS<NativeInt8List>('!', 'new Int8Array(#, #, #)', arg1, arg2, arg3);
+}
+
+@Native("Uint16Array")
+class NativeUint16List extends NativeTypedArrayOfInt implements Uint16List {
+  factory NativeUint16List(int length) => _create1(_checkLength(length));
+
+  factory NativeUint16List.fromList(List<int> list) =>
+      _create1(_ensureNativeList(list));
+
+  factory NativeUint16List.view(
+      ByteBuffer buffer, int offsetInBytes, int length) {
+    _checkViewArguments(buffer, offsetInBytes, length);
+    return length == null
+        ? _create2(buffer, offsetInBytes)
+        : _create3(buffer, offsetInBytes, length);
+  }
+
+  Type get runtimeType => Uint16List;
+
+  int operator [](int index) {
+    _checkValidIndex(index, this, this.length);
+    return JS<int>('!', '#[#]', this, index);
+  }
+
+  Uint16List sublist(int start, [int end]) {
+    end = _checkValidRange(start, end, this.length);
+    var source =
+        JS<NativeUint16List>('!', '#.subarray(#, #)', this, start, end);
+    return _create1(source);
+  }
+
+  static NativeUint16List _create1(arg) =>
+      JS<NativeUint16List>('!', 'new Uint16Array(#)', arg);
+
+  static NativeUint16List _create2(arg1, arg2) =>
+      JS<NativeUint16List>('!', 'new Uint16Array(#, #)', arg1, arg2);
+
+  static NativeUint16List _create3(arg1, arg2, arg3) =>
+      JS<NativeUint16List>('!', 'new Uint16Array(#, #, #)', arg1, arg2, arg3);
+}
+
+@Native("Uint32Array")
+class NativeUint32List extends NativeTypedArrayOfInt implements Uint32List {
+  factory NativeUint32List(int length) => _create1(_checkLength(length));
+
+  factory NativeUint32List.fromList(List<int> elements) =>
+      _create1(_ensureNativeList(elements));
+
+  factory NativeUint32List.view(
+      ByteBuffer buffer, int offsetInBytes, int length) {
+    _checkViewArguments(buffer, offsetInBytes, length);
+    return length == null
+        ? _create2(buffer, offsetInBytes)
+        : _create3(buffer, offsetInBytes, length);
+  }
+
+  Type get runtimeType => Uint32List;
+
+  int operator [](int index) {
+    _checkValidIndex(index, this, this.length);
+    return JS<int>('!', '#[#]', this, index);
+  }
+
+  Uint32List sublist(int start, [int end]) {
+    end = _checkValidRange(start, end, this.length);
+    var source =
+        JS<NativeUint32List>('!', '#.subarray(#, #)', this, start, end);
+    return _create1(source);
+  }
+
+  static NativeUint32List _create1(arg) =>
+      JS<NativeUint32List>('!', 'new Uint32Array(#)', arg);
+
+  static NativeUint32List _create2(arg1, arg2) =>
+      JS<NativeUint32List>('!', 'new Uint32Array(#, #)', arg1, arg2);
+
+  static NativeUint32List _create3(arg1, arg2, arg3) =>
+      JS<NativeUint32List>('!', 'new Uint32Array(#, #, #)', arg1, arg2, arg3);
+}
+
+@Native("Uint8ClampedArray,CanvasPixelArray")
+class NativeUint8ClampedList extends NativeTypedArrayOfInt
+    implements Uint8ClampedList {
+  factory NativeUint8ClampedList(int length) => _create1(_checkLength(length));
+
+  factory NativeUint8ClampedList.fromList(List<int> elements) =>
+      _create1(_ensureNativeList(elements));
+
+  factory NativeUint8ClampedList.view(
+      ByteBuffer buffer, int offsetInBytes, int length) {
+    _checkViewArguments(buffer, offsetInBytes, length);
+    return length == null
+        ? _create2(buffer, offsetInBytes)
+        : _create3(buffer, offsetInBytes, length);
+  }
+
+  Type get runtimeType => Uint8ClampedList;
+
+  int get length => JS<int>('!', '#.length', this);
+
+  int operator [](int index) {
+    _checkValidIndex(index, this, this.length);
+    return JS<int>('!', '#[#]', this, index);
+  }
+
+  Uint8ClampedList sublist(int start, [int end]) {
+    end = _checkValidRange(start, end, this.length);
+    var source =
+        JS<NativeUint8ClampedList>('!', '#.subarray(#, #)', this, start, end);
+    return _create1(source);
+  }
+
+  static NativeUint8ClampedList _create1(arg) =>
+      JS<NativeUint8ClampedList>('!', 'new Uint8ClampedArray(#)', arg);
+
+  static NativeUint8ClampedList _create2(arg1, arg2) =>
+      JS<NativeUint8ClampedList>(
+          '!', 'new Uint8ClampedArray(#, #)', arg1, arg2);
+
+  static NativeUint8ClampedList _create3(arg1, arg2, arg3) => JS(
+      'NativeUint8ClampedList',
+      'new Uint8ClampedArray(#, #, #)',
+      arg1,
+      arg2,
+      arg3);
+}
+
+// On some browsers Uint8ClampedArray is a subtype of Uint8Array.  Marking
+// Uint8List as !nonleaf ensures that the native dispatch correctly handles
+// the potential for Uint8ClampedArray to 'accidentally' pick up the
+// dispatch record for Uint8List.
+@Native("Uint8Array,!nonleaf")
+class NativeUint8List extends NativeTypedArrayOfInt implements Uint8List {
+  factory NativeUint8List(int length) => _create1(_checkLength(length));
+
+  factory NativeUint8List.fromList(List<int> elements) =>
+      _create1(_ensureNativeList(elements));
+
+  factory NativeUint8List.view(
+      ByteBuffer buffer, int offsetInBytes, int length) {
+    _checkViewArguments(buffer, offsetInBytes, length);
+    return length == null
+        ? _create2(buffer, offsetInBytes)
+        : _create3(buffer, offsetInBytes, length);
+  }
+
+  Type get runtimeType => Uint8List;
+
+  int get length => JS<int>('!', '#.length', this);
+
+  int operator [](int index) {
+    _checkValidIndex(index, this, this.length);
+    return JS<int>('!', '#[#]', this, index);
+  }
+
+  Uint8List sublist(int start, [int end]) {
+    end = _checkValidRange(start, end, this.length);
+    var source = JS<NativeUint8List>('!', '#.subarray(#, #)', this, start, end);
+    return _create1(source);
+  }
+
+  static NativeUint8List _create1(arg) =>
+      JS<NativeUint8List>('!', 'new Uint8Array(#)', arg);
+
+  static NativeUint8List _create2(arg1, arg2) =>
+      JS<NativeUint8List>('!', 'new Uint8Array(#, #)', arg1, arg2);
+
+  static NativeUint8List _create3(arg1, arg2, arg3) =>
+      JS<NativeUint8List>('!', 'new Uint8Array(#, #, #)', arg1, arg2, arg3);
+}
+
+/**
+ * Implementation of Dart Float32x4 immutable value type and operations.
+ * Float32x4 stores 4 32-bit floating point values in "lanes".
+ * The lanes are "x", "y", "z", and "w" respectively.
+ */
+class NativeFloat32x4 implements Float32x4 {
+  final double x;
+  final double y;
+  final double z;
+  final double w;
+
+  static final NativeFloat32List _list = NativeFloat32List(4);
+  static final Uint32List _uint32view = _list.buffer.asUint32List();
+
+  static _truncate(x) {
+    _list[0] = x;
+    return _list[0];
+  }
+
+  NativeFloat32x4(double x, double y, double z, double w)
+      : this.x = _truncate(x),
+        this.y = _truncate(y),
+        this.z = _truncate(z),
+        this.w = _truncate(w) {
+    // We would prefer to check for `double` but in dart2js we can't see the
+    // difference anyway.
+    if (x is! num) throw ArgumentError(x);
+    if (y is! num) throw ArgumentError(y);
+    if (z is! num) throw ArgumentError(z);
+    if (w is! num) throw ArgumentError(w);
+  }
+
+  NativeFloat32x4.splat(double v) : this(v, v, v, v);
+  NativeFloat32x4.zero() : this._truncated(0.0, 0.0, 0.0, 0.0);
+
+  /// Returns a bit-wise copy of [i] as a Float32x4.
+  factory NativeFloat32x4.fromInt32x4Bits(Int32x4 i) {
+    _uint32view[0] = i.x;
+    _uint32view[1] = i.y;
+    _uint32view[2] = i.z;
+    _uint32view[3] = i.w;
+    return NativeFloat32x4._truncated(_list[0], _list[1], _list[2], _list[3]);
+  }
+
+  NativeFloat32x4.fromFloat64x2(Float64x2 v)
+      : this._truncated(_truncate(v.x), _truncate(v.y), 0.0, 0.0);
+
+  /// Creates a new NativeFloat32x4.
+  ///
+  /// Does not verify if the given arguments are non-null.
+  NativeFloat32x4._doubles(double x, double y, double z, double w)
+      : this.x = _truncate(x),
+        this.y = _truncate(y),
+        this.z = _truncate(z),
+        this.w = _truncate(w);
+
+  /// Creates a new NativeFloat32x4.
+  ///
+  /// The constructor does not truncate the arguments. They must already be in
+  /// the correct range. It does not verify the type of the given arguments,
+  /// either.
+  NativeFloat32x4._truncated(this.x, this.y, this.z, this.w);
+
+  String toString() {
+    return '[$x, $y, $z, $w]';
+  }
+
+  /// Addition operator.
+  Float32x4 operator +(Float32x4 other) {
+    double _x = x + other.x;
+    double _y = y + other.y;
+    double _z = z + other.z;
+    double _w = w + other.w;
+    return NativeFloat32x4._doubles(_x, _y, _z, _w);
+  }
+
+  /// Negate operator.
+  Float32x4 operator -() {
+    return NativeFloat32x4._truncated(-x, -y, -z, -w);
+  }
+
+  /// Subtraction operator.
+  Float32x4 operator -(Float32x4 other) {
+    double _x = x - other.x;
+    double _y = y - other.y;
+    double _z = z - other.z;
+    double _w = w - other.w;
+    return NativeFloat32x4._doubles(_x, _y, _z, _w);
+  }
+
+  /// Multiplication operator.
+  Float32x4 operator *(Float32x4 other) {
+    double _x = x * other.x;
+    double _y = y * other.y;
+    double _z = z * other.z;
+    double _w = w * other.w;
+    return NativeFloat32x4._doubles(_x, _y, _z, _w);
+  }
+
+  /// Division operator.
+  Float32x4 operator /(Float32x4 other) {
+    double _x = x / other.x;
+    double _y = y / other.y;
+    double _z = z / other.z;
+    double _w = w / other.w;
+    return NativeFloat32x4._doubles(_x, _y, _z, _w);
+  }
+
+  /// Relational less than.
+  Int32x4 lessThan(Float32x4 other) {
+    bool _cx = x < other.x;
+    bool _cy = y < other.y;
+    bool _cz = z < other.z;
+    bool _cw = w < other.w;
+    return NativeInt32x4._truncated(
+        _cx ? -1 : 0, _cy ? -1 : 0, _cz ? -1 : 0, _cw ? -1 : 0);
+  }
+
+  /// Relational less than or equal.
+  Int32x4 lessThanOrEqual(Float32x4 other) {
+    bool _cx = x <= other.x;
+    bool _cy = y <= other.y;
+    bool _cz = z <= other.z;
+    bool _cw = w <= other.w;
+    return NativeInt32x4._truncated(
+        _cx ? -1 : 0, _cy ? -1 : 0, _cz ? -1 : 0, _cw ? -1 : 0);
+  }
+
+  /// Relational greater than.
+  Int32x4 greaterThan(Float32x4 other) {
+    bool _cx = x > other.x;
+    bool _cy = y > other.y;
+    bool _cz = z > other.z;
+    bool _cw = w > other.w;
+    return NativeInt32x4._truncated(
+        _cx ? -1 : 0, _cy ? -1 : 0, _cz ? -1 : 0, _cw ? -1 : 0);
+  }
+
+  /// Relational greater than or equal.
+  Int32x4 greaterThanOrEqual(Float32x4 other) {
+    bool _cx = x >= other.x;
+    bool _cy = y >= other.y;
+    bool _cz = z >= other.z;
+    bool _cw = w >= other.w;
+    return NativeInt32x4._truncated(
+        _cx ? -1 : 0, _cy ? -1 : 0, _cz ? -1 : 0, _cw ? -1 : 0);
+  }
+
+  /// Relational equal.
+  Int32x4 equal(Float32x4 other) {
+    bool _cx = x == other.x;
+    bool _cy = y == other.y;
+    bool _cz = z == other.z;
+    bool _cw = w == other.w;
+    return NativeInt32x4._truncated(
+        _cx ? -1 : 0, _cy ? -1 : 0, _cz ? -1 : 0, _cw ? -1 : 0);
+  }
+
+  /// Relational not-equal.
+  Int32x4 notEqual(Float32x4 other) {
+    bool _cx = x != other.x;
+    bool _cy = y != other.y;
+    bool _cz = z != other.z;
+    bool _cw = w != other.w;
+    return NativeInt32x4._truncated(
+        _cx ? -1 : 0, _cy ? -1 : 0, _cz ? -1 : 0, _cw ? -1 : 0);
+  }
+
+  /// Returns a copy of [this] each lane being scaled by [s].
+  Float32x4 scale(double s) {
+    double _x = s * x;
+    double _y = s * y;
+    double _z = s * z;
+    double _w = s * w;
+    return NativeFloat32x4._doubles(_x, _y, _z, _w);
+  }
+
+  /// Returns the absolute value of this [Float32x4].
+  Float32x4 abs() {
+    double _x = x.abs();
+    double _y = y.abs();
+    double _z = z.abs();
+    double _w = w.abs();
+    return NativeFloat32x4._truncated(_x, _y, _z, _w);
+  }
+
+  /// Clamps [this] to be in the range [lowerLimit]-[upperLimit].
+  Float32x4 clamp(Float32x4 lowerLimit, Float32x4 upperLimit) {
+    double _lx = lowerLimit.x;
+    double _ly = lowerLimit.y;
+    double _lz = lowerLimit.z;
+    double _lw = lowerLimit.w;
+    double _ux = upperLimit.x;
+    double _uy = upperLimit.y;
+    double _uz = upperLimit.z;
+    double _uw = upperLimit.w;
+    double _x = x;
+    double _y = y;
+    double _z = z;
+    double _w = w;
+    // MAX(MIN(self, upper), lower).
+    _x = _x > _ux ? _ux : _x;
+    _y = _y > _uy ? _uy : _y;
+    _z = _z > _uz ? _uz : _z;
+    _w = _w > _uw ? _uw : _w;
+    _x = _x < _lx ? _lx : _x;
+    _y = _y < _ly ? _ly : _y;
+    _z = _z < _lz ? _lz : _z;
+    _w = _w < _lw ? _lw : _w;
+    return NativeFloat32x4._truncated(_x, _y, _z, _w);
+  }
+
+  /// Extract the sign bit from each lane return them in the first 4 bits.
+  int get signMask {
+    var view = _uint32view;
+    var mx, my, mz, mw;
+    _list[0] = x;
+    _list[1] = y;
+    _list[2] = z;
+    _list[3] = w;
+    // This is correct because dart2js uses the unsigned right shift.
+    mx = (view[0] & 0x80000000) >> 31;
+    my = (view[1] & 0x80000000) >> 30;
+    mz = (view[2] & 0x80000000) >> 29;
+    mw = (view[3] & 0x80000000) >> 28;
+    return mx | my | mz | mw;
+  }
+
+  /// Shuffle the lane values. [mask] must be one of the 256 shuffle constants.
+  Float32x4 shuffle(int mask) {
+    if ((mask < 0) || (mask > 255)) {
+      throw RangeError.range(mask, 0, 255, "mask");
+    }
+    _list[0] = x;
+    _list[1] = y;
+    _list[2] = z;
+    _list[3] = w;
+
+    double _x = _list[mask & 0x3];
+    double _y = _list[(mask >> 2) & 0x3];
+    double _z = _list[(mask >> 4) & 0x3];
+    double _w = _list[(mask >> 6) & 0x3];
+    return NativeFloat32x4._truncated(_x, _y, _z, _w);
+  }
+
+  /// Shuffle the lane values in [this] and [other]. The returned
+  /// Float32x4 will have XY lanes from [this] and ZW lanes from [other].
+  /// Uses the same [mask] as [shuffle].
+  Float32x4 shuffleMix(Float32x4 other, int mask) {
+    if ((mask < 0) || (mask > 255)) {
+      throw RangeError.range(mask, 0, 255, "mask");
+    }
+    _list[0] = x;
+    _list[1] = y;
+    _list[2] = z;
+    _list[3] = w;
+    double _x = _list[mask & 0x3];
+    double _y = _list[(mask >> 2) & 0x3];
+
+    _list[0] = other.x;
+    _list[1] = other.y;
+    _list[2] = other.z;
+    _list[3] = other.w;
+    double _z = _list[(mask >> 4) & 0x3];
+    double _w = _list[(mask >> 6) & 0x3];
+    return NativeFloat32x4._truncated(_x, _y, _z, _w);
+  }
+
+  /// Copy [this] and replace the [x] lane.
+  Float32x4 withX(double newX) {
+    return NativeFloat32x4._truncated(_truncate(newX), y, z, w);
+  }
+
+  /// Copy [this] and replace the [y] lane.
+  Float32x4 withY(double newY) {
+    return NativeFloat32x4._truncated(x, _truncate(newY), z, w);
+  }
+
+  /// Copy [this] and replace the [z] lane.
+  Float32x4 withZ(double newZ) {
+    return NativeFloat32x4._truncated(x, y, _truncate(newZ), w);
+  }
+
+  /// Copy [this] and replace the [w] lane.
+  Float32x4 withW(double newW) {
+    return NativeFloat32x4._truncated(x, y, z, _truncate(newW));
+  }
+
+  /// Returns the lane-wise minimum value in [this] or [other].
+  Float32x4 min(Float32x4 other) {
+    double _x = x < other.x ? x : other.x;
+    double _y = y < other.y ? y : other.y;
+    double _z = z < other.z ? z : other.z;
+    double _w = w < other.w ? w : other.w;
+    return NativeFloat32x4._truncated(_x, _y, _z, _w);
+  }
+
+  /// Returns the lane-wise maximum value in [this] or [other].
+  Float32x4 max(Float32x4 other) {
+    double _x = x > other.x ? x : other.x;
+    double _y = y > other.y ? y : other.y;
+    double _z = z > other.z ? z : other.z;
+    double _w = w > other.w ? w : other.w;
+    return NativeFloat32x4._truncated(_x, _y, _z, _w);
+  }
+
+  /// Returns the square root of [this].
+  Float32x4 sqrt() {
+    double _x = Math.sqrt(x);
+    double _y = Math.sqrt(y);
+    double _z = Math.sqrt(z);
+    double _w = Math.sqrt(w);
+    return NativeFloat32x4._doubles(_x, _y, _z, _w);
+  }
+
+  /// Returns the reciprocal of [this].
+  Float32x4 reciprocal() {
+    double _x = 1.0 / x;
+    double _y = 1.0 / y;
+    double _z = 1.0 / z;
+    double _w = 1.0 / w;
+    return NativeFloat32x4._doubles(_x, _y, _z, _w);
+  }
+
+  /// Returns the square root of the reciprocal of [this].
+  Float32x4 reciprocalSqrt() {
+    double _x = Math.sqrt(1.0 / x);
+    double _y = Math.sqrt(1.0 / y);
+    double _z = Math.sqrt(1.0 / z);
+    double _w = Math.sqrt(1.0 / w);
+    return NativeFloat32x4._doubles(_x, _y, _z, _w);
+  }
+}
+
+/**
+ * Interface of Dart Int32x4 and operations.
+ * Int32x4 stores 4 32-bit bit-masks in "lanes".
+ * The lanes are "x", "y", "z", and "w" respectively.
+ */
+class NativeInt32x4 implements Int32x4 {
+  final int x;
+  final int y;
+  final int z;
+  final int w;
+
+  static final _list = NativeInt32List(4);
+
+  static _truncate(x) {
+    _list[0] = x;
+    return _list[0];
+  }
+
+  NativeInt32x4(int x, int y, int z, int w)
+      : this.x = _truncate(x),
+        this.y = _truncate(y),
+        this.z = _truncate(z),
+        this.w = _truncate(w) {
+    if (x != this.x && x is! int) throw ArgumentError(x);
+    if (y != this.y && y is! int) throw ArgumentError(y);
+    if (z != this.z && z is! int) throw ArgumentError(z);
+    if (w != this.w && w is! int) throw ArgumentError(w);
+  }
+
+  NativeInt32x4.bool(bool x, bool y, bool z, bool w)
+      : this.x = x ? -1 : 0,
+        this.y = y ? -1 : 0,
+        this.z = z ? -1 : 0,
+        this.w = w ? -1 : 0;
+
+  /// Returns a bit-wise copy of [f] as a Int32x4.
+  factory NativeInt32x4.fromFloat32x4Bits(Float32x4 f) {
+    NativeFloat32List floatList = NativeFloat32x4._list;
+    floatList[0] = f.x;
+    floatList[1] = f.y;
+    floatList[2] = f.z;
+    floatList[3] = f.w;
+    NativeInt32List view = floatList.buffer.asInt32List();
+    return NativeInt32x4._truncated(view[0], view[1], view[2], view[3]);
+  }
+
+  NativeInt32x4._truncated(this.x, this.y, this.z, this.w);
+
+  String toString() => '[$x, $y, $z, $w]';
+
+  /// The bit-wise or operator.
+  Int32x4 operator |(Int32x4 other) {
+    // Dart2js uses unsigned results for bit-operations.
+    // We use "JS" to fall back to the signed versions.
+    return NativeInt32x4._truncated(
+        JS("int", "# | #", x, other.x),
+        JS("int", "# | #", y, other.y),
+        JS("int", "# | #", z, other.z),
+        JS("int", "# | #", w, other.w));
+  }
+
+  /// The bit-wise and operator.
+  Int32x4 operator &(Int32x4 other) {
+    // Dart2js uses unsigned results for bit-operations.
+    // We use "JS" to fall back to the signed versions.
+    return NativeInt32x4._truncated(
+        JS("int", "# & #", x, other.x),
+        JS("int", "# & #", y, other.y),
+        JS("int", "# & #", z, other.z),
+        JS("int", "# & #", w, other.w));
+  }
+
+  /// The bit-wise xor operator.
+  Int32x4 operator ^(Int32x4 other) {
+    // Dart2js uses unsigned results for bit-operations.
+    // We use "JS" to fall back to the signed versions.
+    return NativeInt32x4._truncated(
+        JS("int", "# ^ #", x, other.x),
+        JS("int", "# ^ #", y, other.y),
+        JS("int", "# ^ #", z, other.z),
+        JS("int", "# ^ #", w, other.w));
+  }
+
+  Int32x4 operator +(Int32x4 other) {
+    // Avoid going through the typed array by "| 0" the result.
+    return NativeInt32x4._truncated(
+        JS("int", "(# + #) | 0", x, other.x),
+        JS("int", "(# + #) | 0", y, other.y),
+        JS("int", "(# + #) | 0", z, other.z),
+        JS("int", "(# + #) | 0", w, other.w));
+  }
+
+  Int32x4 operator -(Int32x4 other) {
+    // Avoid going through the typed array by "| 0" the result.
+    return NativeInt32x4._truncated(
+        JS("int", "(# - #) | 0", x, other.x),
+        JS("int", "(# - #) | 0", y, other.y),
+        JS("int", "(# - #) | 0", z, other.z),
+        JS("int", "(# - #) | 0", w, other.w));
+  }
+
+  Int32x4 operator -() {
+    // Avoid going through the typed array by "| 0" the result.
+    return NativeInt32x4._truncated(
+        JS("int", "(-#) | 0", x),
+        JS("int", "(-#) | 0", y),
+        JS("int", "(-#) | 0", z),
+        JS("int", "(-#) | 0", w));
+  }
+
+  /// Extract the top bit from each lane return them in the first 4 bits.
+  int get signMask {
+    int mx = (x & 0x80000000) >> 31;
+    int my = (y & 0x80000000) >> 31;
+    int mz = (z & 0x80000000) >> 31;
+    int mw = (w & 0x80000000) >> 31;
+    return mx | my << 1 | mz << 2 | mw << 3;
+  }
+
+  /// Shuffle the lane values. [mask] must be one of the 256 shuffle constants.
+  Int32x4 shuffle(int mask) {
+    if ((mask < 0) || (mask > 255)) {
+      throw RangeError.range(mask, 0, 255, "mask");
+    }
+    _list[0] = x;
+    _list[1] = y;
+    _list[2] = z;
+    _list[3] = w;
+    int _x = _list[mask & 0x3];
+    int _y = _list[(mask >> 2) & 0x3];
+    int _z = _list[(mask >> 4) & 0x3];
+    int _w = _list[(mask >> 6) & 0x3];
+    return NativeInt32x4._truncated(_x, _y, _z, _w);
+  }
+
+  /// Shuffle the lane values in [this] and [other]. The returned
+  /// Int32x4 will have XY lanes from [this] and ZW lanes from [other].
+  /// Uses the same [mask] as [shuffle].
+  Int32x4 shuffleMix(Int32x4 other, int mask) {
+    if ((mask < 0) || (mask > 255)) {
+      throw RangeError.range(mask, 0, 255, "mask");
+    }
+    _list[0] = x;
+    _list[1] = y;
+    _list[2] = z;
+    _list[3] = w;
+    int _x = _list[mask & 0x3];
+    int _y = _list[(mask >> 2) & 0x3];
+
+    _list[0] = other.x;
+    _list[1] = other.y;
+    _list[2] = other.z;
+    _list[3] = other.w;
+    int _z = _list[(mask >> 4) & 0x3];
+    int _w = _list[(mask >> 6) & 0x3];
+    return NativeInt32x4._truncated(_x, _y, _z, _w);
+  }
+
+  /// Returns a new [Int32x4] copied from [this] with a new x value.
+  Int32x4 withX(int x) {
+    int _x = _truncate(x);
+    return NativeInt32x4._truncated(_x, y, z, w);
+  }
+
+  /// Returns a new [Int32x4] copied from [this] with a new y value.
+  Int32x4 withY(int y) {
+    int _y = _truncate(y);
+    return NativeInt32x4._truncated(x, _y, z, w);
+  }
+
+  /// Returns a new [Int32x4] copied from [this] with a new z value.
+  Int32x4 withZ(int z) {
+    int _z = _truncate(z);
+    return NativeInt32x4._truncated(x, y, _z, w);
+  }
+
+  /// Returns a new [Int32x4] copied from [this] with a new w value.
+  Int32x4 withW(int w) {
+    int _w = _truncate(w);
+    return NativeInt32x4._truncated(x, y, z, _w);
+  }
+
+  /// Extracted x value. Returns `false` for 0, `true` for any other value.
+  bool get flagX => x != 0;
+
+  /// Extracted y value. Returns `false` for 0, `true` for any other value.
+  bool get flagY => y != 0;
+
+  /// Extracted z value. Returns `false` for 0, `true` for any other value.
+  bool get flagZ => z != 0;
+
+  /// Extracted w value. Returns `false` for 0, `true` for any other value.
+  bool get flagW => w != 0;
+
+  /// Returns a new [Int32x4] copied from [this] with a new x value.
+  Int32x4 withFlagX(bool flagX) {
+    int _x = flagX ? -1 : 0;
+    return NativeInt32x4._truncated(_x, y, z, w);
+  }
+
+  /// Returns a new [Int32x4] copied from [this] with a new y value.
+  Int32x4 withFlagY(bool flagY) {
+    int _y = flagY ? -1 : 0;
+    return NativeInt32x4._truncated(x, _y, z, w);
+  }
+
+  /// Returns a new [Int32x4] copied from [this] with a new z value.
+  Int32x4 withFlagZ(bool flagZ) {
+    int _z = flagZ ? -1 : 0;
+    return NativeInt32x4._truncated(x, y, _z, w);
+  }
+
+  /// Returns a new [Int32x4] copied from [this] with a new w value.
+  Int32x4 withFlagW(bool flagW) {
+    int _w = flagW ? -1 : 0;
+    return NativeInt32x4._truncated(x, y, z, _w);
+  }
+
+  /// Merge [trueValue] and [falseValue] based on [this]' bit mask:
+  /// Select bit from [trueValue] when bit in [this] is on.
+  /// Select bit from [falseValue] when bit in [this] is off.
+  Float32x4 select(Float32x4 trueValue, Float32x4 falseValue) {
+    var floatList = NativeFloat32x4._list;
+    var intView = NativeFloat32x4._uint32view;
+
+    floatList[0] = trueValue.x;
+    floatList[1] = trueValue.y;
+    floatList[2] = trueValue.z;
+    floatList[3] = trueValue.w;
+    int stx = intView[0];
+    int sty = intView[1];
+    int stz = intView[2];
+    int stw = intView[3];
+
+    floatList[0] = falseValue.x;
+    floatList[1] = falseValue.y;
+    floatList[2] = falseValue.z;
+    floatList[3] = falseValue.w;
+    int sfx = intView[0];
+    int sfy = intView[1];
+    int sfz = intView[2];
+    int sfw = intView[3];
+    int _x = (x & stx) | (~x & sfx);
+    int _y = (y & sty) | (~y & sfy);
+    int _z = (z & stz) | (~z & sfz);
+    int _w = (w & stw) | (~w & sfw);
+    intView[0] = _x;
+    intView[1] = _y;
+    intView[2] = _z;
+    intView[3] = _w;
+    return NativeFloat32x4._truncated(
+        floatList[0], floatList[1], floatList[2], floatList[3]);
+  }
+}
+
+class NativeFloat64x2 implements Float64x2 {
+  final double x;
+  final double y;
+
+  static NativeFloat64List _list = NativeFloat64List(2);
+  static NativeUint32List _uint32View = _list.buffer.asUint32List();
+
+  NativeFloat64x2(this.x, this.y) {
+    if (x is! num) throw ArgumentError(x);
+    if (y is! num) throw ArgumentError(y);
+  }
+
+  NativeFloat64x2.splat(double v) : this(v, v);
+
+  NativeFloat64x2.zero() : this.splat(0.0);
+
+  NativeFloat64x2.fromFloat32x4(Float32x4 v) : this(v.x, v.y);
+
+  /// Arguments [x] and [y] must be doubles.
+  NativeFloat64x2._doubles(this.x, this.y);
+
+  String toString() => '[$x, $y]';
+
+  /// Addition operator.
+  Float64x2 operator +(Float64x2 other) {
+    return NativeFloat64x2._doubles(x + other.x, y + other.y);
+  }
+
+  /// Negate operator.
+  Float64x2 operator -() {
+    return NativeFloat64x2._doubles(-x, -y);
+  }
+
+  /// Subtraction operator.
+  Float64x2 operator -(Float64x2 other) {
+    return NativeFloat64x2._doubles(x - other.x, y - other.y);
+  }
+
+  /// Multiplication operator.
+  Float64x2 operator *(Float64x2 other) {
+    return NativeFloat64x2._doubles(x * other.x, y * other.y);
+  }
+
+  /// Division operator.
+  Float64x2 operator /(Float64x2 other) {
+    return NativeFloat64x2._doubles(x / other.x, y / other.y);
+  }
+
+  /// Returns a copy of [this] each lane being scaled by [s].
+  Float64x2 scale(double s) {
+    return NativeFloat64x2._doubles(x * s, y * s);
+  }
+
+  /// Returns the absolute value of this [Float64x2].
+  Float64x2 abs() {
+    return NativeFloat64x2._doubles(x.abs(), y.abs());
+  }
+
+  /// Clamps [this] to be in the range [lowerLimit]-[upperLimit].
+  Float64x2 clamp(Float64x2 lowerLimit, Float64x2 upperLimit) {
+    double _lx = lowerLimit.x;
+    double _ly = lowerLimit.y;
+    double _ux = upperLimit.x;
+    double _uy = upperLimit.y;
+    double _x = x;
+    double _y = y;
+    // MAX(MIN(self, upper), lower).
+    _x = _x > _ux ? _ux : _x;
+    _y = _y > _uy ? _uy : _y;
+    _x = _x < _lx ? _lx : _x;
+    _y = _y < _ly ? _ly : _y;
+    return NativeFloat64x2._doubles(_x, _y);
+  }
+
+  /// Extract the sign bits from each lane return them in the first 2 bits.
+  int get signMask {
+    var view = _uint32View;
+    _list[0] = x;
+    _list[1] = y;
+    var mx = (view[1] & 0x80000000) >> 31;
+    var my = (view[3] & 0x80000000) >> 31;
+    return mx | my << 1;
+  }
+
+  /// Returns a new [Float64x2] copied from [this] with a new x value.
+  Float64x2 withX(double x) {
+    if (x is! num) throw ArgumentError(x);
+    return NativeFloat64x2._doubles(x, y);
+  }
+
+  /// Returns a new [Float64x2] copied from [this] with a new y value.
+  Float64x2 withY(double y) {
+    if (y is! num) throw ArgumentError(y);
+    return NativeFloat64x2._doubles(x, y);
+  }
+
+  /// Returns the lane-wise minimum value in [this] or [other].
+  Float64x2 min(Float64x2 other) {
+    return NativeFloat64x2._doubles(
+        x < other.x ? x : other.x, y < other.y ? y : other.y);
+  }
+
+  /// Returns the lane-wise maximum value in [this] or [other].
+  Float64x2 max(Float64x2 other) {
+    return NativeFloat64x2._doubles(
+        x > other.x ? x : other.x, y > other.y ? y : other.y);
+  }
+
+  /// Returns the lane-wise square root of [this].
+  Float64x2 sqrt() {
+    return NativeFloat64x2._doubles(Math.sqrt(x), Math.sqrt(y));
+  }
+}
+
+/// Checks that the value is a Uint32. If not, it's not valid as an array
+/// index or offset. Also ensures that the value is non-negative.
+bool _isInvalidArrayIndex(int index) {
+  return (JS<bool>('!', '(# >>> 0 !== #)', index, index));
+}
+
+/// Checks that [index] is a valid index into [list] which has length [length].
+///
+/// That is, [index] is an integer in the range `0..length - 1`.
+void _checkValidIndex(int index, List list, int length) {
+  if (_isInvalidArrayIndex(index) || JS<int>('!', '#', index) >= length) {
+    throw diagnoseIndexError(list, index);
+  }
+}
+
+/// Checks that [start] and [end] form a range of a list of length [length].
+///
+/// That is: `start` and `end` are integers with `0 <= start <= end <= length`.
+/// If `end` is `null` in which case it is considered to be `length`
+///
+/// Returns the actual value of `end`, which is `length` if `end` is `null`, and
+/// the original value of `end` otherwise.
+int _checkValidRange(int start, int end, int length) {
+  if (_isInvalidArrayIndex(start) || // Ensures start is non-negative int.
+      ((end == null)
+          ? start > length
+          : (_isInvalidArrayIndex(end) || start > end || end > length))) {
+    throw diagnoseRangeError(start, end, length);
+  }
+  if (end == null) return length;
+  return end;
+}
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/private/preambles/README b/sdk_nnbd/lib/_internal/js_dev_runtime/private/preambles/README
new file mode 100644
index 0000000..7eb614e
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/private/preambles/README
@@ -0,0 +1,17 @@
+The files in this directory polyfill some of the functionality that browsers
+provide. When running command-line JS evaluators it is frequently necessary to
+execute the preambles before executing the output of dart2js.
+
+=Usage=
+- d8:
+    d8 <sdk>/lib/_internal/compiler/js_lib/preambles/d8.js <output>.js
+
+- jsshell:
+    jsshell -f <sdk>/lib/_internal/compiler/js_lib/preambles/d8.js -f <output>.js
+
+- node.js:
+  The d8 preamble file works for most programs.
+
+  Unfortunately we are not aware of any easy way to provide multiple input files
+  to node. It seems to be necessary to concatenate the d8 preamble and the
+  dart2js output.
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/private/preambles/d8.js b/sdk_nnbd/lib/_internal/js_dev_runtime/private/preambles/d8.js
new file mode 100644
index 0000000..0c432f5
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/private/preambles/d8.js
@@ -0,0 +1,291 @@
+// Copyright (c) 2014, 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.
+
+// Javascript preamble, that lets the output of dart2js run on V8's d8 shell.
+
+// Node wraps files and provides them with a different `this`. The global
+// `this` can be accessed through `global`.
+
+var self = this;
+if (typeof global != "undefined") self = global;  // Node.js.
+
+(function(self) {
+  // Using strict mode to avoid accidentally defining global variables.
+  "use strict"; // Should be first statement of this function.
+
+  // Location (Uri.base)
+
+  var workingDirectory;
+  // TODO(sgjesse): This does not work on Windows.
+  if (typeof os == "object" && "system" in os) {
+    // V8.
+    workingDirectory = os.system("pwd");
+    var length = workingDirectory.length;
+    if (workingDirectory[length - 1] == '\n') {
+      workingDirectory = workingDirectory.substring(0, length - 1);
+    }
+  } else if (typeof process != "undefined" &&
+             typeof process.cwd == "function") {
+    // Node.js.
+    workingDirectory = process.cwd();
+  }
+  self.location = { href: "file://" + workingDirectory + "/" };
+
+  // Event loop.
+  // Task queue as cyclic list queue.
+  var taskQueue = new Array(8);  // Length is power of 2.
+  var head = 0;
+  var tail = 0;
+  var mask = taskQueue.length - 1;
+  function addTask(elem) {
+    taskQueue[head] = elem;
+    head = (head + 1) & mask;
+    if (head == tail) _growTaskQueue();
+  }
+  function removeTask() {
+    if (head == tail) return;
+    var result = taskQueue[tail];
+    taskQueue[tail] = undefined;
+    tail = (tail + 1) & mask;
+    return result;
+  }
+  function _growTaskQueue() {
+    // head == tail.
+    var length = taskQueue.length;
+    var split = head;
+    taskQueue.length = length * 2;
+    if (split * 2 < length) {  // split < length / 2
+      for (var i = 0; i < split; i++) {
+        taskQueue[length + i] = taskQueue[i];
+        taskQueue[i] = undefined;
+      }
+      head += length;
+    } else {
+      for (var i = split; i < length; i++) {
+        taskQueue[length + i] = taskQueue[i];
+        taskQueue[i] = undefined;
+      }
+      tail += length;
+    }
+    mask = taskQueue.length - 1;
+  }
+
+  // Mapping from timer id to timer function.
+  // The timer id is written on the function as .$timerId.
+  // That field is cleared when the timer is cancelled, but it is not returned
+  // from the queue until its time comes.
+  var timerIds = {};
+  var timerIdCounter = 1;  // Counter used to assign ids.
+
+  // Zero-timer queue as simple array queue using push/shift.
+  var zeroTimerQueue = [];
+
+  function addTimer(f, ms) {
+    var id = timerIdCounter++;
+    f.$timerId = id;
+    timerIds[id] = f;
+    if (ms == 0 && !isNextTimerDue()) {
+      zeroTimerQueue.push(f);
+    } else {
+      addDelayedTimer(f, ms);
+    }
+    return id;
+  }
+
+  function nextZeroTimer() {
+    while (zeroTimerQueue.length > 0) {
+      var action = zeroTimerQueue.shift();
+      if (action.$timerId !== undefined) return action;
+    }
+  }
+
+  function nextEvent() {
+    var action = removeTask();
+    if (action) {
+      return action;
+    }
+    do {
+      action = nextZeroTimer();
+      if (action) break;
+      var nextList = nextDelayedTimerQueue();
+      if (!nextList) {
+        return;
+      }
+      var newTime = nextList.shift();
+      advanceTimeTo(newTime);
+      zeroTimerQueue = nextList;
+    } while (true)
+    var id = action.$timerId;
+    clearTimerId(action, id);
+    return action;
+  }
+
+  // Mocking time.
+  var timeOffset = 0;
+  var now = function() {
+    // Install the mock Date object only once.
+    // Following calls to "now" will just use the new (mocked) Date.now
+    // method directly.
+    installMockDate();
+    now = Date.now;
+    return Date.now();
+  };
+  var originalDate = Date;
+  var originalNow = originalDate.now;
+  function advanceTimeTo(time) {
+    var now = originalNow();
+    if (timeOffset < time - now) {
+      timeOffset = time - now;
+    }
+  }
+  function installMockDate() {
+    var NewDate = function Date(Y, M, D, h, m, s, ms) {
+      if (this instanceof Date) {
+        // Assume a construct call.
+        switch (arguments.length) {
+          case 0:  return new originalDate(originalNow() + timeOffset);
+          case 1:  return new originalDate(Y);
+          case 2:  return new originalDate(Y, M);
+          case 3:  return new originalDate(Y, M, D);
+          case 4:  return new originalDate(Y, M, D, h);
+          case 5:  return new originalDate(Y, M, D, h, m);
+          case 6:  return new originalDate(Y, M, D, h, m, s);
+          default: return new originalDate(Y, M, D, h, m, s, ms);
+        }
+      }
+      return new originalDate(originalNow() + timeOffset).toString();
+    };
+    NewDate.UTC = originalDate.UTC;
+    NewDate.parse = originalDate.parse;
+    NewDate.now = function now() { return originalNow() + timeOffset; };
+    NewDate.prototype = originalDate.prototype;
+    originalDate.prototype.constructor = NewDate;
+    Date = NewDate;
+  }
+
+  // Heap priority queue with key index.
+  // Each entry is list of [timeout, callback1 ... callbackn].
+  var timerHeap = [];
+  var timerIndex = {};
+  function addDelayedTimer(f, ms) {
+    var timeout = now() + ms;
+    var timerList = timerIndex[timeout];
+    if (timerList == null) {
+      timerList = [timeout, f];
+      timerIndex[timeout] = timerList;
+      var index = timerHeap.length;
+      timerHeap.length += 1;
+      bubbleUp(index, timeout, timerList);
+    } else {
+      timerList.push(f);
+    }
+  }
+
+  function isNextTimerDue() {
+    if (timerHeap.length == 0) return false;
+    var head = timerHeap[0];
+    return head[0] < originalNow() + timeOffset;
+  }
+
+  function nextDelayedTimerQueue() {
+    if (timerHeap.length == 0) return null;
+    var result = timerHeap[0];
+    var last = timerHeap.pop();
+    if (timerHeap.length > 0) {
+      bubbleDown(0, last[0], last);
+    }
+    return result;
+  }
+
+  function bubbleUp(index, key, value) {
+    while (index != 0) {
+      var parentIndex = (index - 1) >> 1;
+      var parent = timerHeap[parentIndex];
+      var parentKey = parent[0];
+      if (key > parentKey) break;
+      timerHeap[index] = parent;
+      index = parentIndex;
+    }
+    timerHeap[index] = value;
+  }
+
+  function bubbleDown(index, key, value) {
+    while (true) {
+      var leftChildIndex = index * 2 + 1;
+      if (leftChildIndex >= timerHeap.length) break;
+      var minChildIndex = leftChildIndex;
+      var minChild = timerHeap[leftChildIndex];
+      var minChildKey = minChild[0];
+      var rightChildIndex = leftChildIndex + 1;
+      if (rightChildIndex < timerHeap.length) {
+        var rightChild = timerHeap[rightChildIndex];
+        var rightKey = rightChild[0];
+        if (rightKey < minChildKey) {
+          minChildIndex = rightChildIndex;
+          minChild = rightChild;
+          minChildKey = rightKey;
+        }
+      }
+      if (minChildKey > key) break;
+      timerHeap[index] = minChild;
+      index = minChildIndex;
+    }
+    timerHeap[index] = value;
+  }
+
+  function addInterval(f, ms) {
+    var id = timerIdCounter++;
+    function repeat() {
+      // Reactivate with the same id.
+      repeat.$timerId = id;
+      timerIds[id] = repeat;
+      addDelayedTimer(repeat, ms);
+      f();
+    }
+    repeat.$timerId = id;
+    timerIds[id] = repeat;
+    addDelayedTimer(repeat, ms);
+    return id;
+  }
+
+  function cancelTimer(id) {
+    var f = timerIds[id];
+    if (f == null) return;
+    clearTimerId(f, id);
+  }
+
+  function clearTimerId(f, id) {
+    f.$timerId = undefined;
+    delete timerIds[id];
+  }
+
+  function eventLoop(action) {
+    while (action) {
+      try {
+        action();
+      } catch (e) {
+        if (typeof onerror == "function") {
+          onerror(e, null, -1);
+        } else {
+          throw e;
+        }
+      }
+      action = nextEvent();
+    }
+  }
+
+  // Global properties. "self" refers to the global object, so adding a
+  // property to "self" defines a global variable.
+  self.dartMainRunner = function(main, args) {
+    // Initialize.
+    var action = function() { main(args); }
+    eventLoop(action);
+  };
+  self.setTimeout = addTimer;
+  self.clearTimeout = cancelTimer;
+  self.setInterval = addInterval;
+  self.clearInterval = cancelTimer;
+  self.scheduleImmediate = addTask;
+  self.self = self;
+})(self);
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/private/preambles/jsshell.js b/sdk_nnbd/lib/_internal/js_dev_runtime/private/preambles/jsshell.js
new file mode 100644
index 0000000..8f13bcc
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/private/preambles/jsshell.js
@@ -0,0 +1,19 @@
+// Copyright (c) 2014, 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.
+
+// Javascript preamble, that lets the output of dart2js run on JSShell.
+
+(function(self) {
+  // Using strict mode to avoid accidentally defining global variables.
+  "use strict"; // Should be first statement of this function.
+
+  // Location (Uri.base)
+
+  var workingDirectory = environment["PWD"];
+  self.location = { href: "file://" + workingDirectory + "/" };
+
+  // Global properties. "self" refers to the global object, so adding a
+  // property to "self" defines a global variable.
+  self.self = self;
+})(this)
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/private/profile.dart b/sdk_nnbd/lib/_internal/js_dev_runtime/private/profile.dart
new file mode 100644
index 0000000..d46f7f7
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/private/profile.dart
@@ -0,0 +1,135 @@
+// 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.
+
+/// This file supports profiling dynamic calls.
+part of dart._debugger;
+
+class _MethodStats {
+  final String typeName;
+  final String frame;
+  double count;
+
+  _MethodStats(this.typeName, this.frame) {
+    count = 0.0;
+  }
+}
+
+class _CallMethodRecord {
+  var jsError;
+  var type;
+
+  _CallMethodRecord(this.jsError, this.type);
+}
+
+/// Size for the random sample of dynamic calls.
+int _callRecordSampleSize = 5000;
+
+/// If the number of dynamic calls exceeds [_callRecordSampleSize] this list
+/// will represent a random sample of the dynamic calls made.
+List<_CallMethodRecord> _callMethodRecords = List();
+
+/// If the number of dynamic calls exceeds [_callRecordSampleSize] this value
+/// will be greater than [_callMethodRecords.length].
+int _totalCallRecords = 0;
+
+/// Minimum number of samples to consider a profile entry relevant.
+/// This could be set a lot higher. We set this value so users are not
+/// confused into thinking that a dynamic call that occurred once but was
+/// randomly included in the sample is relevant.
+num _minCount = 2;
+
+/// Cache mapping from raw stack frames to source mapped stack frames to
+/// speedup lookup of source map frames when running the profiler.
+/// The number of source map entries looked up makes caching more important
+/// in this case than for typical source map use cases.
+Map<String, String> _frameMappingCache = Map();
+
+List<List<Object>> getDynamicStats() {
+  // Process the accumulated method stats. This may be quite slow as processing
+  // stack traces is expensive. If there are performance blockers, we should
+  // switch to a sampling approach that caps the number of _callMethodRecords
+  // and uses random sampling to decide whether to add each additional record
+  // to the sample. Main change required is that we need to still show the total
+  // raw number of dynamic calls so that the magnitude of the dynamic call
+  // performance hit is clear to users.
+
+  Map<String, _MethodStats> callMethodStats = Map();
+  if (_callMethodRecords.length > 0) {
+    // Ratio between total record count and sampled records count.
+    var recordRatio = _totalCallRecords / _callMethodRecords.length;
+    for (var record in _callMethodRecords) {
+      String stackStr = JS<String>('!', '#.stack', record.jsError);
+      var frames = stackStr.split('\n');
+      // Skip first two lines as the first couple frames are from the dart
+      // runtime.
+      var src = frames
+          .skip(2)
+          .map((f) =>
+              _frameMappingCache.putIfAbsent(f, () => stackTraceMapper('\n$f')))
+          .firstWhere((f) => !f.startsWith('dart:'), orElse: () => '');
+
+      var actualTypeName = dart.typeName(record.type);
+      callMethodStats
+          .putIfAbsent(
+              "$actualTypeName <$src>", () => _MethodStats(actualTypeName, src))
+          .count += recordRatio;
+    }
+
+    // filter out all calls that did not occur at least _minCount times in the
+    // random sample if we are dealing with a random sample instead of a
+    // complete profile.
+    if (_totalCallRecords != _callMethodRecords.length) {
+      for (var k in callMethodStats.keys.toList()) {
+        var stats = callMethodStats[k];
+        var threshold = _minCount * recordRatio;
+        if (stats.count + 0.001 < threshold) {
+          callMethodStats.remove(k);
+        }
+      }
+    }
+  }
+  _callMethodRecords.clear();
+  _totalCallRecords = 0;
+  var keys = callMethodStats.keys.toList();
+
+  keys.sort(
+      (a, b) => callMethodStats[b].count.compareTo(callMethodStats[a].count));
+  List<List<Object>> ret = [];
+  for (var key in keys) {
+    var stats = callMethodStats[key];
+    ret.add([stats.typeName, stats.frame, stats.count.round()]);
+  }
+  return ret;
+}
+
+clearDynamicStats() {
+  _callMethodRecords.clear();
+}
+
+// We need to set this property while the sdk is only partially initialized
+// so we cannot use a regular Dart field.
+bool get _trackProfile => JS<bool>('!', 'dart.__trackProfile');
+
+trackCall(obj) {
+  if (JS<bool>('!', '!#', _trackProfile)) return;
+  int index = -1;
+  _totalCallRecords++;
+  if (_callMethodRecords.length == _callRecordSampleSize) {
+    // Ensure that each sample has an equal
+    // _callRecordSampleSize / _totalCallRecords chance of inclusion
+    // by choosing to include the new record in the sample the with the
+    // appropriate probability randomly evicting one of the existing records.
+    // Unfortunately we can't use the excellent Random.nextInt method defined
+    // by Dart from within this library.
+    index = JS<int>('!', 'Math.floor(Math.random() * #)', _totalCallRecords);
+    if (index >= _callMethodRecords.length) return; // don't sample
+  }
+  var record =
+      _CallMethodRecord(JS('', 'new Error()'), dart.getReifiedType(obj));
+  if (index == -1) {
+    _callMethodRecords.add(record);
+  } else {
+    _callMethodRecords[index] = record;
+  }
+}
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/private/regexp_helper.dart b/sdk_nnbd/lib/_internal/js_dev_runtime/private/regexp_helper.dart
new file mode 100644
index 0000000..fadcda0
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/private/regexp_helper.dart
@@ -0,0 +1,283 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart._js_helper;
+
+// Helper method used by internal libraries.
+regExpGetNative(JSSyntaxRegExp regexp) => regexp._nativeRegExp;
+
+/**
+ * Returns a native version of the RegExp with the global flag set.
+ *
+ * The RegExp's `lastIndex` property is zero when it is returned.
+ *
+ * The returned regexp is shared, and its `lastIndex` property may be
+ * modified by other uses, so the returned regexp must be used immediately
+ * when it's returned, with no user-provided code run in between.
+ */
+regExpGetGlobalNative(JSSyntaxRegExp regexp) {
+  var nativeRegexp = regexp._nativeGlobalVersion;
+  JS("void", "#.lastIndex = 0", nativeRegexp);
+  return nativeRegexp;
+}
+
+/**
+ * Computes the number of captures in a regexp.
+ *
+ * This currently involves creating a new RegExp object with a different
+ * source and running it against the empty string (the last part is usually
+ * fast).
+ *
+ * The JSSyntaxRegExp could cache the result, and set the cache any time
+ * it finds a match.
+ */
+int regExpCaptureCount(JSSyntaxRegExp regexp) {
+  var nativeAnchoredRegExp = regexp._nativeAnchoredVersion;
+  JSExtendableArray match =
+      JS('JSExtendableArray', "#.exec('')", nativeAnchoredRegExp);
+  // The native-anchored regexp always have one capture more than the original,
+  // and always matches the empty string.
+  return match.length - 2;
+}
+
+class JSSyntaxRegExp implements RegExp {
+  final String pattern;
+  final _nativeRegExp;
+  var _nativeGlobalRegExp;
+  var _nativeAnchoredRegExp;
+
+  String toString() =>
+      'RegExp/$pattern/' + JS<String>('!', '#.flags', _nativeRegExp);
+
+  JSSyntaxRegExp(String source,
+      {bool multiLine = false,
+      bool caseSensitive = true,
+      bool unicode = false,
+      bool dotAll = false})
+      : this.pattern = source,
+        this._nativeRegExp = makeNative(
+            source, multiLine, caseSensitive, unicode, dotAll, false);
+
+  get _nativeGlobalVersion {
+    if (_nativeGlobalRegExp != null) return _nativeGlobalRegExp;
+    return _nativeGlobalRegExp = makeNative(
+        pattern, _isMultiLine, _isCaseSensitive, _isUnicode, _isDotAll, true);
+  }
+
+  get _nativeAnchoredVersion {
+    if (_nativeAnchoredRegExp != null) return _nativeAnchoredRegExp;
+    // An "anchored version" of a regexp is created by adding "|()" to the
+    // source. This means that the regexp always matches at the first position
+    // that it tries, and you can see if the original regexp matched, or it
+    // was the added zero-width match that matched, by looking at the last
+    // capture. If it is a String, the match participated, otherwise it didn't.
+    return _nativeAnchoredRegExp = makeNative("$pattern|()", _isMultiLine,
+        _isCaseSensitive, _isUnicode, _isDotAll, true);
+  }
+
+  bool get _isMultiLine => JS("bool", "#.multiline", _nativeRegExp);
+  bool get _isCaseSensitive => JS("bool", "!#.ignoreCase", _nativeRegExp);
+  bool get _isUnicode => JS("bool", "#.unicode", _nativeRegExp);
+  bool get _isDotAll => JS("bool", "#.dotAll", _nativeRegExp);
+
+  static makeNative(@nullCheck String source, bool multiLine,
+      bool caseSensitive, bool unicode, bool dotAll, bool global) {
+    String m = multiLine ? 'm' : '';
+    String i = caseSensitive ? '' : 'i';
+    String u = unicode ? 'u' : '';
+    String s = dotAll ? 's' : '';
+    String g = global ? 'g' : '';
+    // We're using the JavaScript's try catch instead of the Dart one
+    // to avoid dragging in Dart runtime support just because of using
+    // RegExp.
+    var regexp = JS(
+        '',
+        '(function() {'
+            'try {'
+            'return new RegExp(#, # + # + # + # + #);'
+            '} catch (e) {'
+            'return e;'
+            '}'
+            '})()',
+        source,
+        m,
+        i,
+        u,
+        s,
+        g);
+    if (JS<bool>('!', '# instanceof RegExp', regexp)) return regexp;
+    // The returned value is the JavaScript exception. Turn it into a
+    // Dart exception.
+    String errorMessage = JS<String>('!', r'String(#)', regexp);
+    throw FormatException("Illegal RegExp pattern: $source, $errorMessage");
+  }
+
+  RegExpMatch firstMatch(@nullCheck String string) {
+    List m = JS('JSExtendableArray|Null', r'#.exec(#)', _nativeRegExp, string);
+    if (m == null) return null;
+    return _MatchImplementation(this, JSArray<String>.of(m));
+  }
+
+  @notNull
+  bool hasMatch(@nullCheck String string) {
+    return JS<bool>('!', r'#.test(#)', _nativeRegExp, string);
+  }
+
+  String stringMatch(String string) {
+    var match = firstMatch(string);
+    if (match != null) return match.group(0);
+    return null;
+  }
+
+  Iterable<RegExpMatch> allMatches(@nullCheck String string,
+      [@nullCheck int start = 0]) {
+    if (start < 0 || start > string.length) {
+      throw RangeError.range(start, 0, string.length);
+    }
+    return _AllMatchesIterable(this, string, start);
+  }
+
+  RegExpMatch _execGlobal(String string, int start) {
+    Object regexp = _nativeGlobalVersion;
+    JS("void", "#.lastIndex = #", regexp, start);
+    List match = JS("JSExtendableArray|Null", "#.exec(#)", regexp, string);
+    if (match == null) return null;
+    return _MatchImplementation(this, JSArray<String>.of(match));
+  }
+
+  RegExpMatch _execAnchored(String string, int start) {
+    Object regexp = _nativeAnchoredVersion;
+    JS("void", "#.lastIndex = #", regexp, start);
+    List match = JS("JSExtendableArray|Null", "#.exec(#)", regexp, string);
+    if (match == null) return null;
+    // If the last capture group participated, the original regexp did not
+    // match at the start position.
+    if (match[match.length - 1] != null) return null;
+    match.length -= 1;
+    return _MatchImplementation(this, JSArray<String>.of(match));
+  }
+
+  RegExpMatch matchAsPrefix(String string, [int start = 0]) {
+    if (start < 0 || start > string.length) {
+      throw RangeError.range(start, 0, string.length);
+    }
+    return _execAnchored(string, start);
+  }
+
+  bool get isMultiLine => _isMultiLine;
+  bool get isCaseSensitive => _isCaseSensitive;
+  bool get isUnicode => _isUnicode;
+  bool get isDotAll => _isDotAll;
+}
+
+class _MatchImplementation implements RegExpMatch {
+  final Pattern pattern;
+  // Contains a JS RegExp match object.
+  // It is an Array of String values with extra "index" and "input" properties.
+  final List<String> _match;
+
+  _MatchImplementation(this.pattern, this._match) {
+    assert(JS("var", "#.input", _match) is String);
+    assert(JS("var", "#.index", _match) is int);
+  }
+
+  String get input => JS("String", "#.input", _match);
+  int get start => JS("int", "#.index", _match);
+  int get end => start + _match[0].length;
+
+  String group(int index) => _match[index];
+  String operator [](int index) => group(index);
+  int get groupCount => _match.length - 1;
+
+  List<String> groups(List<int> groups) {
+    List<String> out = [];
+    for (int i in groups) {
+      out.add(group(i));
+    }
+    return out;
+  }
+
+  String namedGroup(String name) {
+    var groups = JS('Object', '#.groups', _match);
+    if (groups != null) {
+      var result = JS('String|Null', '#[#]', groups, name);
+      if (result != null || JS<bool>('!', '# in #', name, groups)) {
+        return result;
+      }
+    }
+    throw ArgumentError.value(name, "name", "Not a capture group name");
+  }
+
+  Iterable<String> get groupNames {
+    var groups = JS('Object', '#.groups', _match);
+    if (groups != null) {
+      var keys = JSArray<String>.of(JS('', 'Object.keys(#)', groups));
+      return SubListIterable(keys, 0, null);
+    }
+    return Iterable.empty();
+  }
+}
+
+class _AllMatchesIterable extends IterableBase<RegExpMatch> {
+  final JSSyntaxRegExp _re;
+  final String _string;
+  final int _start;
+
+  _AllMatchesIterable(this._re, this._string, this._start);
+
+  Iterator<RegExpMatch> get iterator =>
+      _AllMatchesIterator(_re, _string, _start);
+}
+
+class _AllMatchesIterator implements Iterator<RegExpMatch> {
+  final JSSyntaxRegExp _regExp;
+  String _string;
+  int _nextIndex;
+  RegExpMatch _current;
+
+  _AllMatchesIterator(this._regExp, this._string, this._nextIndex);
+
+  RegExpMatch get current => _current;
+
+  static bool _isLeadSurrogate(int c) {
+    return c >= 0xd800 && c <= 0xdbff;
+  }
+
+  static bool _isTrailSurrogate(int c) {
+    return c >= 0xdc00 && c <= 0xdfff;
+  }
+
+  bool moveNext() {
+    if (_string == null) return false;
+    if (_nextIndex <= _string.length) {
+      var match = _regExp._execGlobal(_string, _nextIndex);
+      if (match != null) {
+        _current = match;
+        int nextIndex = match.end;
+        if (match.start == nextIndex) {
+          // Zero-width match. Advance by one more, unless the regexp
+          // is in unicode mode and it would put us within a surrogate
+          // pair. In that case, advance past the code point as a whole.
+          if (_regExp.isUnicode &&
+              _nextIndex + 1 < _string.length &&
+              _isLeadSurrogate(_string.codeUnitAt(_nextIndex)) &&
+              _isTrailSurrogate(_string.codeUnitAt(_nextIndex + 1))) {
+            nextIndex++;
+          }
+          nextIndex++;
+        }
+        _nextIndex = nextIndex;
+        return true;
+      }
+    }
+    _current = null;
+    _string = null; // Marks iteration as ended.
+    return false;
+  }
+}
+
+/** Find the first match of [regExp] in [string] at or after [start]. */
+RegExpMatch firstMatchAfter(JSSyntaxRegExp regExp, String string, int start) {
+  return regExp._execGlobal(string, start);
+}
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/private/string_helper.dart b/sdk_nnbd/lib/_internal/js_dev_runtime/private/string_helper.dart
new file mode 100644
index 0000000..c1b5c18
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/private/string_helper.dart
@@ -0,0 +1,297 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart._js_helper;
+
+@notNull
+int stringIndexOfStringUnchecked(receiver, other, startIndex) {
+  return JS<int>('!', '#.indexOf(#, #)', receiver, other, startIndex);
+}
+
+@notNull
+String substring1Unchecked(receiver, startIndex) {
+  return JS('!', '#.substring(#)', receiver, startIndex);
+}
+
+@notNull
+String substring2Unchecked(receiver, startIndex, endIndex) {
+  return JS('!', '#.substring(#, #)', receiver, startIndex, endIndex);
+}
+
+@notNull
+bool stringContainsStringUnchecked(receiver, other, startIndex) {
+  return stringIndexOfStringUnchecked(receiver, other, startIndex) >= 0;
+}
+
+class StringMatch implements Match {
+  const StringMatch(int this.start, String this.input, String this.pattern);
+
+  int get end => start + pattern.length;
+  String operator [](int g) => group(g);
+  int get groupCount => 0;
+
+  String group(int group_) {
+    if (group_ != 0) {
+      throw RangeError.value(group_);
+    }
+    return pattern;
+  }
+
+  List<String> groups(List<int> groups_) {
+    List<String> result = List<String>();
+    for (int g in groups_) {
+      result.add(group(g));
+    }
+    return result;
+  }
+
+  final int start;
+  final String input;
+  final String pattern;
+}
+
+Iterable<Match> allMatchesInStringUnchecked(
+    String pattern, String string, int startIndex) {
+  return _StringAllMatchesIterable(string, pattern, startIndex);
+}
+
+class _StringAllMatchesIterable extends Iterable<Match> {
+  final String _input;
+  final String _pattern;
+  final int _index;
+
+  _StringAllMatchesIterable(this._input, this._pattern, this._index);
+
+  Iterator<Match> get iterator =>
+      _StringAllMatchesIterator(_input, _pattern, _index);
+
+  Match get first {
+    int index = stringIndexOfStringUnchecked(_input, _pattern, _index);
+    if (index >= 0) {
+      return StringMatch(index, _input, _pattern);
+    }
+    throw IterableElementError.noElement();
+  }
+}
+
+class _StringAllMatchesIterator implements Iterator<Match> {
+  final String _input;
+  final String _pattern;
+  int _index;
+  Match _current;
+
+  _StringAllMatchesIterator(this._input, this._pattern, this._index);
+
+  bool moveNext() {
+    if (_index + _pattern.length > _input.length) {
+      _current = null;
+      return false;
+    }
+    var index = stringIndexOfStringUnchecked(_input, _pattern, _index);
+    if (index < 0) {
+      _index = _input.length + 1;
+      _current = null;
+      return false;
+    }
+    int end = index + _pattern.length;
+    _current = StringMatch(index, _input, _pattern);
+    // Empty match, don't start at same location again.
+    if (end == _index) end++;
+    _index = end;
+    return true;
+  }
+
+  Match get current => _current;
+}
+
+@notNull
+bool stringContainsUnchecked(
+    @notNull String receiver, @notNull other, int startIndex) {
+  if (other is String) {
+    return stringContainsStringUnchecked(receiver, other, startIndex);
+  } else if (other is JSSyntaxRegExp) {
+    return other.hasMatch(receiver.substring(startIndex));
+  } else {
+    var substr = receiver.substring(startIndex);
+    return other.allMatches(substr).isNotEmpty;
+  }
+}
+
+@notNull
+String stringReplaceJS(String receiver, replacer, String replacement) {
+  // The JavaScript String.replace method recognizes replacement
+  // patterns in the replacement string. Dart does not have that
+  // behavior.
+  replacement = JS<String>('!', r'#.replace(/\$/g, "$$$$")', replacement);
+  return JS<String>('!', r'#.replace(#, #)', receiver, replacer, replacement);
+}
+
+@notNull
+String stringReplaceFirstRE(@notNull String receiver, JSSyntaxRegExp regexp,
+    String replacement, int startIndex) {
+  var match = regexp._execGlobal(receiver, startIndex);
+  if (match == null) return receiver;
+  var start = match.start;
+  var end = match.end;
+  return stringReplaceRangeUnchecked(receiver, start, end, replacement);
+}
+
+/// Returns a string for a RegExp pattern that matches [string]. This is done by
+/// escaping all RegExp metacharacters.
+@notNull
+String quoteStringForRegExp(string) {
+  return JS<String>('!', r'#.replace(/[[\]{}()*+?.\\^$|]/g, "\\$&")', string);
+}
+
+@notNull
+String stringReplaceAllUnchecked(@notNull String receiver,
+    @nullCheck Pattern pattern, @nullCheck String replacement) {
+  if (pattern is String) {
+    if (pattern == "") {
+      if (receiver == "") {
+        return replacement;
+      } else {
+        StringBuffer result = StringBuffer();
+        int length = receiver.length;
+        result.write(replacement);
+        for (int i = 0; i < length; i++) {
+          result.write(receiver[i]);
+          result.write(replacement);
+        }
+        return result.toString();
+      }
+    } else {
+      return JS<String>(
+          '!', '#.split(#).join(#)', receiver, pattern, replacement);
+    }
+  } else if (pattern is JSSyntaxRegExp) {
+    var re = regExpGetGlobalNative(pattern);
+    return stringReplaceJS(receiver, re, replacement);
+  } else {
+    // TODO(floitsch): implement generic String.replace (with patterns).
+    throw "String.replaceAll(Pattern) UNIMPLEMENTED";
+  }
+}
+
+String _matchString(Match match) => match[0];
+String _stringIdentity(String string) => string;
+
+@notNull
+String stringReplaceAllFuncUnchecked(
+    String receiver,
+    @nullCheck Pattern pattern,
+    String onMatch(Match match),
+    String onNonMatch(String nonMatch)) {
+  if (onMatch == null) onMatch = _matchString;
+  if (onNonMatch == null) onNonMatch = _stringIdentity;
+  if (pattern is String) {
+    return stringReplaceAllStringFuncUnchecked(
+        receiver, pattern, onMatch, onNonMatch);
+  }
+  StringBuffer buffer = StringBuffer();
+  int startIndex = 0;
+  for (Match match in pattern.allMatches(receiver)) {
+    buffer.write(onNonMatch(receiver.substring(startIndex, match.start)));
+    buffer.write(onMatch(match));
+    startIndex = match.end;
+  }
+  buffer.write(onNonMatch(receiver.substring(startIndex)));
+  return buffer.toString();
+}
+
+@notNull
+String stringReplaceAllEmptyFuncUnchecked(String receiver,
+    String onMatch(Match match), String onNonMatch(String nonMatch)) {
+  // Pattern is the empty string.
+  StringBuffer buffer = StringBuffer();
+  int length = receiver.length;
+  int i = 0;
+  buffer.write(onNonMatch(""));
+  while (i < length) {
+    buffer.write(onMatch(StringMatch(i, receiver, "")));
+    // Special case to avoid splitting a surrogate pair.
+    int code = receiver.codeUnitAt(i);
+    if ((code & ~0x3FF) == 0xD800 && length > i + 1) {
+      // Leading surrogate;
+      code = receiver.codeUnitAt(i + 1);
+      if ((code & ~0x3FF) == 0xDC00) {
+        // Matching trailing surrogate.
+        buffer.write(onNonMatch(receiver.substring(i, i + 2)));
+        i += 2;
+        continue;
+      }
+    }
+    buffer.write(onNonMatch(receiver[i]));
+    i++;
+  }
+  buffer.write(onMatch(StringMatch(i, receiver, "")));
+  buffer.write(onNonMatch(""));
+  return buffer.toString();
+}
+
+@notNull
+String stringReplaceAllStringFuncUnchecked(String receiver, String pattern,
+    String onMatch(Match match), String onNonMatch(String nonMatch)) {
+  int patternLength = pattern.length;
+  if (patternLength == 0) {
+    return stringReplaceAllEmptyFuncUnchecked(receiver, onMatch, onNonMatch);
+  }
+  int length = receiver.length;
+  StringBuffer buffer = StringBuffer();
+  int startIndex = 0;
+  while (startIndex < length) {
+    int position = stringIndexOfStringUnchecked(receiver, pattern, startIndex);
+    if (position == -1) {
+      break;
+    }
+    buffer.write(onNonMatch(receiver.substring(startIndex, position)));
+    buffer.write(onMatch(StringMatch(position, receiver, pattern)));
+    startIndex = position + patternLength;
+  }
+  buffer.write(onNonMatch(receiver.substring(startIndex)));
+  return buffer.toString();
+}
+
+@notNull
+String stringReplaceFirstUnchecked(@notNull String receiver,
+    @nullCheck Pattern pattern, String replacement, int startIndex) {
+  if (pattern is String) {
+    int index = stringIndexOfStringUnchecked(receiver, pattern, startIndex);
+    if (index < 0) return receiver;
+    int end = index + pattern.length;
+    return stringReplaceRangeUnchecked(receiver, index, end, replacement);
+  }
+  if (pattern is JSSyntaxRegExp) {
+    return startIndex == 0
+        ? stringReplaceJS(receiver, regExpGetNative(pattern), replacement)
+        : stringReplaceFirstRE(receiver, pattern, replacement, startIndex);
+  }
+  Iterator<Match> matches = pattern.allMatches(receiver, startIndex).iterator;
+  if (!matches.moveNext()) return receiver;
+  Match match = matches.current;
+  return receiver.replaceRange(match.start, match.end, replacement);
+}
+
+@notNull
+String stringReplaceFirstMappedUnchecked(String receiver, Pattern pattern,
+    String replace(Match current), int startIndex) {
+  Iterator<Match> matches = pattern.allMatches(receiver, startIndex).iterator;
+  if (!matches.moveNext()) return receiver;
+  Match match = matches.current;
+  String replacement = "${replace(match)}";
+  return receiver.replaceRange(match.start, match.end, replacement);
+}
+
+@notNull
+String stringJoinUnchecked(array, separator) {
+  return JS<String>('!', r'#.join(#)', array, separator);
+}
+
+@notNull
+String stringReplaceRangeUnchecked(
+    String receiver, int start, int end, String replacement) {
+  String prefix = JS('!', '#.substring(0, #)', receiver, start);
+  String suffix = JS('!', '#.substring(#)', receiver, end);
+  return "$prefix$replacement$suffix";
+}
diff --git a/sdk_nnbd/lib/_internal/js_runtime/.packages b/sdk_nnbd/lib/_internal/js_runtime/.packages
new file mode 100644
index 0000000..adf8b36
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_runtime/.packages
@@ -0,0 +1,2 @@
+# Generated by pub on 2015-12-07 17:08:11.724.
+js_runtime:lib/
diff --git a/sdk_nnbd/lib/_internal/js_runtime/lib/annotations.dart b/sdk_nnbd/lib/_internal/js_runtime/lib/annotations.dart
new file mode 100644
index 0000000..f53c5f3
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_runtime/lib/annotations.dart
@@ -0,0 +1,18 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of _js_helper;
+
+/// Marks a class as native and defines its JavaScript name(s).
+class Native {
+  final String name;
+  const Native(this.name);
+}
+
+class _Patch {
+  const _Patch();
+}
+
+/// Annotation that marks the declaration as a patch.
+const _Patch patch = const _Patch();
diff --git a/sdk_nnbd/lib/_internal/js_runtime/lib/async_patch.dart b/sdk_nnbd/lib/_internal/js_runtime/lib/async_patch.dart
new file mode 100644
index 0000000..68bcbeb
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_runtime/lib/async_patch.dart
@@ -0,0 +1,694 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Patch file for the dart:async library.
+
+import 'dart:_js_helper'
+    show
+        patch,
+        ExceptionAndStackTrace,
+        convertDartClosureToJS,
+        getTraceFromException,
+        requiresPreamble,
+        wrapException,
+        unwrapException;
+
+import 'dart:_foreign_helper' show JS, JS_GET_FLAG;
+
+import 'dart:_async_await_error_codes' as async_error_codes;
+
+import "dart:collection" show IterableBase;
+
+@patch
+class _AsyncRun {
+  @patch
+  static void _scheduleImmediate(void callback()) {
+    _scheduleImmediateClosure(callback);
+  }
+
+  // Lazily initialized.
+  static final Function _scheduleImmediateClosure =
+      _initializeScheduleImmediate();
+
+  static Function _initializeScheduleImmediate() {
+    requiresPreamble();
+    if (JS('', 'self.scheduleImmediate') != null) {
+      return _scheduleImmediateJsOverride;
+    }
+    if (JS('', 'self.MutationObserver') != null &&
+        JS('', 'self.document') != null) {
+      // Use mutationObservers.
+      var div = JS('', 'self.document.createElement("div")');
+      var span = JS('', 'self.document.createElement("span")');
+      var storedCallback;
+
+      internalCallback(_) {
+        var f = storedCallback;
+        storedCallback = null;
+        f();
+      }
+
+      var observer = JS('', 'new self.MutationObserver(#)',
+          convertDartClosureToJS(internalCallback, 1));
+      JS('', '#.observe(#, { childList: true })', observer, div);
+
+      return (void callback()) {
+        assert(storedCallback == null);
+        storedCallback = callback;
+        // Because of a broken shadow-dom polyfill we have to change the
+        // children instead a cheap property.
+        JS('', '#.firstChild ? #.removeChild(#): #.appendChild(#)', div, div,
+            span, div, span);
+      };
+    } else if (JS('', 'self.setImmediate') != null) {
+      return _scheduleImmediateWithSetImmediate;
+    }
+    // TODO(20055): We should use DOM promises when available.
+    return _scheduleImmediateWithTimer;
+  }
+
+  static void _scheduleImmediateJsOverride(void callback()) {
+    internalCallback() {
+      callback();
+    }
+
+    JS('void', 'self.scheduleImmediate(#)',
+        convertDartClosureToJS(internalCallback, 0));
+  }
+
+  static void _scheduleImmediateWithSetImmediate(void callback()) {
+    internalCallback() {
+      callback();
+    }
+
+    JS('void', 'self.setImmediate(#)',
+        convertDartClosureToJS(internalCallback, 0));
+  }
+
+  static void _scheduleImmediateWithTimer(void callback()) {
+    Timer._createTimer(Duration.zero, callback);
+  }
+}
+
+@patch
+class DeferredLibrary {
+  @patch
+  Future<Null> load() {
+    throw 'DeferredLibrary not supported. '
+        'please use the `import "lib.dart" deferred as lib` syntax.';
+  }
+}
+
+@patch
+class Timer {
+  @patch
+  static Timer _createTimer(Duration duration, void callback()) {
+    int milliseconds = duration.inMilliseconds;
+    if (milliseconds < 0) milliseconds = 0;
+    return new _TimerImpl(milliseconds, callback);
+  }
+
+  @patch
+  static Timer _createPeriodicTimer(
+      Duration duration, void callback(Timer timer)) {
+    int milliseconds = duration.inMilliseconds;
+    if (milliseconds < 0) milliseconds = 0;
+    return new _TimerImpl.periodic(milliseconds, callback);
+  }
+}
+
+class _TimerImpl implements Timer {
+  final bool _once;
+  int _handle;
+  int _tick = 0;
+
+  _TimerImpl(int milliseconds, void callback()) : _once = true {
+    if (_hasTimer()) {
+      void internalCallback() {
+        _handle = null;
+        this._tick = 1;
+        callback();
+      }
+
+      _handle = JS('int', 'self.setTimeout(#, #)',
+          convertDartClosureToJS(internalCallback, 0), milliseconds);
+    } else {
+      throw new UnsupportedError('`setTimeout()` not found.');
+    }
+  }
+
+  _TimerImpl.periodic(int milliseconds, void callback(Timer timer))
+      : _once = false {
+    if (_hasTimer()) {
+      int start = JS('int', 'Date.now()');
+      _handle = JS(
+          'int',
+          'self.setInterval(#, #)',
+          convertDartClosureToJS(() {
+            int tick = this._tick + 1;
+            if (milliseconds > 0) {
+              int duration = JS('int', 'Date.now()') - start;
+              if (duration > (tick + 1) * milliseconds) {
+                tick = duration ~/ milliseconds;
+              }
+            }
+            this._tick = tick;
+            callback(this);
+          }, 0),
+          milliseconds);
+    } else {
+      throw new UnsupportedError('Periodic timer.');
+    }
+  }
+
+  @override
+  bool get isActive => _handle != null;
+
+  @override
+  int get tick => _tick;
+
+  @override
+  void cancel() {
+    if (_hasTimer()) {
+      if (_handle == null) return;
+      if (_once) {
+        JS('void', 'self.clearTimeout(#)', _handle);
+      } else {
+        JS('void', 'self.clearInterval(#)', _handle);
+      }
+      _handle = null;
+    } else {
+      throw new UnsupportedError('Canceling a timer.');
+    }
+  }
+}
+
+bool _hasTimer() {
+  requiresPreamble();
+  return JS('', 'self.setTimeout') != null;
+}
+
+class _AsyncAwaitCompleter<T> implements Completer<T> {
+  final _future = new _Future<T>();
+  bool isSync;
+
+  _AsyncAwaitCompleter() : isSync = false;
+
+  void complete([FutureOr<T> value]) {
+    if (!isSync || value is Future<T>) {
+      _future._asyncComplete(value);
+    } else {
+      _future._completeWithValue(value);
+    }
+  }
+
+  void completeError(e, [st]) {
+    if (isSync) {
+      _future._completeError(e, st);
+    } else {
+      _future._asyncCompleteError(e, st);
+    }
+  }
+
+  Future<T> get future => _future;
+  bool get isCompleted => !_future._mayComplete;
+}
+
+/// Creates a Completer for an `async` function.
+///
+/// Used as part of the runtime support for the async/await transformation.
+Completer<T> _makeAsyncAwaitCompleter<T>() {
+  return new _AsyncAwaitCompleter<T>();
+}
+
+/// Initiates the computation of an `async` function and starts the body
+/// synchronously.
+///
+/// Used as part of the runtime support for the async/await transformation.
+///
+/// This function sets up the first call into the transformed [bodyFunction].
+/// Independently, it takes the [completer] and returns the future of the
+/// completer for convenience of the transformed code.
+dynamic _asyncStartSync(
+    _WrappedAsyncBody bodyFunction, _AsyncAwaitCompleter completer) {
+  bodyFunction(async_error_codes.SUCCESS, null);
+  completer.isSync = true;
+  return completer.future;
+}
+
+/// Performs the `await` operation of an `async` function.
+///
+/// Used as part of the runtime support for the async/await transformation.
+///
+/// Arranges for [bodyFunction] to be called when the future or value [object]
+/// is completed with a code [async_error_codes.SUCCESS] or
+/// [async_error_codes.ERROR] depending on the success of the future.
+dynamic _asyncAwait(dynamic object, _WrappedAsyncBody bodyFunction) {
+  _awaitOnObject(object, bodyFunction);
+}
+
+/// Completes the future of an `async` function.
+///
+/// Used as part of the runtime support for the async/await transformation.
+///
+/// This function is used when the `async` function returns (explicitly or
+/// implicitly).
+dynamic _asyncReturn(dynamic object, Completer completer) {
+  completer.complete(object);
+}
+
+/// Completes the future of an `async` function with an error.
+///
+/// Used as part of the runtime support for the async/await transformation.
+///
+/// This function is used when the `async` function re-throws an exception.
+dynamic _asyncRethrow(dynamic object, Completer completer) {
+  // The error is a js-error.
+  completer.completeError(
+      unwrapException(object), getTraceFromException(object));
+}
+
+/// Awaits on the given [object].
+///
+/// If the [object] is a Future, registers on it, otherwise wraps it into a
+/// future first.
+///
+/// The [bodyFunction] argument is the continuation that should be invoked
+/// when the future completes.
+void _awaitOnObject(object, _WrappedAsyncBody bodyFunction) {
+  Function thenCallback =
+      (result) => bodyFunction(async_error_codes.SUCCESS, result);
+
+  Function errorCallback = (dynamic error, StackTrace stackTrace) {
+    ExceptionAndStackTrace wrappedException =
+        new ExceptionAndStackTrace(error, stackTrace);
+    bodyFunction(async_error_codes.ERROR, wrappedException);
+  };
+
+  if (object is _Future) {
+    // We can skip the zone registration, since the bodyFunction is already
+    // registered (see [_wrapJsFunctionForAsync]).
+    object._thenAwait(thenCallback, errorCallback);
+  } else if (object is Future) {
+    object.then(thenCallback, onError: errorCallback);
+  } else {
+    _Future future = new _Future().._setValue(object);
+    // We can skip the zone registration, since the bodyFunction is already
+    // registered (see [_wrapJsFunctionForAsync]).
+    future._thenAwait(thenCallback, null);
+  }
+}
+
+typedef void _WrappedAsyncBody(int errorCode, dynamic result);
+
+_WrappedAsyncBody _wrapJsFunctionForAsync(dynamic /* js function */ function) {
+  var protected = JS(
+      '',
+      """
+        (function (fn, ERROR) {
+          // Invokes [function] with [errorCode] and [result].
+          //
+          // If (and as long as) the invocation throws, calls [function] again,
+          // with an error-code.
+          return function(errorCode, result) {
+            while (true) {
+              try {
+                fn(errorCode, result);
+                break;
+              } catch (error) {
+                result = error;
+                errorCode = ERROR;
+              }
+            }
+          }
+        })(#, #)""",
+      function,
+      async_error_codes.ERROR);
+
+  return Zone.current.registerBinaryCallback((int errorCode, dynamic result) {
+    JS('', '#(#, #)', protected, errorCode, result);
+  });
+}
+
+/// Implements the runtime support for async* functions.
+///
+/// Called by the transformed function for each original return, await, yield,
+/// yield* and before starting the function.
+///
+/// When the async* function wants to return it calls this function with
+/// [asyncBody] == [async_error_codes.SUCCESS], the asyncStarHelper takes this
+/// as signal to close the stream.
+///
+/// When the async* function wants to signal that an uncaught error was thrown,
+/// it calls this function with [asyncBody] == [async_error_codes.ERROR],
+/// the streamHelper takes this as signal to addError [object] to the
+/// [controller] and close it.
+///
+/// If the async* function wants to do a yield or yield*, it calls this function
+/// with [object] being an [IterationMarker].
+///
+/// In the case of a yield or yield*, if the stream subscription has been
+/// canceled, schedules [asyncBody] to be called with
+/// [async_error_codes.STREAM_WAS_CANCELED].
+///
+/// If [object] is a single-yield [IterationMarker], adds the value of the
+/// [IterationMarker] to the stream. If the stream subscription has been
+/// paused, return early. Otherwise schedule the helper function to be
+/// executed again.
+///
+/// If [object] is a yield-star [IterationMarker], starts listening to the
+/// yielded stream, and adds all events and errors to our own controller (taking
+/// care if the subscription has been paused or canceled) - when the sub-stream
+/// is done, schedules [asyncBody] again.
+///
+/// If the async* function wants to do an await it calls this function with
+/// [object] not an [IterationMarker].
+///
+/// If [object] is not a [Future], it is wrapped in a `Future.value`.
+/// The [asyncBody] is called on completion of the future (see [asyncHelper].
+void _asyncStarHelper(
+    dynamic object,
+    dynamic /* int | _WrappedAsyncBody */ bodyFunctionOrErrorCode,
+    _AsyncStarStreamController controller) {
+  if (identical(bodyFunctionOrErrorCode, async_error_codes.SUCCESS)) {
+    // This happens on return from the async* function.
+    if (controller.isCanceled) {
+      controller.cancelationFuture._completeWithValue(null);
+    } else {
+      controller.close();
+    }
+    return;
+  } else if (identical(bodyFunctionOrErrorCode, async_error_codes.ERROR)) {
+    // The error is a js-error.
+    if (controller.isCanceled) {
+      controller.cancelationFuture._completeError(
+          unwrapException(object), getTraceFromException(object));
+    } else {
+      controller.addError(
+          unwrapException(object), getTraceFromException(object));
+      controller.close();
+    }
+    return;
+  }
+
+  if (object is _IterationMarker) {
+    if (controller.isCanceled) {
+      bodyFunctionOrErrorCode(async_error_codes.STREAM_WAS_CANCELED, null);
+      return;
+    }
+    if (object.state == _IterationMarker.YIELD_SINGLE) {
+      controller.add(object.value);
+
+      scheduleMicrotask(() {
+        if (controller.isPaused) {
+          // We only suspend the thread inside the microtask in order to allow
+          // listeners on the output stream to pause in response to the just
+          // output value, and have the stream immediately stop producing.
+          controller.isSuspended = true;
+          return;
+        }
+        bodyFunctionOrErrorCode(null, async_error_codes.SUCCESS);
+      });
+      return;
+    } else if (object.state == _IterationMarker.YIELD_STAR) {
+      Stream stream = object.value;
+      // Errors of [stream] are passed though to the main stream. (see
+      // [AsyncStreamController.addStream]).
+      // TODO(sigurdm): The spec is not very clear here. Clarify with Gilad.
+      controller.addStream(stream).then((_) {
+        // No check for isPaused here because the spec 17.16.2 only
+        // demands checks *before* each element in [stream] not after the last
+        // one. On the other hand we check for isCanceled, as that check happens
+        // after insertion of each element.
+        int errorCode = controller.isCanceled
+            ? async_error_codes.STREAM_WAS_CANCELED
+            : async_error_codes.SUCCESS;
+        bodyFunctionOrErrorCode(errorCode, null);
+      });
+      return;
+    }
+  }
+
+  _awaitOnObject(object, bodyFunctionOrErrorCode);
+}
+
+Stream _streamOfController(_AsyncStarStreamController controller) {
+  return controller.stream;
+}
+
+/// A wrapper around a [StreamController] that keeps track of the state of
+/// the execution of an async* function.
+/// It can be in 1 of 3 states:
+///
+/// - running/scheduled
+/// - suspended
+/// - canceled
+///
+/// If yielding while the subscription is paused it will become suspended. And
+/// only resume after the subscription is resumed or canceled.
+class _AsyncStarStreamController<T> {
+  StreamController<T> controller;
+  Stream get stream => controller.stream;
+
+  /// True when the async* function has yielded while being paused.
+  /// When true execution will only resume after a `onResume` or `onCancel`
+  /// event.
+  bool isSuspended = false;
+
+  bool get isPaused => controller.isPaused;
+
+  _Future cancelationFuture = null;
+
+  /// True after the StreamSubscription has been cancelled.
+  /// When this is true, errors thrown from the async* body should go to the
+  /// [cancelationFuture] instead of adding them to [controller], and
+  /// returning from the async function should complete [cancelationFuture].
+  bool get isCanceled => cancelationFuture != null;
+
+  add(event) => controller.add(event);
+
+  addStream(Stream<T> stream) {
+    return controller.addStream(stream, cancelOnError: false);
+  }
+
+  addError(error, stackTrace) => controller.addError(error, stackTrace);
+
+  close() => controller.close();
+
+  _AsyncStarStreamController(_WrappedAsyncBody body) {
+    _resumeBody() {
+      scheduleMicrotask(() {
+        body(async_error_codes.SUCCESS, null);
+      });
+    }
+
+    controller = new StreamController<T>(onListen: () {
+      _resumeBody();
+    }, onResume: () {
+      // Only schedule again if the async* function actually is suspended.
+      // Resume directly instead of scheduling, so that the sequence
+      // `pause-resume-pause` will result in one extra event produced.
+      if (isSuspended) {
+        isSuspended = false;
+        _resumeBody();
+      }
+    }, onCancel: () {
+      // If the async* is finished we ignore cancel events.
+      if (!controller.isClosed) {
+        cancelationFuture = new _Future();
+        if (isSuspended) {
+          // Resume the suspended async* function to run finalizers.
+          isSuspended = false;
+          scheduleMicrotask(() {
+            body(async_error_codes.STREAM_WAS_CANCELED, null);
+          });
+        }
+        return cancelationFuture;
+      }
+    });
+  }
+}
+
+/// Creates a stream controller for an `async*` function.
+///
+/// Used as part of the runtime support for the async/await transformation.
+_makeAsyncStarStreamController<T>(_WrappedAsyncBody body) {
+  return new _AsyncStarStreamController<T>(body);
+}
+
+class _IterationMarker {
+  static const YIELD_SINGLE = 0;
+  static const YIELD_STAR = 1;
+  static const ITERATION_ENDED = 2;
+  static const UNCAUGHT_ERROR = 3;
+
+  final value;
+  final int state;
+
+  const _IterationMarker._(this.state, this.value);
+
+  static yieldStar(dynamic /* Iterable or Stream */ values) {
+    return new _IterationMarker._(YIELD_STAR, values);
+  }
+
+  static endOfIteration() {
+    return const _IterationMarker._(ITERATION_ENDED, null);
+  }
+
+  static yieldSingle(dynamic value) {
+    return new _IterationMarker._(YIELD_SINGLE, value);
+  }
+
+  static uncaughtError(dynamic error) {
+    return new _IterationMarker._(UNCAUGHT_ERROR, error);
+  }
+
+  toString() => "IterationMarker($state, $value)";
+}
+
+class _SyncStarIterator<T> implements Iterator<T> {
+  // _SyncStarIterator handles stepping a sync* generator body state machine.
+  //
+  // It also handles the stepping over 'nested' iterators to flatten yield*
+  // statements. For non-sync* iterators, [_nestedIterator] contains the
+  // iterator. We delegate to [_nestedIterator] when it is not `null`.
+  //
+  // For nested sync* iterators, [this] iterator acts on behalf of the innermost
+  // nested sync* iterator. The current state machine is suspended on a stack
+  // until the inner state machine ends.
+
+  // The state machine for the innermost _SyncStarIterator.
+  dynamic _body;
+
+  // The current value, unless iterating a non-sync* nested iterator.
+  T _current = null;
+
+  // This is the nested iterator when iterating a yield* of a non-sync iterator.
+  // TODO(32956): In strong-mode, yield* takes an Iterable<T> (possibly checked
+  // with an implicit downcast), so change type to Iterator<T>.
+  Iterator _nestedIterator = null;
+
+  // Stack of suspended state machines when iterating a yield* of a sync*
+  // iterator.
+  List _suspendedBodies = null;
+
+  _SyncStarIterator(this._body);
+
+  T get current {
+    if (_nestedIterator == null) return _current;
+    return _nestedIterator.current;
+  }
+
+  _runBody() {
+    // TODO(sra): Find a way to hard-wire SUCCESS and ERROR codes.
+    return JS(
+        '',
+        '''
+        // Invokes [body] with [errorCode] and [result].
+        //
+        // If (and as long as) the invocation throws, calls [function] again,
+        // with an error-code.
+        (function(body, SUCCESS, ERROR) {
+          var errorValue, errorCode = SUCCESS;
+          while (true) {
+            try {
+              return body(errorCode, errorValue);
+            } catch (error) {
+              errorValue = error;
+              errorCode = ERROR;
+            }
+          }
+        })(#, #, #)''',
+        _body,
+        async_error_codes.SUCCESS,
+        async_error_codes.ERROR);
+  }
+
+  bool moveNext() {
+    while (true) {
+      if (_nestedIterator != null) {
+        if (_nestedIterator.moveNext()) {
+          return true;
+        } else {
+          _nestedIterator = null;
+        }
+      }
+      var value = _runBody();
+      if (value is _IterationMarker) {
+        int state = value.state;
+        if (state == _IterationMarker.ITERATION_ENDED) {
+          if (_suspendedBodies == null || _suspendedBodies.isEmpty) {
+            _current = null;
+            // Rely on [_body] to repeatedly return `ITERATION_ENDED`.
+            return false;
+          }
+          // Resume the innermost suspended iterator.
+          _body = _suspendedBodies.removeLast();
+          continue;
+        } else if (state == _IterationMarker.UNCAUGHT_ERROR) {
+          // Rely on [_body] to repeatedly return `UNCAUGHT_ERROR`.
+          // This is a wrapped exception, so we use JavaScript throw to throw
+          // it.
+          JS('', 'throw #', value.value);
+        } else {
+          assert(state == _IterationMarker.YIELD_STAR);
+          Iterator inner = value.value.iterator;
+          if (inner is _SyncStarIterator) {
+            // Suspend the current state machine and start acting on behalf of
+            // the nested state machine.
+            //
+            // TODO(sra): Recognize "tail yield*" statements and avoid
+            // suspending the current body when all it will do is step without
+            // effect to ITERATION_ENDED.
+            (_suspendedBodies ??= []).add(_body);
+            _body = inner._body;
+            continue;
+          } else {
+            _nestedIterator = inner;
+            // TODO(32956): Change to the following when strong-mode is the only
+            // option:
+            //
+            //     _nestedIterator = JS<Iterator<T>>('','#', inner);
+            continue;
+          }
+        }
+      } else {
+        // TODO(32956): Remove this test.
+        _current = JS<T>('', '#', value);
+        return true;
+      }
+    }
+    return false; // TODO(sra): Fix type inference so that this is not needed.
+  }
+}
+
+/// Creates an Iterable for a `sync*` function.
+///
+/// Used as part of the runtime support for the async/await transformation.
+_SyncStarIterable<T> _makeSyncStarIterable<T>(body) {
+  return new _SyncStarIterable<T>(body);
+}
+
+/// An Iterable corresponding to a sync* method.
+///
+/// Each invocation of a sync* method will return a new instance of this class.
+class _SyncStarIterable<T> extends IterableBase<T> {
+  // This is a function that will return a helper function that does the
+  // iteration of the sync*.
+  //
+  // Each invocation should give a body with fresh state.
+  final dynamic /* js function */ _outerHelper;
+
+  _SyncStarIterable(this._outerHelper);
+
+  Iterator<T> get iterator =>
+      new _SyncStarIterator<T>(JS('', '#()', _outerHelper));
+}
+
+@patch
+void _rethrow(Object error, StackTrace stackTrace) {
+  error = wrapException(error);
+  JS('void', '#.stack = #', error, stackTrace.toString());
+  JS('void', 'throw #', error);
+}
diff --git a/sdk_nnbd/lib/_internal/js_runtime/lib/cli_patch.dart b/sdk_nnbd/lib/_internal/js_runtime/lib/cli_patch.dart
new file mode 100644
index 0000000..6921e60
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_runtime/lib/cli_patch.dart
@@ -0,0 +1,10 @@
+// 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:_js_helper' show patch;
+
+@patch
+void _waitForEvent(int timeoutMillis) {
+  throw new UnsupportedError("waitForEvent");
+}
diff --git a/sdk_nnbd/lib/_internal/js_runtime/lib/collection_patch.dart b/sdk_nnbd/lib/_internal/js_runtime/lib/collection_patch.dart
new file mode 100644
index 0000000..300d490
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_runtime/lib/collection_patch.dart
@@ -0,0 +1,1727 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Patch file for dart:collection classes.
+import 'dart:_foreign_helper' show JS;
+import 'dart:_js_helper'
+    show
+        fillLiteralMap,
+        fillLiteralSet,
+        InternalMap,
+        NoInline,
+        NoSideEffects,
+        NoThrows,
+        patch,
+        JsLinkedHashMap,
+        LinkedHashMapCell,
+        LinkedHashMapKeyIterable,
+        LinkedHashMapKeyIterator;
+
+import 'dart:_internal' hide Symbol;
+
+const _USE_ES6_MAPS = const bool.fromEnvironment("dart2js.use.es6.maps");
+
+const int _mask30 = 0x3fffffff; // Low 30 bits.
+
+@patch
+class HashMap<K, V> {
+  @patch
+  factory HashMap(
+      {bool equals(K key1, K key2),
+      int hashCode(K key),
+      bool isValidKey(potentialKey)}) {
+    if (isValidKey == null) {
+      if (hashCode == null) {
+        if (equals == null) {
+          return new _HashMap<K, V>();
+        }
+        hashCode = _defaultHashCode;
+      } else {
+        if (identical(identityHashCode, hashCode) &&
+            identical(identical, equals)) {
+          return new _IdentityHashMap<K, V>();
+        }
+        if (equals == null) {
+          equals = _defaultEquals;
+        }
+      }
+    } else {
+      if (hashCode == null) {
+        hashCode = _defaultHashCode;
+      }
+      if (equals == null) {
+        equals = _defaultEquals;
+      }
+    }
+    return new _CustomHashMap<K, V>(equals, hashCode, isValidKey);
+  }
+
+  @patch
+  factory HashMap.identity() = _IdentityHashMap<K, V>;
+}
+
+class _HashMap<K, V> extends MapBase<K, V> implements HashMap<K, V> {
+  int _length = 0;
+
+  // The hash map contents are divided into three parts: one part for
+  // string keys, one for numeric keys, and one for the rest. String
+  // and numeric keys map directly to their values, but the rest of
+  // the entries are stored in bucket lists of the form:
+  //
+  //    [key-0, value-0, key-1, value-1, ...]
+  //
+  // where all keys in the same bucket share the same hash code.
+  var _strings;
+  var _nums;
+  var _rest;
+
+  // When iterating over the hash map, it is very convenient to have a
+  // list of all the keys. We cache that on the instance and clear the
+  // the cache whenever the key set changes. This is also used to
+  // guard against concurrent modifications.
+  List _keys;
+
+  _HashMap();
+
+  int get length => _length;
+  bool get isEmpty => _length == 0;
+  bool get isNotEmpty => !isEmpty;
+
+  Iterable<K> get keys {
+    return new _HashMapKeyIterable<K>(this);
+  }
+
+  Iterable<V> get values {
+    return new MappedIterable<K, V>(keys, (each) => this[each]);
+  }
+
+  bool containsKey(Object key) {
+    if (_isStringKey(key)) {
+      var strings = _strings;
+      return (strings == null) ? false : _hasTableEntry(strings, key);
+    } else if (_isNumericKey(key)) {
+      var nums = _nums;
+      return (nums == null) ? false : _hasTableEntry(nums, key);
+    } else {
+      return _containsKey(key);
+    }
+  }
+
+  bool _containsKey(Object key) {
+    var rest = _rest;
+    if (rest == null) return false;
+    var bucket = _getBucket(rest, key);
+    return _findBucketIndex(bucket, key) >= 0;
+  }
+
+  bool containsValue(Object value) {
+    return _computeKeys().any((each) => this[each] == value);
+  }
+
+  void addAll(Map<K, V> other) {
+    other.forEach((K key, V value) {
+      this[key] = value;
+    });
+  }
+
+  V operator [](Object key) {
+    if (_isStringKey(key)) {
+      var strings = _strings;
+      return JS('', '#', strings == null ? null : _getTableEntry(strings, key));
+    } else if (_isNumericKey(key)) {
+      var nums = _nums;
+      return JS('', '#', nums == null ? null : _getTableEntry(nums, key));
+    } else {
+      return _get(key);
+    }
+  }
+
+  V _get(Object key) {
+    var rest = _rest;
+    if (rest == null) return null;
+    var bucket = _getBucket(rest, key);
+    int index = _findBucketIndex(bucket, key);
+    return (index < 0) ? null : JS('', '#[#]', bucket, index + 1);
+  }
+
+  void operator []=(K key, V value) {
+    if (_isStringKey(key)) {
+      var strings = _strings;
+      if (strings == null) _strings = strings = _newHashTable();
+      _addHashTableEntry(strings, key, value);
+    } else if (_isNumericKey(key)) {
+      var nums = _nums;
+      if (nums == null) _nums = nums = _newHashTable();
+      _addHashTableEntry(nums, key, value);
+    } else {
+      _set(key, value);
+    }
+  }
+
+  void _set(K key, V value) {
+    var rest = _rest;
+    if (rest == null) _rest = rest = _newHashTable();
+    var hash = _computeHashCode(key);
+    var bucket = JS('var', '#[#]', rest, hash);
+    if (bucket == null) {
+      _setTableEntry(rest, hash, JS('var', '[#, #]', key, value));
+      _length++;
+      _keys = null;
+    } else {
+      int index = _findBucketIndex(bucket, key);
+      if (index >= 0) {
+        JS('void', '#[#] = #', bucket, index + 1, value);
+      } else {
+        JS('void', '#.push(#, #)', bucket, key, value);
+        _length++;
+        _keys = null;
+      }
+    }
+  }
+
+  V putIfAbsent(K key, V ifAbsent()) {
+    if (containsKey(key)) return this[key];
+    V value = ifAbsent();
+    this[key] = value;
+    return value;
+  }
+
+  V remove(Object key) {
+    if (_isStringKey(key)) {
+      return _removeHashTableEntry(_strings, key);
+    } else if (_isNumericKey(key)) {
+      return _removeHashTableEntry(_nums, key);
+    } else {
+      return _remove(key);
+    }
+  }
+
+  V _remove(Object key) {
+    var rest = _rest;
+    if (rest == null) return null;
+    var bucket = _getBucket(rest, key);
+    int index = _findBucketIndex(bucket, key);
+    if (index < 0) return null;
+    // TODO(kasperl): Consider getting rid of the bucket list when
+    // the length reaches zero.
+    _length--;
+    _keys = null;
+    // Use splice to remove the two [key, value] elements at the
+    // index and return the value.
+    return JS('var', '#.splice(#, 2)[1]', bucket, index);
+  }
+
+  void clear() {
+    if (_length > 0) {
+      _strings = _nums = _rest = _keys = null;
+      _length = 0;
+    }
+  }
+
+  void forEach(void action(K key, V value)) {
+    List keys = _computeKeys();
+    for (int i = 0, length = keys.length; i < length; i++) {
+      var key = JS('var', '#[#]', keys, i);
+      action(key, this[key]);
+      if (JS('bool', '# !== #', keys, _keys)) {
+        throw new ConcurrentModificationError(this);
+      }
+    }
+  }
+
+  List _computeKeys() {
+    if (_keys != null) return _keys;
+    List result = new List(_length);
+    int index = 0;
+
+    // Add all string keys to the list.
+    var strings = _strings;
+    if (strings != null) {
+      var names = JS('var', 'Object.getOwnPropertyNames(#)', strings);
+      int entries = JS('int', '#.length', names);
+      for (int i = 0; i < entries; i++) {
+        String key = JS('String', '#[#]', names, i);
+        JS('void', '#[#] = #', result, index, key);
+        index++;
+      }
+    }
+
+    // Add all numeric keys to the list.
+    var nums = _nums;
+    if (nums != null) {
+      var names = JS('var', 'Object.getOwnPropertyNames(#)', nums);
+      int entries = JS('int', '#.length', names);
+      for (int i = 0; i < entries; i++) {
+        // Object.getOwnPropertyNames returns a list of strings, so we
+        // have to convert the keys back to numbers (+).
+        num key = JS('num', '+#[#]', names, i);
+        JS('void', '#[#] = #', result, index, key);
+        index++;
+      }
+    }
+
+    // Add all the remaining keys to the list.
+    var rest = _rest;
+    if (rest != null) {
+      var names = JS('var', 'Object.getOwnPropertyNames(#)', rest);
+      int entries = JS('int', '#.length', names);
+      for (int i = 0; i < entries; i++) {
+        var key = JS('String', '#[#]', names, i);
+        var bucket = JS('var', '#[#]', rest, key);
+        int length = JS('int', '#.length', bucket);
+        for (int i = 0; i < length; i += 2) {
+          var key = JS('var', '#[#]', bucket, i);
+          JS('void', '#[#] = #', result, index, key);
+          index++;
+        }
+      }
+    }
+    assert(index == _length);
+    return _keys = result;
+  }
+
+  void _addHashTableEntry(var table, K key, V value) {
+    if (!_hasTableEntry(table, key)) {
+      _length++;
+      _keys = null;
+    }
+    _setTableEntry(table, key, value);
+  }
+
+  V _removeHashTableEntry(var table, Object key) {
+    if (table != null && _hasTableEntry(table, key)) {
+      V value = _getTableEntry(table, key);
+      _deleteTableEntry(table, key);
+      _length--;
+      _keys = null;
+      return value;
+    } else {
+      return null;
+    }
+  }
+
+  static bool _isStringKey(var key) {
+    return key is String && key != '__proto__';
+  }
+
+  static bool _isNumericKey(var key) {
+    // Only treat unsigned 30-bit integers as numeric keys. This way,
+    // we avoid converting them to strings when we use them as keys in
+    // the JavaScript hash table object.
+    return key is num && JS('bool', '(# & #) === #', key, _mask30, key);
+  }
+
+  int _computeHashCode(var key) {
+    // We force the hash codes to be unsigned 30-bit integers to avoid
+    // issues with problematic keys like '__proto__'. Another option
+    // would be to throw an exception if the hash code isn't a number.
+    return JS('int', '# & #', key.hashCode, _mask30);
+  }
+
+  static bool _hasTableEntry(var table, var key) {
+    var entry = JS('var', '#[#]', table, key);
+    // We take care to only store non-null entries in the table, so we
+    // can check if the table has an entry for the given key with a
+    // simple null check.
+    return entry != null;
+  }
+
+  static _getTableEntry(var table, var key) {
+    var entry = JS('var', '#[#]', table, key);
+    // We store the table itself as the entry to signal that it really
+    // is a null value, so we have to map back to null here.
+    return JS('bool', '# === #', entry, table) ? null : entry;
+  }
+
+  static void _setTableEntry(var table, var key, var value) {
+    // We only store non-null entries in the table, so we have to
+    // change null values to refer to the table itself. Such values
+    // will be recognized and mapped back to null on access.
+    if (value == null) {
+      // Do not update [value] with [table], otherwise our
+      // optimizations could be confused by this opaque object being
+      // now used for more things than storing and fetching from it.
+      JS('void', '#[#] = #', table, key, table);
+    } else {
+      JS('void', '#[#] = #', table, key, value);
+    }
+  }
+
+  static void _deleteTableEntry(var table, var key) {
+    JS('void', 'delete #[#]', table, key);
+  }
+
+  List _getBucket(var table, var key) {
+    var hash = _computeHashCode(key);
+    return JS('var', '#[#]', table, hash);
+  }
+
+  int _findBucketIndex(var bucket, var key) {
+    if (bucket == null) return -1;
+    int length = JS('int', '#.length', bucket);
+    for (int i = 0; i < length; i += 2) {
+      if (JS('var', '#[#]', bucket, i) == key) return i;
+    }
+    return -1;
+  }
+
+  static _newHashTable() {
+    // Create a new JavaScript object to be used as a hash table. Use
+    // Object.create to avoid the properties on Object.prototype
+    // showing up as entries.
+    var table = JS('var', 'Object.create(null)');
+    // Attempt to force the hash table into 'dictionary' mode by
+    // adding a property to it and deleting it again.
+    var temporaryKey = '<non-identifier-key>';
+    _setTableEntry(table, temporaryKey, table);
+    _deleteTableEntry(table, temporaryKey);
+    return table;
+  }
+}
+
+class _IdentityHashMap<K, V> extends _HashMap<K, V> {
+  int _computeHashCode(var key) {
+    // We force the hash codes to be unsigned 30-bit integers to avoid
+    // issues with problematic keys like '__proto__'. Another option
+    // would be to throw an exception if the hash code isn't a number.
+    return JS('int', '# & #', identityHashCode(key), _mask30);
+  }
+
+  int _findBucketIndex(var bucket, var key) {
+    if (bucket == null) return -1;
+    int length = JS('int', '#.length', bucket);
+    for (int i = 0; i < length; i += 2) {
+      if (identical(JS('var', '#[#]', bucket, i), key)) return i;
+    }
+    return -1;
+  }
+}
+
+class _CustomHashMap<K, V> extends _HashMap<K, V> {
+  final _Equality<K> _equals;
+  final _Hasher<K> _hashCode;
+  final _Predicate _validKey;
+
+  _CustomHashMap(this._equals, this._hashCode, bool validKey(potentialKey))
+      : _validKey = (validKey != null) ? validKey : ((v) => v is K);
+
+  V operator [](Object key) {
+    if (!_validKey(key)) return null;
+    return super._get(key);
+  }
+
+  void operator []=(K key, V value) {
+    super._set(key, value);
+  }
+
+  bool containsKey(Object key) {
+    if (!_validKey(key)) return false;
+    return super._containsKey(key);
+  }
+
+  V remove(Object key) {
+    if (!_validKey(key)) return null;
+    return super._remove(key);
+  }
+
+  int _computeHashCode(var key) {
+    // We force the hash codes to be unsigned 30-bit integers to avoid
+    // issues with problematic keys like '__proto__'. Another option
+    // would be to throw an exception if the hash code isn't a number.
+    return JS('int', '# & #', _hashCode(key), _mask30);
+  }
+
+  int _findBucketIndex(var bucket, var key) {
+    if (bucket == null) return -1;
+    int length = JS('int', '#.length', bucket);
+    for (int i = 0; i < length; i += 2) {
+      if (_equals(JS('var', '#[#]', bucket, i), key)) return i;
+    }
+    return -1;
+  }
+}
+
+class _HashMapKeyIterable<E> extends EfficientLengthIterable<E> {
+  final _map;
+  _HashMapKeyIterable(this._map);
+
+  int get length => _map._length;
+  bool get isEmpty => _map._length == 0;
+
+  Iterator<E> get iterator {
+    return new _HashMapKeyIterator<E>(_map, _map._computeKeys());
+  }
+
+  bool contains(Object element) {
+    return _map.containsKey(element);
+  }
+
+  void forEach(void f(E element)) {
+    List keys = _map._computeKeys();
+    for (int i = 0, length = JS('int', '#.length', keys); i < length; i++) {
+      f(JS('var', '#[#]', keys, i));
+      if (JS('bool', '# !== #', keys, _map._keys)) {
+        throw new ConcurrentModificationError(_map);
+      }
+    }
+  }
+}
+
+class _HashMapKeyIterator<E> implements Iterator<E> {
+  final _map;
+  final List _keys;
+  int _offset = 0;
+  E _current;
+
+  _HashMapKeyIterator(this._map, this._keys);
+
+  E get current => _current;
+
+  bool moveNext() {
+    var keys = _keys;
+    int offset = _offset;
+    if (JS('bool', '# !== #', keys, _map._keys)) {
+      throw new ConcurrentModificationError(_map);
+    } else if (offset >= JS('int', '#.length', keys)) {
+      _current = null;
+      return false;
+    } else {
+      _current = JS('var', '#[#]', keys, offset);
+      // TODO(kasperl): For now, we have to tell the type inferrer to
+      // treat the result of doing offset + 1 as an int. Otherwise, we
+      // get unnecessary bailout code.
+      _offset = JS('int', '#', offset + 1);
+      return true;
+    }
+  }
+}
+
+@patch
+class LinkedHashMap<K, V> {
+  @patch
+  factory LinkedHashMap(
+      {bool equals(K key1, K key2),
+      int hashCode(K key),
+      bool isValidKey(potentialKey)}) {
+    if (isValidKey == null) {
+      if (hashCode == null) {
+        if (equals == null) {
+          return new JsLinkedHashMap<K, V>.es6();
+        }
+        hashCode = _defaultHashCode;
+      } else {
+        if (identical(identityHashCode, hashCode) &&
+            identical(identical, equals)) {
+          return new _LinkedIdentityHashMap<K, V>.es6();
+        }
+        if (equals == null) {
+          equals = _defaultEquals;
+        }
+      }
+    } else {
+      if (hashCode == null) {
+        hashCode = _defaultHashCode;
+      }
+      if (equals == null) {
+        equals = _defaultEquals;
+      }
+    }
+    return new _LinkedCustomHashMap<K, V>(equals, hashCode, isValidKey);
+  }
+
+  @patch
+  factory LinkedHashMap.identity() = _LinkedIdentityHashMap<K, V>.es6;
+
+  // Private factory constructor called by generated code for map literals.
+  @pragma('dart2js:noInline')
+  factory LinkedHashMap._literal(List keyValuePairs) {
+    return fillLiteralMap(keyValuePairs, new JsLinkedHashMap<K, V>.es6());
+  }
+
+  // Private factory constructor called by generated code for map literals.
+  @pragma('dart2js:noThrows')
+  @pragma('dart2js:noInline')
+  @pragma('dart2js:noSideEffects')
+  factory LinkedHashMap._empty() {
+    return new JsLinkedHashMap<K, V>.es6();
+  }
+
+  // Private factory static function called by generated code for map literals.
+  // This version is for map literals without type parameters.
+  @pragma('dart2js:noThrows')
+  @pragma('dart2js:noInline')
+  @pragma('dart2js:noSideEffects')
+  static _makeEmpty() => new JsLinkedHashMap();
+
+  // Private factory static function called by generated code for map literals.
+  // This version is for map literals without type parameters.
+  @pragma('dart2js:noInline')
+  static _makeLiteral(keyValuePairs) =>
+      fillLiteralMap(keyValuePairs, new JsLinkedHashMap());
+}
+
+class _LinkedIdentityHashMap<K, V> extends JsLinkedHashMap<K, V> {
+  static bool get _supportsEs6Maps {
+    return JS('returns:bool;depends:none;effects:none;throws:never;gvn:true',
+        'typeof Map != "undefined"');
+  }
+
+  factory _LinkedIdentityHashMap.es6() {
+    return (_USE_ES6_MAPS && _LinkedIdentityHashMap._supportsEs6Maps)
+        ? new _Es6LinkedIdentityHashMap<K, V>()
+        : new _LinkedIdentityHashMap<K, V>();
+  }
+
+  _LinkedIdentityHashMap();
+
+  int internalComputeHashCode(var key) {
+    // We force the hash codes to be unsigned 30-bit integers to avoid
+    // issues with problematic keys like '__proto__'. Another option
+    // would be to throw an exception if the hash code isn't a number.
+    return JS('int', '# & #', identityHashCode(key), _mask30);
+  }
+
+  int internalFindBucketIndex(var bucket, var key) {
+    if (bucket == null) return -1;
+    int length = JS('int', '#.length', bucket);
+    for (int i = 0; i < length; i++) {
+      LinkedHashMapCell cell = JS('var', '#[#]', bucket, i);
+      if (identical(cell.hashMapCellKey, key)) return i;
+    }
+    return -1;
+  }
+}
+
+class _Es6LinkedIdentityHashMap<K, V> extends _LinkedIdentityHashMap<K, V>
+    implements InternalMap {
+  final _map;
+  int _modifications = 0;
+
+  _Es6LinkedIdentityHashMap() : _map = JS('var', 'new Map()');
+
+  int get length => JS('int', '#.size', _map);
+  bool get isEmpty => length == 0;
+  bool get isNotEmpty => !isEmpty;
+
+  Iterable<K> get keys => new _Es6MapIterable<K>(this, true);
+
+  Iterable<V> get values => new _Es6MapIterable<V>(this, false);
+
+  bool containsKey(Object key) {
+    return JS('bool', '#.has(#)', _map, key);
+  }
+
+  bool containsValue(Object value) {
+    return values.any((each) => each == value);
+  }
+
+  void addAll(Map<K, V> other) {
+    other.forEach((K key, V value) {
+      this[key] = value;
+    });
+  }
+
+  V operator [](Object key) {
+    return JS('var', '#.get(#)', _map, key);
+  }
+
+  void operator []=(K key, V value) {
+    JS('var', '#.set(#, #)', _map, key, value);
+    _modified();
+  }
+
+  V putIfAbsent(K key, V ifAbsent()) {
+    if (containsKey(key)) return this[key];
+    V value = ifAbsent();
+    this[key] = value;
+    return value;
+  }
+
+  V remove(Object key) {
+    V value = this[key];
+    JS('bool', '#.delete(#)', _map, key);
+    _modified();
+    return value;
+  }
+
+  void clear() {
+    JS('void', '#.clear()', _map);
+    _modified();
+  }
+
+  void forEach(void action(K key, V value)) {
+    var jsEntries = JS('var', '#.entries()', _map);
+    int modifications = _modifications;
+    while (true) {
+      var next = JS('var', '#.next()', jsEntries);
+      bool done = JS('bool', '#.done', next);
+      if (done) break;
+      var entry = JS('var', '#.value', next);
+      var key = JS('var', '#[0]', entry);
+      var value = JS('var', '#[1]', entry);
+      action(key, value);
+      if (modifications != _modifications) {
+        throw new ConcurrentModificationError(this);
+      }
+    }
+  }
+
+  void _modified() {
+    // Value cycles after 2^30 modifications so that modification counts are
+    // always unboxed (Smi) values. Modification detection will be missed if you
+    // make exactly some multiple of 2^30 modifications between advances of an
+    // iterator.
+    _modifications = _mask30 & (_modifications + 1);
+  }
+}
+
+class _Es6MapIterable<E> extends EfficientLengthIterable<E> {
+  final _map;
+  final bool _isKeys;
+
+  _Es6MapIterable(this._map, this._isKeys);
+
+  int get length => _map.length;
+  bool get isEmpty => _map.isEmpty;
+
+  Iterator<E> get iterator =>
+      new _Es6MapIterator<E>(_map, _map._modifications, _isKeys);
+
+  bool contains(Object element) => _map.containsKey(element);
+
+  void forEach(void f(E element)) {
+    var jsIterator;
+    if (_isKeys) {
+      jsIterator = JS('var', '#.keys()', _map._map);
+    } else {
+      jsIterator = JS('var', '#.values()', _map._map);
+    }
+    int modifications = _map._modifications;
+    while (true) {
+      var next = JS('var', '#.next()', jsIterator);
+      bool done = JS('bool', '#.done', next);
+      if (done) break;
+      var value = JS('var', '#.value', next);
+      f(value);
+      if (modifications != _map._modifications) {
+        throw new ConcurrentModificationError(_map);
+      }
+    }
+  }
+}
+
+class _Es6MapIterator<E> implements Iterator<E> {
+  final _map;
+  final int _modifications;
+  final bool _isKeys;
+  var _jsIterator;
+  var _next;
+  E _current;
+  bool _done;
+
+  _Es6MapIterator(this._map, this._modifications, this._isKeys) {
+    if (_isKeys) {
+      _jsIterator = JS('var', '#.keys()', _map._map);
+    } else {
+      _jsIterator = JS('var', '#.values()', _map._map);
+    }
+    _done = false;
+  }
+
+  E get current => _current;
+
+  bool moveNext() {
+    if (_modifications != _map._modifications) {
+      throw new ConcurrentModificationError(_map);
+    }
+    if (_done) return false;
+    _next = JS('var', '#.next()', _jsIterator);
+    bool done = JS('bool', '#.done', _next);
+    if (done) {
+      _current = null;
+      _done = true;
+      return false;
+    } else {
+      _current = JS('var', '#.value', _next);
+      return true;
+    }
+  }
+}
+
+// TODO(floitsch): use ES6 maps when available.
+class _LinkedCustomHashMap<K, V> extends JsLinkedHashMap<K, V> {
+  final _Equality<K> _equals;
+  final _Hasher<K> _hashCode;
+  final _Predicate _validKey;
+
+  _LinkedCustomHashMap(
+      this._equals, this._hashCode, bool validKey(potentialKey))
+      : _validKey = (validKey != null) ? validKey : ((v) => v is K);
+
+  V operator [](Object key) {
+    if (!_validKey(key)) return null;
+    return super.internalGet(key);
+  }
+
+  void operator []=(K key, V value) {
+    super.internalSet(key, value);
+  }
+
+  bool containsKey(Object key) {
+    if (!_validKey(key)) return false;
+    return super.internalContainsKey(key);
+  }
+
+  V remove(Object key) {
+    if (!_validKey(key)) return null;
+    return super.internalRemove(key);
+  }
+
+  int internalComputeHashCode(var key) {
+    // We force the hash codes to be unsigned 30-bit integers to avoid
+    // issues with problematic keys like '__proto__'. Another option
+    // would be to throw an exception if the hash code isn't a number.
+    return JS('int', '# & #', _hashCode(key), _mask30);
+  }
+
+  int internalFindBucketIndex(var bucket, var key) {
+    if (bucket == null) return -1;
+    int length = JS('int', '#.length', bucket);
+    for (int i = 0; i < length; i++) {
+      LinkedHashMapCell cell = JS('var', '#[#]', bucket, i);
+      if (_equals(cell.hashMapCellKey, key)) return i;
+    }
+    return -1;
+  }
+}
+
+@patch
+class HashSet<E> {
+  @patch
+  factory HashSet(
+      {bool equals(E e1, E e2),
+      int hashCode(E e),
+      bool isValidKey(potentialKey)}) {
+    if (isValidKey == null) {
+      if (hashCode == null) {
+        if (equals == null) {
+          return new _HashSet<E>();
+        }
+        hashCode = _defaultHashCode;
+      } else {
+        if (identical(identityHashCode, hashCode) &&
+            identical(identical, equals)) {
+          return new _IdentityHashSet<E>();
+        }
+        if (equals == null) {
+          equals = _defaultEquals;
+        }
+      }
+    } else {
+      if (hashCode == null) {
+        hashCode = _defaultHashCode;
+      }
+      if (equals == null) {
+        equals = _defaultEquals;
+      }
+    }
+    return new _CustomHashSet<E>(equals, hashCode, isValidKey);
+  }
+
+  @patch
+  factory HashSet.identity() = _IdentityHashSet<E>;
+}
+
+class _HashSet<E> extends _SetBase<E> implements HashSet<E> {
+  int _length = 0;
+
+  // The hash set contents are divided into three parts: one part for
+  // string elements, one for numeric elements, and one for the
+  // rest. String and numeric elements map directly to a sentinel
+  // value, but the rest of the entries are stored in bucket lists of
+  // the form:
+  //
+  //    [element-0, element-1, element-2, ...]
+  //
+  // where all elements in the same bucket share the same hash code.
+  var _strings;
+  var _nums;
+  var _rest;
+
+  // When iterating over the hash set, it is very convenient to have a
+  // list of all the elements. We cache that on the instance and clear
+  // the cache whenever the set changes. This is also used to
+  // guard against concurrent modifications.
+  List _elements;
+
+  _HashSet();
+
+  Set<E> _newSet() => new _HashSet<E>();
+  Set<R> _newSimilarSet<R>() => new _HashSet<R>();
+
+  // Iterable.
+  Iterator<E> get iterator {
+    return new _HashSetIterator<E>(this, _computeElements());
+  }
+
+  int get length => _length;
+  bool get isEmpty => _length == 0;
+  bool get isNotEmpty => !isEmpty;
+
+  bool contains(Object object) {
+    if (_isStringElement(object)) {
+      var strings = _strings;
+      return (strings == null) ? false : _hasTableEntry(strings, object);
+    } else if (_isNumericElement(object)) {
+      var nums = _nums;
+      return (nums == null) ? false : _hasTableEntry(nums, object);
+    } else {
+      return _contains(object);
+    }
+  }
+
+  bool _contains(Object object) {
+    var rest = _rest;
+    if (rest == null) return false;
+    var bucket = _getBucket(rest, object);
+    return _findBucketIndex(bucket, object) >= 0;
+  }
+
+  E lookup(Object object) {
+    if (_isStringElement(object) || _isNumericElement(object)) {
+      return this.contains(object) ? object : null;
+    }
+    return _lookup(object);
+  }
+
+  E _lookup(Object object) {
+    var rest = _rest;
+    if (rest == null) return null;
+    var bucket = _getBucket(rest, object);
+    var index = _findBucketIndex(bucket, object);
+    if (index < 0) return null;
+    return bucket[index];
+  }
+
+  // Collection.
+  bool add(E element) {
+    if (_isStringElement(element)) {
+      var strings = _strings;
+      if (strings == null) _strings = strings = _newHashTable();
+      return _addHashTableEntry(strings, element);
+    } else if (_isNumericElement(element)) {
+      var nums = _nums;
+      if (nums == null) _nums = nums = _newHashTable();
+      return _addHashTableEntry(nums, element);
+    } else {
+      return _add(element);
+    }
+  }
+
+  bool _add(E element) {
+    var rest = _rest;
+    if (rest == null) _rest = rest = _newHashTable();
+    var hash = _computeHashCode(element);
+    var bucket = JS('var', '#[#]', rest, hash);
+    if (bucket == null) {
+      _setTableEntry(rest, hash, JS('var', '[#]', element));
+    } else {
+      int index = _findBucketIndex(bucket, element);
+      if (index >= 0) return false;
+      JS('void', '#.push(#)', bucket, element);
+    }
+    _length++;
+    _elements = null;
+    return true;
+  }
+
+  void addAll(Iterable<E> objects) {
+    for (E each in objects) {
+      add(each);
+    }
+  }
+
+  bool remove(Object object) {
+    if (_isStringElement(object)) {
+      return _removeHashTableEntry(_strings, object);
+    } else if (_isNumericElement(object)) {
+      return _removeHashTableEntry(_nums, object);
+    } else {
+      return _remove(object);
+    }
+  }
+
+  bool _remove(Object object) {
+    var rest = _rest;
+    if (rest == null) return false;
+    var bucket = _getBucket(rest, object);
+    int index = _findBucketIndex(bucket, object);
+    if (index < 0) return false;
+    // TODO(kasperl): Consider getting rid of the bucket list when
+    // the length reaches zero.
+    _length--;
+    _elements = null;
+    // TODO(kasperl): It would probably be faster to move the
+    // element to the end and reduce the length of the bucket list.
+    JS('void', '#.splice(#, 1)', bucket, index);
+    return true;
+  }
+
+  void clear() {
+    if (_length > 0) {
+      _strings = _nums = _rest = _elements = null;
+      _length = 0;
+    }
+  }
+
+  List _computeElements() {
+    if (_elements != null) return _elements;
+    List result = new List(_length);
+    int index = 0;
+
+    // Add all string elements to the list.
+    var strings = _strings;
+    if (strings != null) {
+      var names = JS('var', 'Object.getOwnPropertyNames(#)', strings);
+      int entries = JS('int', '#.length', names);
+      for (int i = 0; i < entries; i++) {
+        String element = JS('String', '#[#]', names, i);
+        JS('void', '#[#] = #', result, index, element);
+        index++;
+      }
+    }
+
+    // Add all numeric elements to the list.
+    var nums = _nums;
+    if (nums != null) {
+      var names = JS('var', 'Object.getOwnPropertyNames(#)', nums);
+      int entries = JS('int', '#.length', names);
+      for (int i = 0; i < entries; i++) {
+        // Object.getOwnPropertyNames returns a list of strings, so we
+        // have to convert the elements back to numbers (+).
+        num element = JS('num', '+#[#]', names, i);
+        JS('void', '#[#] = #', result, index, element);
+        index++;
+      }
+    }
+
+    // Add all the remaining elements to the list.
+    var rest = _rest;
+    if (rest != null) {
+      var names = JS('var', 'Object.getOwnPropertyNames(#)', rest);
+      int entries = JS('int', '#.length', names);
+      for (int i = 0; i < entries; i++) {
+        var entry = JS('String', '#[#]', names, i);
+        var bucket = JS('var', '#[#]', rest, entry);
+        int length = JS('int', '#.length', bucket);
+        for (int i = 0; i < length; i++) {
+          JS('void', '#[#] = #[#]', result, index, bucket, i);
+          index++;
+        }
+      }
+    }
+    assert(index == _length);
+    return _elements = result;
+  }
+
+  bool _addHashTableEntry(var table, E element) {
+    if (_hasTableEntry(table, element)) return false;
+    _setTableEntry(table, element, 0);
+    _length++;
+    _elements = null;
+    return true;
+  }
+
+  bool _removeHashTableEntry(var table, Object element) {
+    if (table != null && _hasTableEntry(table, element)) {
+      _deleteTableEntry(table, element);
+      _length--;
+      _elements = null;
+      return true;
+    } else {
+      return false;
+    }
+  }
+
+  static bool _isStringElement(var element) {
+    return element is String && element != '__proto__';
+  }
+
+  static bool _isNumericElement(var element) {
+    // Only treat unsigned 30-bit integers as numeric elements. This
+    // way, we avoid converting them to strings when we use them as
+    // keys in the JavaScript hash table object.
+    return element is num &&
+        JS('bool', '(# & #) === #', element, _mask30, element);
+  }
+
+  int _computeHashCode(var element) {
+    // We force the hash codes to be unsigned 30-bit integers to avoid
+    // issues with problematic elements like '__proto__'. Another
+    // option would be to throw an exception if the hash code isn't a
+    // number.
+    return JS('int', '# & #', element.hashCode, _mask30);
+  }
+
+  static bool _hasTableEntry(var table, var key) {
+    var entry = JS('var', '#[#]', table, key);
+    // We take care to only store non-null entries in the table, so we
+    // can check if the table has an entry for the given key with a
+    // simple null check.
+    return entry != null;
+  }
+
+  static void _setTableEntry(var table, var key, var value) {
+    assert(value != null);
+    JS('void', '#[#] = #', table, key, value);
+  }
+
+  static void _deleteTableEntry(var table, var key) {
+    JS('void', 'delete #[#]', table, key);
+  }
+
+  List _getBucket(var table, var element) {
+    var hash = _computeHashCode(element);
+    return JS('var', '#[#]', table, hash);
+  }
+
+  int _findBucketIndex(var bucket, var element) {
+    if (bucket == null) return -1;
+    int length = JS('int', '#.length', bucket);
+    for (int i = 0; i < length; i++) {
+      if (JS('var', '#[#]', bucket, i) == element) return i;
+    }
+    return -1;
+  }
+
+  static _newHashTable() {
+    // Create a new JavaScript object to be used as a hash table. Use
+    // Object.create to avoid the properties on Object.prototype
+    // showing up as entries.
+    var table = JS('var', 'Object.create(null)');
+    // Attempt to force the hash table into 'dictionary' mode by
+    // adding a property to it and deleting it again.
+    var temporaryKey = '<non-identifier-key>';
+    _setTableEntry(table, temporaryKey, table);
+    _deleteTableEntry(table, temporaryKey);
+    return table;
+  }
+}
+
+class _IdentityHashSet<E> extends _HashSet<E> {
+  Set<E> _newSet() => new _IdentityHashSet<E>();
+  Set<R> _newSimilarSet<R>() => new _IdentityHashSet<R>();
+
+  int _computeHashCode(var key) {
+    // We force the hash codes to be unsigned 30-bit integers to avoid
+    // issues with problematic keys like '__proto__'. Another option
+    // would be to throw an exception if the hash code isn't a number.
+    return JS('int', '# & #', identityHashCode(key), _mask30);
+  }
+
+  int _findBucketIndex(var bucket, var element) {
+    if (bucket == null) return -1;
+    int length = JS('int', '#.length', bucket);
+    for (int i = 0; i < length; i++) {
+      if (identical(JS('var', '#[#]', bucket, i), element)) return i;
+    }
+    return -1;
+  }
+}
+
+class _CustomHashSet<E> extends _HashSet<E> {
+  _Equality<E> _equality;
+  _Hasher<E> _hasher;
+  _Predicate _validKey;
+  _CustomHashSet(this._equality, this._hasher, bool validKey(potentialKey))
+      : _validKey = (validKey != null) ? validKey : ((x) => x is E);
+
+  Set<E> _newSet() => new _CustomHashSet<E>(_equality, _hasher, _validKey);
+  Set<R> _newSimilarSet<R>() => new _HashSet<R>();
+
+  int _findBucketIndex(var bucket, var element) {
+    if (bucket == null) return -1;
+    int length = JS('int', '#.length', bucket);
+    for (int i = 0; i < length; i++) {
+      if (_equality(JS('var', '#[#]', bucket, i), element)) return i;
+    }
+    return -1;
+  }
+
+  int _computeHashCode(var element) {
+    // We force the hash codes to be unsigned 30-bit integers to avoid
+    // issues with problematic elements like '__proto__'. Another
+    // option would be to throw an exception if the hash code isn't a
+    // number.
+    return JS('int', '# & #', _hasher(element), _mask30);
+  }
+
+  bool add(E object) => super._add(object);
+
+  bool contains(Object object) {
+    if (!_validKey(object)) return false;
+    return super._contains(object);
+  }
+
+  E lookup(Object object) {
+    if (!_validKey(object)) return null;
+    return super._lookup(object);
+  }
+
+  bool remove(Object object) {
+    if (!_validKey(object)) return false;
+    return super._remove(object);
+  }
+}
+
+// TODO(kasperl): Share this code with _HashMapKeyIterator<E>?
+class _HashSetIterator<E> implements Iterator<E> {
+  final _set;
+  final List _elements;
+  int _offset = 0;
+  E _current;
+
+  _HashSetIterator(this._set, this._elements);
+
+  E get current => _current;
+
+  bool moveNext() {
+    var elements = _elements;
+    int offset = _offset;
+    if (JS('bool', '# !== #', elements, _set._elements)) {
+      throw new ConcurrentModificationError(_set);
+    } else if (offset >= JS('int', '#.length', elements)) {
+      _current = null;
+      return false;
+    } else {
+      _current = JS('var', '#[#]', elements, offset);
+      // TODO(kasperl): For now, we have to tell the type inferrer to
+      // treat the result of doing offset + 1 as an int. Otherwise, we
+      // get unnecessary bailout code.
+      _offset = JS('int', '#', offset + 1);
+      return true;
+    }
+  }
+}
+
+@patch
+class LinkedHashSet<E> {
+  @patch
+  factory LinkedHashSet(
+      {bool equals(E e1, E e2),
+      int hashCode(E e),
+      bool isValidKey(potentialKey)}) {
+    if (isValidKey == null) {
+      if (hashCode == null) {
+        if (equals == null) {
+          return new _LinkedHashSet<E>();
+        }
+        hashCode = _defaultHashCode;
+      } else {
+        if (identical(identityHashCode, hashCode) &&
+            identical(identical, equals)) {
+          return new _LinkedIdentityHashSet<E>();
+        }
+        if (equals == null) {
+          equals = _defaultEquals;
+        }
+      }
+    } else {
+      if (hashCode == null) {
+        hashCode = _defaultHashCode;
+      }
+      if (equals == null) {
+        equals = _defaultEquals;
+      }
+    }
+    return new _LinkedCustomHashSet<E>(equals, hashCode, isValidKey);
+  }
+
+  @patch
+  factory LinkedHashSet.identity() = _LinkedIdentityHashSet<E>;
+
+  // Private factory constructor called by generated code for set literals.
+  @pragma('dart2js:noThrows')
+  @pragma('dart2js:noInline')
+  @pragma('dart2js:noSideEffects')
+  factory LinkedHashSet._empty() => new _LinkedHashSet<E>();
+
+  // Private factory constructor called by generated code for set literals.
+  @pragma('dart2js:noInline')
+  factory LinkedHashSet._literal(List values) =>
+      fillLiteralSet(values, new _LinkedHashSet<E>());
+
+  // Private factory static function called by generated code for set literals.
+  // This version is for set literals without type parameters.
+  @pragma('dart2js:noThrows')
+  @pragma('dart2js:noInline')
+  @pragma('dart2js:noSideEffects')
+  static _makeEmpty() => new _LinkedHashSet();
+
+  // Private factory static function called by generated code for set literals.
+  // This version is for set literals without type parameters.
+  @pragma('dart2js:noInline')
+  static _makeLiteral(List values) =>
+      fillLiteralSet(values, new _LinkedHashSet());
+}
+
+class _LinkedHashSet<E> extends _SetBase<E> implements LinkedHashSet<E> {
+  int _length = 0;
+
+  // The hash set contents are divided into three parts: one part for
+  // string elements, one for numeric elements, and one for the
+  // rest. String and numeric elements map directly to their linked
+  // cells, but the rest of the entries are stored in bucket lists of
+  // the form:
+  //
+  //    [cell-0, cell-1, ...]
+  //
+  // where all elements in the same bucket share the same hash code.
+  var _strings;
+  var _nums;
+  var _rest;
+
+  // The elements are stored in cells that are linked together
+  // to form a double linked list.
+  _LinkedHashSetCell _first;
+  _LinkedHashSetCell _last;
+
+  // We track the number of modifications done to the element set to
+  // be able to throw when the set is modified while being iterated
+  // over.
+  int _modifications = 0;
+
+  _LinkedHashSet();
+
+  Set<E> _newSet() => new _LinkedHashSet<E>();
+  Set<R> _newSimilarSet<R>() => new _LinkedHashSet<R>();
+
+  void _unsupported(String operation) {
+    throw 'LinkedHashSet: unsupported $operation';
+  }
+
+  // Iterable.
+  Iterator<E> get iterator {
+    return new _LinkedHashSetIterator(this, _modifications);
+  }
+
+  int get length => _length;
+  bool get isEmpty => _length == 0;
+  bool get isNotEmpty => !isEmpty;
+
+  bool contains(Object object) {
+    if (_isStringElement(object)) {
+      var strings = _strings;
+      if (strings == null) return false;
+      _LinkedHashSetCell cell = _getTableEntry(strings, object);
+      return cell != null;
+    } else if (_isNumericElement(object)) {
+      var nums = _nums;
+      if (nums == null) return false;
+      _LinkedHashSetCell cell = _getTableEntry(nums, object);
+      return cell != null;
+    } else {
+      return _contains(object);
+    }
+  }
+
+  bool _contains(Object object) {
+    var rest = _rest;
+    if (rest == null) return false;
+    var bucket = _getBucket(rest, object);
+    return _findBucketIndex(bucket, object) >= 0;
+  }
+
+  E lookup(Object object) {
+    if (_isStringElement(object) || _isNumericElement(object)) {
+      return this.contains(object) ? object : null;
+    } else {
+      return _lookup(object);
+    }
+  }
+
+  E _lookup(Object object) {
+    var rest = _rest;
+    if (rest == null) return null;
+    var bucket = _getBucket(rest, object);
+    var index = _findBucketIndex(bucket, object);
+    if (index < 0) return null;
+    return bucket[index]._element;
+  }
+
+  void forEach(void action(E element)) {
+    _LinkedHashSetCell cell = _first;
+    int modifications = _modifications;
+    while (cell != null) {
+      action(cell._element);
+      if (modifications != _modifications) {
+        throw new ConcurrentModificationError(this);
+      }
+      cell = cell._next;
+    }
+  }
+
+  E get first {
+    if (_first == null) throw new StateError("No elements");
+    return _first._element;
+  }
+
+  E get last {
+    if (_last == null) throw new StateError("No elements");
+    return _last._element;
+  }
+
+  // Collection.
+  bool add(E element) {
+    if (_isStringElement(element)) {
+      var strings = _strings;
+      if (strings == null) _strings = strings = _newHashTable();
+      return _addHashTableEntry(strings, element);
+    } else if (_isNumericElement(element)) {
+      var nums = _nums;
+      if (nums == null) _nums = nums = _newHashTable();
+      return _addHashTableEntry(nums, element);
+    } else {
+      return _add(element);
+    }
+  }
+
+  bool _add(E element) {
+    var rest = _rest;
+    if (rest == null) _rest = rest = _newHashTable();
+    var hash = _computeHashCode(element);
+    var bucket = JS('var', '#[#]', rest, hash);
+    if (bucket == null) {
+      _LinkedHashSetCell cell = _newLinkedCell(element);
+      _setTableEntry(rest, hash, JS('var', '[#]', cell));
+    } else {
+      int index = _findBucketIndex(bucket, element);
+      if (index >= 0) return false;
+      _LinkedHashSetCell cell = _newLinkedCell(element);
+      JS('void', '#.push(#)', bucket, cell);
+    }
+    return true;
+  }
+
+  bool remove(Object object) {
+    if (_isStringElement(object)) {
+      return _removeHashTableEntry(_strings, object);
+    } else if (_isNumericElement(object)) {
+      return _removeHashTableEntry(_nums, object);
+    } else {
+      return _remove(object);
+    }
+  }
+
+  bool _remove(Object object) {
+    var rest = _rest;
+    if (rest == null) return false;
+    var bucket = _getBucket(rest, object);
+    int index = _findBucketIndex(bucket, object);
+    if (index < 0) return false;
+    // Use splice to remove the [cell] element at the index and
+    // unlink it.
+    _LinkedHashSetCell cell = JS('var', '#.splice(#, 1)[0]', bucket, index);
+    _unlinkCell(cell);
+    return true;
+  }
+
+  void removeWhere(bool test(E element)) {
+    _filterWhere(test, true);
+  }
+
+  void retainWhere(bool test(E element)) {
+    _filterWhere(test, false);
+  }
+
+  void _filterWhere(bool test(E element), bool removeMatching) {
+    _LinkedHashSetCell cell = _first;
+    while (cell != null) {
+      E element = cell._element;
+      _LinkedHashSetCell next = cell._next;
+      int modifications = _modifications;
+      bool shouldRemove = (removeMatching == test(element));
+      if (modifications != _modifications) {
+        throw new ConcurrentModificationError(this);
+      }
+      if (shouldRemove) remove(element);
+      cell = next;
+    }
+  }
+
+  void clear() {
+    if (_length > 0) {
+      _strings = _nums = _rest = _first = _last = null;
+      _length = 0;
+      _modified();
+    }
+  }
+
+  bool _addHashTableEntry(var table, E element) {
+    _LinkedHashSetCell cell = _getTableEntry(table, element);
+    if (cell != null) return false;
+    _setTableEntry(table, element, _newLinkedCell(element));
+    return true;
+  }
+
+  bool _removeHashTableEntry(var table, Object element) {
+    if (table == null) return false;
+    _LinkedHashSetCell cell = _getTableEntry(table, element);
+    if (cell == null) return false;
+    _unlinkCell(cell);
+    _deleteTableEntry(table, element);
+    return true;
+  }
+
+  void _modified() {
+    // Value cycles after 2^30 modifications. If you keep hold of an
+    // iterator for that long, you might miss a modification
+    // detection, and iteration can go sour. Don't do that.
+    _modifications = _mask30 & (_modifications + 1);
+  }
+
+  // Create a new cell and link it in as the last one in the list.
+  _LinkedHashSetCell _newLinkedCell(E element) {
+    _LinkedHashSetCell cell = new _LinkedHashSetCell(element);
+    if (_first == null) {
+      _first = _last = cell;
+    } else {
+      _LinkedHashSetCell last = _last;
+      cell._previous = last;
+      _last = last._next = cell;
+    }
+    _length++;
+    _modified();
+    return cell;
+  }
+
+  // Unlink the given cell from the linked list of cells.
+  void _unlinkCell(_LinkedHashSetCell cell) {
+    _LinkedHashSetCell previous = cell._previous;
+    _LinkedHashSetCell next = cell._next;
+    if (previous == null) {
+      assert(cell == _first);
+      _first = next;
+    } else {
+      previous._next = next;
+    }
+    if (next == null) {
+      assert(cell == _last);
+      _last = previous;
+    } else {
+      next._previous = previous;
+    }
+    _length--;
+    _modified();
+  }
+
+  static bool _isStringElement(var element) {
+    return element is String && element != '__proto__';
+  }
+
+  static bool _isNumericElement(var element) {
+    // Only treat unsigned 30-bit integers as numeric elements. This
+    // way, we avoid converting them to strings when we use them as
+    // keys in the JavaScript hash table object.
+    return element is num &&
+        JS('bool', '(# & #) === #', element, _mask30, element);
+  }
+
+  int _computeHashCode(var element) {
+    // We force the hash codes to be unsigned 30-bit integers to avoid
+    // issues with problematic elements like '__proto__'. Another
+    // option would be to throw an exception if the hash code isn't a
+    // number.
+    return JS('int', '# & #', element.hashCode, _mask30);
+  }
+
+  static _getTableEntry(var table, var key) {
+    return JS('var', '#[#]', table, key);
+  }
+
+  static void _setTableEntry(var table, var key, var value) {
+    assert(value != null);
+    JS('void', '#[#] = #', table, key, value);
+  }
+
+  static void _deleteTableEntry(var table, var key) {
+    JS('void', 'delete #[#]', table, key);
+  }
+
+  List _getBucket(var table, var element) {
+    var hash = _computeHashCode(element);
+    return JS('var', '#[#]', table, hash);
+  }
+
+  int _findBucketIndex(var bucket, var element) {
+    if (bucket == null) return -1;
+    int length = JS('int', '#.length', bucket);
+    for (int i = 0; i < length; i++) {
+      _LinkedHashSetCell cell = JS('var', '#[#]', bucket, i);
+      if (cell._element == element) return i;
+    }
+    return -1;
+  }
+
+  static _newHashTable() {
+    // Create a new JavaScript object to be used as a hash table. Use
+    // Object.create to avoid the properties on Object.prototype
+    // showing up as entries.
+    var table = JS('var', 'Object.create(null)');
+    // Attempt to force the hash table into 'dictionary' mode by
+    // adding a property to it and deleting it again.
+    var temporaryKey = '<non-identifier-key>';
+    _setTableEntry(table, temporaryKey, table);
+    _deleteTableEntry(table, temporaryKey);
+    return table;
+  }
+}
+
+class _LinkedIdentityHashSet<E> extends _LinkedHashSet<E> {
+  Set<E> _newSet() => new _LinkedIdentityHashSet<E>();
+  Set<R> _newSimilarSet<R>() => new _LinkedIdentityHashSet<R>();
+
+  int _computeHashCode(var key) {
+    // We force the hash codes to be unsigned 30-bit integers to avoid
+    // issues with problematic keys like '__proto__'. Another option
+    // would be to throw an exception if the hash code isn't a number.
+    return JS('int', '# & #', identityHashCode(key), _mask30);
+  }
+
+  int _findBucketIndex(var bucket, var element) {
+    if (bucket == null) return -1;
+    int length = JS('int', '#.length', bucket);
+    for (int i = 0; i < length; i++) {
+      _LinkedHashSetCell cell = JS('var', '#[#]', bucket, i);
+      if (identical(cell._element, element)) return i;
+    }
+    return -1;
+  }
+}
+
+class _LinkedCustomHashSet<E> extends _LinkedHashSet<E> {
+  _Equality<E> _equality;
+  _Hasher<E> _hasher;
+  _Predicate _validKey;
+  _LinkedCustomHashSet(
+      this._equality, this._hasher, bool validKey(potentialKey))
+      : _validKey = (validKey != null) ? validKey : ((x) => x is E);
+
+  Set<E> _newSet() =>
+      new _LinkedCustomHashSet<E>(_equality, _hasher, _validKey);
+  Set<R> _newSimilarSet<R>() => new _LinkedHashSet<R>();
+
+  int _findBucketIndex(var bucket, var element) {
+    if (bucket == null) return -1;
+    int length = JS('int', '#.length', bucket);
+    for (int i = 0; i < length; i++) {
+      _LinkedHashSetCell cell = JS('var', '#[#]', bucket, i);
+      if (_equality(cell._element, element)) return i;
+    }
+    return -1;
+  }
+
+  int _computeHashCode(var element) {
+    // We force the hash codes to be unsigned 30-bit integers to avoid
+    // issues with problematic elements like '__proto__'. Another
+    // option would be to throw an exception if the hash code isn't a
+    // number.
+    return JS('int', '# & #', _hasher(element), _mask30);
+  }
+
+  bool add(E element) => super._add(element);
+
+  bool contains(Object object) {
+    if (!_validKey(object)) return false;
+    return super._contains(object);
+  }
+
+  E lookup(Object object) {
+    if (!_validKey(object)) return null;
+    return super._lookup(object);
+  }
+
+  bool remove(Object object) {
+    if (!_validKey(object)) return false;
+    return super._remove(object);
+  }
+
+  bool containsAll(Iterable<Object> elements) {
+    for (Object element in elements) {
+      if (!_validKey(element) || !this.contains(element)) return false;
+    }
+    return true;
+  }
+
+  void removeAll(Iterable<Object> elements) {
+    for (Object element in elements) {
+      if (_validKey(element)) {
+        super._remove(element);
+      }
+    }
+  }
+}
+
+class _LinkedHashSetCell {
+  final _element;
+
+  _LinkedHashSetCell _next;
+  _LinkedHashSetCell _previous;
+
+  _LinkedHashSetCell(this._element);
+}
+
+// TODO(kasperl): Share this code with LinkedHashMapKeyIterator<E>?
+class _LinkedHashSetIterator<E> implements Iterator<E> {
+  final _set;
+  final int _modifications;
+  _LinkedHashSetCell _cell;
+  E _current;
+
+  _LinkedHashSetIterator(this._set, this._modifications) {
+    _cell = _set._first;
+  }
+
+  E get current => _current;
+
+  bool moveNext() {
+    if (_modifications != _set._modifications) {
+      throw new ConcurrentModificationError(_set);
+    } else if (_cell == null) {
+      _current = null;
+      return false;
+    } else {
+      _current = _cell._element;
+      _cell = _cell._next;
+      return true;
+    }
+  }
+}
+
+@patch
+abstract class _SplayTree<K, Node extends _SplayTreeNode<K>> {
+  @patch
+  Node _splayMin(Node node) {
+    Node current = node;
+    while (current.left != null) {
+      Node left = current.left;
+      current.left = left.right;
+      left.right = current;
+      current = left;
+    }
+    return current;
+  }
+
+  @patch
+  Node _splayMax(Node node) {
+    Node current = node;
+    while (current.right != null) {
+      Node right = current.right;
+      current.right = right.left;
+      right.left = current;
+      current = right;
+    }
+    return current;
+  }
+}
diff --git a/sdk_nnbd/lib/_internal/js_runtime/lib/constant_map.dart b/sdk_nnbd/lib/_internal/js_runtime/lib/constant_map.dart
new file mode 100644
index 0000000..f7c7936
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_runtime/lib/constant_map.dart
@@ -0,0 +1,222 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of _js_helper;
+
+class ConstantMapView<K, V> extends UnmodifiableMapView<K, V>
+    implements ConstantMap<K, V> {
+  ConstantMapView(Map<K, V> base) : super(base);
+}
+
+abstract class ConstantMap<K, V> implements Map<K, V> {
+  // Used to create unmodifiable maps from other maps.
+  factory ConstantMap.from(Map other) {
+    List keys = new List<K>.from(other.keys);
+    bool allStrings = true;
+    for (var k in keys) {
+      if (k is! String) {
+        allStrings = false;
+        break;
+      }
+    }
+    if (allStrings) {
+      bool containsProto = false;
+      var protoValue = null;
+      var object = JS('=Object', '{}');
+      int length = 0;
+      for (var k in keys) {
+        V v = other[k];
+        if (k != '__proto__') {
+          if (!jsHasOwnProperty(object, k)) length++;
+          JS('void', '#[#] = #', object, k, v);
+        } else {
+          containsProto = true;
+          protoValue = v;
+        }
+      }
+      if (containsProto) {
+        length++;
+        return new ConstantProtoMap<K, V>._(length, object, keys, protoValue);
+      }
+      return new ConstantStringMap<K, V>._(length, object, keys);
+    }
+    // TODO(lrn): Make a proper unmodifiable map implementation.
+    return new ConstantMapView<K, V>(new Map.from(other));
+  }
+
+  const ConstantMap._();
+
+  Map<RK, RV> cast<RK, RV>() => Map.castFrom<K, V, RK, RV>(this);
+  bool get isEmpty => length == 0;
+
+  bool get isNotEmpty => !isEmpty;
+
+  String toString() => MapBase.mapToString(this);
+
+  static Null _throwUnmodifiable() {
+    throw new UnsupportedError('Cannot modify unmodifiable Map');
+  }
+
+  void operator []=(K key, V val) => _throwUnmodifiable();
+  V putIfAbsent(K key, V ifAbsent()) => _throwUnmodifiable();
+  V remove(Object key) => _throwUnmodifiable();
+  void clear() => _throwUnmodifiable();
+  void addAll(Map<K, V> other) => _throwUnmodifiable();
+
+  Iterable<MapEntry<K, V>> get entries sync* {
+    for (var key in keys) yield new MapEntry<K, V>(key, this[key]);
+  }
+
+  void addEntries(Iterable<MapEntry<K, V>> entries) {
+    for (var entry in entries) this[entry.key] = entry.value;
+  }
+
+  Map<K2, V2> map<K2, V2>(MapEntry<K2, V2> transform(K key, V value)) {
+    var result = <K2, V2>{};
+    this.forEach((K key, V value) {
+      var entry = transform(key, value);
+      result[entry.key] = entry.value;
+    });
+    return result;
+  }
+
+  V update(K key, V update(V value), {V ifAbsent()}) {
+    _throwUnmodifiable();
+  }
+
+  void updateAll(V update(K key, V value)) {
+    _throwUnmodifiable();
+  }
+
+  void removeWhere(bool test(K key, V value)) {
+    _throwUnmodifiable();
+  }
+}
+
+class ConstantStringMap<K, V> extends ConstantMap<K, V> {
+  // This constructor is not used for actual compile-time constants.
+  // The instantiation of constant maps is shortcut by the compiler.
+  const ConstantStringMap._(this._length, this._jsObject, this._keys)
+      : super._();
+
+  // TODO(18131): Ensure type inference knows the precise types of the fields.
+  final int _length;
+  // A constant map is backed by a JavaScript object.
+  final _jsObject;
+  final List<K> _keys;
+
+  int get length => JS('JSUInt31', '#', _length);
+  List<K> get _keysArray => JS('JSUnmodifiableArray', '#', _keys);
+
+  bool containsValue(Object needle) {
+    return values.any((V value) => value == needle);
+  }
+
+  bool containsKey(Object key) {
+    if (key is! String) return false;
+    if ('__proto__' == key) return false;
+    return jsHasOwnProperty(_jsObject, key);
+  }
+
+  V operator [](Object key) {
+    if (!containsKey(key)) return null;
+    return JS('', '#', _fetch(key));
+  }
+
+  // [_fetch] is the indexer for keys for which `containsKey(key)` is true.
+  _fetch(key) => jsPropertyAccess(_jsObject, key);
+
+  void forEach(void f(K key, V value)) {
+    // Use a JS 'cast' to get efficient loop.  Type inference doesn't get this
+    // since constant map representation is chosen after type inference and the
+    // instantiation is shortcut by the compiler.
+    var keys = _keysArray;
+    for (int i = 0; i < keys.length; i++) {
+      var key = keys[i];
+      f(key, _fetch(key));
+    }
+  }
+
+  Iterable<K> get keys {
+    return new _ConstantMapKeyIterable<K>(this);
+  }
+
+  Iterable<V> get values {
+    return new MappedIterable<K, V>(_keysArray, (key) => _fetch(key));
+  }
+}
+
+class ConstantProtoMap<K, V> extends ConstantStringMap<K, V> {
+  // This constructor is not used.  The instantiation is shortcut by the
+  // compiler. It is here to make the uninitialized final fields legal.
+  ConstantProtoMap._(length, jsObject, keys, this._protoValue)
+      : super._(length, jsObject, keys);
+
+  final V _protoValue;
+
+  bool containsKey(Object key) {
+    if (key is! String) return false;
+    if ('__proto__' == key) return true;
+    return jsHasOwnProperty(_jsObject, key);
+  }
+
+  _fetch(key) =>
+      '__proto__' == key ? _protoValue : jsPropertyAccess(_jsObject, key);
+}
+
+class _ConstantMapKeyIterable<K> extends Iterable<K> {
+  ConstantStringMap<K, dynamic> _map;
+  _ConstantMapKeyIterable(this._map);
+
+  Iterator<K> get iterator => _map._keysArray.iterator;
+
+  int get length => _map._keysArray.length;
+}
+
+class GeneralConstantMap<K, V> extends ConstantMap<K, V> {
+  // This constructor is not used.  The instantiation is shortcut by the
+  // compiler. It is here to make the uninitialized final fields legal.
+  GeneralConstantMap(this._jsData) : super._();
+
+  // [_jsData] holds a key-value pair list.
+  final _jsData;
+
+  // We cannot create the backing map on creation since hashCode interceptors
+  // have not been defined when constants are created.
+  Map<K, V> _getMap() {
+    LinkedHashMap<K, V> backingMap = JS('LinkedHashMap|Null', r'#.$map', this);
+    if (backingMap == null) {
+      backingMap = new JsLinkedHashMap<K, V>();
+      fillLiteralMap(_jsData, backingMap);
+      JS('', r'#.$map = #', this, backingMap);
+    }
+    return backingMap;
+  }
+
+  bool containsValue(Object needle) {
+    return _getMap().containsValue(needle);
+  }
+
+  bool containsKey(Object key) {
+    return _getMap().containsKey(key);
+  }
+
+  V operator [](Object key) {
+    return _getMap()[key];
+  }
+
+  void forEach(void f(K key, V value)) {
+    _getMap().forEach(f);
+  }
+
+  Iterable<K> get keys {
+    return _getMap().keys;
+  }
+
+  Iterable<V> get values {
+    return _getMap().values;
+  }
+
+  int get length => _getMap().length;
+}
diff --git a/sdk_nnbd/lib/_internal/js_runtime/lib/convert_patch.dart b/sdk_nnbd/lib/_internal/js_runtime/lib/convert_patch.dart
new file mode 100644
index 0000000..fa6a0b0
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_runtime/lib/convert_patch.dart
@@ -0,0 +1,502 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Patch file for dart:convert library.
+
+import 'dart:_js_helper' show argumentErrorValue, patch;
+import 'dart:_foreign_helper' show JS;
+import 'dart:_interceptors' show JSArray, JSExtendableArray;
+import 'dart:_internal' show MappedIterable, ListIterable;
+import 'dart:collection' show LinkedHashMap, MapBase;
+import 'dart:_native_typed_data' show NativeUint8List;
+
+/// Parses [json] and builds the corresponding parsed JSON value.
+///
+/// Parsed JSON values Nare of the types [num], [String], [bool], [Null],
+/// [List]s of parsed JSON values or [Map]s from [String] to parsed
+/// JSON values.
+///
+/// The optional [reviver] function, if provided, is called once for each object
+/// or list property parsed. The arguments are the property name ([String]) or
+/// list index ([int]), and the value is the parsed value.  The return value of
+/// the reviver will be used as the value of that property instead of the parsed
+/// value.  The top level value is passed to the reviver with the empty string
+/// as a key.
+///
+/// Throws [FormatException] if the input is not valid JSON text.
+@patch
+_parseJson(String source, reviver(key, value)) {
+  if (source is! String) throw argumentErrorValue(source);
+
+  var parsed;
+  try {
+    parsed = JS('=Object|JSExtendableArray|Null|bool|num|String',
+        'JSON.parse(#)', source);
+  } catch (e) {
+    throw new FormatException(JS('String', 'String(#)', e));
+  }
+
+  if (reviver == null) {
+    return _convertJsonToDartLazy(parsed);
+  } else {
+    return _convertJsonToDart(parsed, reviver);
+  }
+}
+
+/// Walks the raw JavaScript value [json], replacing JavaScript Objects with
+/// Maps. [json] is expected to be freshly allocated so elements can be replaced
+/// in-place.
+_convertJsonToDart(json, reviver(key, value)) {
+  assert(reviver != null);
+  walk(e) {
+    // JavaScript null, string, number, bool are in the correct representation.
+    if (JS('bool', '# == null', e) || JS('bool', 'typeof # != "object"', e)) {
+      return e;
+    }
+
+    // This test is needed to avoid identifying '{"__proto__":[]}' as an Array.
+    // TODO(sra): Replace this test with cheaper '#.constructor === Array' when
+    // bug 621 below is fixed.
+    if (JS('bool', 'Object.getPrototypeOf(#) === Array.prototype', e)) {
+      // In-place update of the elements since JS Array is a Dart List.
+      for (int i = 0; i < JS('int', '#.length', e); i++) {
+        // Use JS indexing to avoid range checks.  We know this is the only
+        // reference to the list, but the compiler will likely never be able to
+        // tell that this instance of the list cannot have its length changed by
+        // the reviver even though it later will be passed to the reviver at the
+        // outer level.
+        var item = JS('', '#[#]', e, i);
+        JS('', '#[#]=#', e, i, reviver(i, walk(item)));
+      }
+      return e;
+    }
+
+    // Otherwise it is a plain object, so copy to a JSON map, so we process
+    // and revive all entries recursively.
+    _JsonMap map = new _JsonMap(e);
+    var processed = map._processed;
+    List<String> keys = map._computeKeys();
+    for (int i = 0; i < keys.length; i++) {
+      String key = keys[i];
+      var revived = reviver(key, walk(JS('', '#[#]', e, key)));
+      JS('', '#[#]=#', processed, key, revived);
+    }
+
+    // Update the JSON map structure so future access is cheaper.
+    map._original = processed; // Don't keep two objects around.
+    return map;
+  }
+
+  return reviver(null, walk(json));
+}
+
+_convertJsonToDartLazy(object) {
+  // JavaScript null and undefined are represented as null.
+  if (object == null) return null;
+
+  // JavaScript string, number, bool already has the correct representation.
+  if (JS('bool', 'typeof # != "object"', object)) {
+    return object;
+  }
+
+  // This test is needed to avoid identifying '{"__proto__":[]}' as an array.
+  // TODO(sra): Replace this test with cheaper '#.constructor === Array' when
+  // bug https://code.google.com/p/v8/issues/detail?id=621 is fixed.
+  if (JS('bool', 'Object.getPrototypeOf(#) !== Array.prototype', object)) {
+    return new _JsonMap(object);
+  }
+
+  // Update the elements in place since JS arrays are Dart lists.
+  for (int i = 0; i < JS('int', '#.length', object); i++) {
+    // Use JS indexing to avoid range checks.  We know this is the only
+    // reference to the list, but the compiler will likely never be able to
+    // tell that this instance of the list cannot have its length changed by
+    // the reviver even though it later will be passed to the reviver at the
+    // outer level.
+    var item = JS('', '#[#]', object, i);
+    JS('', '#[#]=#', object, i, _convertJsonToDartLazy(item));
+  }
+  return object;
+}
+
+class _JsonMap extends MapBase<String, dynamic> {
+  // The original JavaScript object remains unchanged until
+  // the map is eventually upgraded, in which case we null it
+  // out to reclaim the memory used by it.
+  var _original;
+
+  // We keep track of the map entries that we have already
+  // processed by adding them to a separate JavaScript object.
+  var _processed = _newJavaScriptObject();
+
+  // If the data slot isn't null, it represents either the list
+  // of keys (for non-upgraded JSON maps) or the upgraded map.
+  var _data = null;
+
+  _JsonMap(this._original);
+
+  operator [](key) {
+    if (_isUpgraded) {
+      return _upgradedMap[key];
+    } else if (key is! String) {
+      return null;
+    } else {
+      var result = _getProperty(_processed, key);
+      if (_isUnprocessed(result)) result = _process(key);
+      return result;
+    }
+  }
+
+  int get length => _isUpgraded ? _upgradedMap.length : _computeKeys().length;
+
+  bool get isEmpty => length == 0;
+  bool get isNotEmpty => length > 0;
+
+  Iterable<String> get keys {
+    if (_isUpgraded) return _upgradedMap.keys;
+    return new _JsonMapKeyIterable(this);
+  }
+
+  Iterable get values {
+    if (_isUpgraded) return _upgradedMap.values;
+    return new MappedIterable(_computeKeys(), (each) => this[each]);
+  }
+
+  operator []=(key, value) {
+    if (_isUpgraded) {
+      _upgradedMap[key] = value;
+    } else if (containsKey(key)) {
+      var processed = _processed;
+      _setProperty(processed, key, value);
+      var original = _original;
+      if (!identical(original, processed)) {
+        _setProperty(original, key, null); // Reclaim memory.
+      }
+    } else {
+      _upgrade()[key] = value;
+    }
+  }
+
+  void addAll(Map<String, dynamic> other) {
+    other.forEach((key, value) {
+      this[key] = value;
+    });
+  }
+
+  bool containsValue(value) {
+    if (_isUpgraded) return _upgradedMap.containsValue(value);
+    List<String> keys = _computeKeys();
+    for (int i = 0; i < keys.length; i++) {
+      String key = keys[i];
+      if (this[key] == value) return true;
+    }
+    return false;
+  }
+
+  bool containsKey(key) {
+    if (_isUpgraded) return _upgradedMap.containsKey(key);
+    if (key is! String) return false;
+    return _hasProperty(_original, key);
+  }
+
+  putIfAbsent(key, ifAbsent()) {
+    if (containsKey(key)) return this[key];
+    var value = ifAbsent();
+    this[key] = value;
+    return value;
+  }
+
+  remove(Object key) {
+    if (!_isUpgraded && !containsKey(key)) return null;
+    return _upgrade().remove(key);
+  }
+
+  void clear() {
+    if (_isUpgraded) {
+      _upgradedMap.clear();
+    } else {
+      if (_data != null) {
+        // Clear the list of keys to make sure we force
+        // a concurrent modification error if anyone is
+        // currently iterating over it.
+        _data.clear();
+      }
+      _original = _processed = null;
+      _data = {};
+    }
+  }
+
+  void forEach(void f(String key, value)) {
+    if (_isUpgraded) return _upgradedMap.forEach(f);
+    List<String> keys = _computeKeys();
+    for (int i = 0; i < keys.length; i++) {
+      String key = keys[i];
+
+      // Compute the value under the assumption that the property
+      // is present but potentially not processed.
+      var value = _getProperty(_processed, key);
+      if (_isUnprocessed(value)) {
+        value = _convertJsonToDartLazy(_getProperty(_original, key));
+        _setProperty(_processed, key, value);
+      }
+
+      // Do the callback.
+      f(key, value);
+
+      // Check if invoking the callback function changed
+      // the key set. If so, throw an exception.
+      if (!identical(keys, _data)) {
+        throw new ConcurrentModificationError(this);
+      }
+    }
+  }
+
+  // ------------------------------------------
+  // Private helper methods.
+  // ------------------------------------------
+
+  bool get _isUpgraded => _processed == null;
+
+  Map<String, dynamic> get _upgradedMap {
+    assert(_isUpgraded);
+    // 'cast' the union type to LinkedHashMap.  It would be even better if we
+    // could 'cast' to the implementation type, since LinkedHashMap includes
+    // _JsonMap.
+    return JS('LinkedHashMap', '#', _data);
+  }
+
+  List<String> _computeKeys() {
+    assert(!_isUpgraded);
+    List keys = _data;
+    if (keys == null) {
+      keys = _data = new JSArray<String>.typed(_getPropertyNames(_original));
+    }
+    return JS('JSExtendableArray', '#', keys);
+  }
+
+  Map<String, dynamic> _upgrade() {
+    if (_isUpgraded) return _upgradedMap;
+
+    // Copy all the (key, value) pairs to a freshly allocated
+    // linked hash map thus preserving the ordering.
+    var result = <String, dynamic>{};
+    List<String> keys = _computeKeys();
+    for (int i = 0; i < keys.length; i++) {
+      String key = keys[i];
+      result[key] = this[key];
+    }
+
+    // We only upgrade when we need to extend the map, so we can
+    // safely force a concurrent modification error in case
+    // someone is iterating over the map here.
+    if (keys.isEmpty) {
+      keys.add(null);
+    } else {
+      keys.clear();
+    }
+
+    // Clear out the associated JavaScript objects and mark the
+    // map as having been upgraded.
+    _original = _processed = null;
+    _data = result;
+    assert(_isUpgraded);
+    return result;
+  }
+
+  _process(String key) {
+    if (!_hasProperty(_original, key)) return null;
+    var result = _convertJsonToDartLazy(_getProperty(_original, key));
+    return _setProperty(_processed, key, result);
+  }
+
+  // ------------------------------------------
+  // Private JavaScript helper methods.
+  // ------------------------------------------
+
+  static bool _hasProperty(object, String key) =>
+      JS('bool', 'Object.prototype.hasOwnProperty.call(#,#)', object, key);
+  static _getProperty(object, String key) => JS('', '#[#]', object, key);
+  static _setProperty(object, String key, value) =>
+      JS('', '#[#]=#', object, key, value);
+  static List _getPropertyNames(object) =>
+      JS('JSExtendableArray', 'Object.keys(#)', object);
+  static bool _isUnprocessed(object) =>
+      JS('bool', 'typeof(#)=="undefined"', object);
+  static _newJavaScriptObject() => JS('=Object', 'Object.create(null)');
+}
+
+class _JsonMapKeyIterable extends ListIterable<String> {
+  final _JsonMap _parent;
+
+  _JsonMapKeyIterable(this._parent);
+
+  int get length => _parent.length;
+
+  String elementAt(int index) {
+    return _parent._isUpgraded
+        ? _parent.keys.elementAt(index)
+        : _parent._computeKeys()[index];
+  }
+
+  /// Although [ListIterable] defines its own iterator, we return the iterator
+  /// of the underlying list [_keys] in order to propagate
+  /// [ConcurrentModificationError]s.
+  Iterator<String> get iterator {
+    return _parent._isUpgraded
+        ? _parent.keys.iterator
+        : _parent._computeKeys().iterator;
+  }
+
+  /// Delegate to [parent.containsKey] to ensure the performance expected
+  /// from [Map.keys.containsKey].
+  bool contains(Object key) => _parent.containsKey(key);
+}
+
+@patch
+class JsonDecoder {
+  @patch
+  StringConversionSink startChunkedConversion(Sink<Object> sink) {
+    return new _JsonDecoderSink(_reviver, sink);
+  }
+}
+
+/// Implements the chunked conversion from a JSON string to its corresponding
+/// object.
+///
+/// The sink only creates one object, but its input can be chunked.
+// TODO(floitsch): don't accumulate everything before starting to decode.
+class _JsonDecoderSink extends _StringSinkConversionSink {
+  final Function(Object key, Object value) _reviver;
+  final Sink<Object> _sink;
+
+  _JsonDecoderSink(this._reviver, this._sink) : super(new StringBuffer(''));
+
+  void close() {
+    super.close();
+    StringBuffer buffer = _stringSink;
+    String accumulated = buffer.toString();
+    buffer.clear();
+    Object decoded = _parseJson(accumulated, _reviver);
+    _sink.add(decoded);
+    _sink.close();
+  }
+}
+
+@patch
+class Utf8Decoder {
+  @patch
+  Converter<List<int>, T> fuse<T>(Converter<String, T> next) {
+    return super.fuse(next);
+  }
+
+  @patch
+  static String _convertIntercepted(
+      bool allowMalformed, List<int> codeUnits, int start, int end) {
+    // Test `codeUnits is NativeUint8List`. Dart's NativeUint8List is
+    // implemented by JavaScript's Uint8Array.
+    if (JS('bool', '# instanceof Uint8Array', codeUnits)) {
+      // JS 'cast' to avoid a downcast equivalent to the is-check we hand-coded.
+      NativeUint8List casted = JS('NativeUint8List', '#', codeUnits);
+      return _convertInterceptedUint8List(allowMalformed, casted, start, end);
+    }
+    return null; // This call was not intercepted.
+  }
+
+  static String _convertInterceptedUint8List(
+      bool allowMalformed, NativeUint8List codeUnits, int start, int end) {
+    if (allowMalformed) {
+      // TextDecoder with option {fatal: false} does not produce the same result
+      // as [Utf8Decoder]. It disagrees on the number of `U+FFFD` (REPLACEMENT
+      // CHARACTER) generated for some malformed sequences. We could use
+      // TextDecoder with option {fatal: true}, catch the error, and re-try
+      // without acceleration. That turns out to be extremely slow (the Error
+      // captures a stack trace).
+      // TODO(31370): Bring Utf8Decoder into alignment with TextDecoder.
+      // TODO(sra): If we can't do that, can we detect valid input fast enough
+      // to use a check like the [_unsafe] check below?
+      return null;
+    }
+
+    var decoder = _decoder;
+    if (decoder == null) return null;
+    if (0 == start && end == null) {
+      return _useTextDecoderChecked(decoder, codeUnits);
+    }
+
+    int length = codeUnits.length;
+    end = RangeError.checkValidRange(start, end, length);
+
+    if (0 == start && end == codeUnits.length) {
+      return _useTextDecoderChecked(decoder, codeUnits);
+    }
+
+    return _useTextDecoderChecked(decoder,
+        JS('NativeUint8List', '#.subarray(#, #)', codeUnits, start, end));
+  }
+
+  static String _useTextDecoderChecked(decoder, NativeUint8List codeUnits) {
+    if (_unsafe(codeUnits)) return null;
+    return _useTextDecoderUnchecked(decoder, codeUnits);
+  }
+
+  static String _useTextDecoderUnchecked(decoder, NativeUint8List codeUnits) {
+    // If the input is malformed, catch the exception and return `null` to fall
+    // back on unintercepted decoder. The fallback will either succeed in
+    // decoding, or report the problem better than TextDecoder.
+    try {
+      return JS('String', '#.decode(#)', decoder, codeUnits);
+    } catch (e) {}
+    return null;
+  }
+
+  /// Returns `true` if [codeUnits] contains problematic encodings.
+  ///
+  /// TextDecoder behaves differently to [Utf8Encoder] when the input encodes a
+  /// surrogate (U+D800 through U+DFFF). TextDecoder considers the surrogate to
+  /// be an encoding error and, depending on the `fatal` option, either throws
+  /// and Error or encodes the surrogate as U+FFFD. [Utf8Decoder] does not
+  /// consider the surrogate to be an error and returns the code unit encoded by
+  /// the surrogate.
+  ///
+  /// Throwing an `Error` captures the stack, whoch makes it so expensive that
+  /// it is worth checking the input for surrogates and avoiding TextDecoder in
+  /// this case.
+  static bool _unsafe(NativeUint8List codeUnits) {
+    // Surrogates encode as (hex) ED Ax xx or ED Bx xx.
+    int limit = codeUnits.length - 2;
+    for (int i = 0; i < limit; i++) {
+      int unit1 = codeUnits[i];
+      if (unit1 == 0xED) {
+        int unit2 = codeUnits[i + 1];
+        if ((unit2 & 0xE0) == 0xA0) return true;
+      }
+    }
+    return false;
+  }
+
+  // TextDecoder is not defined on some browsers and on the stand-alone d8 and
+  // jsshell engines. Use a lazy initializer to do feature detection once.
+  static final _decoder = _makeDecoder();
+  static _makeDecoder() {
+    try {
+      // Use `{fatal: true}`. 'fatal' does not correspond exactly to
+      // `!allowMalformed`: TextDecoder rejects unpaired surrogates which
+      // [Utf8Decoder] accepts.  In non-fatal mode, TextDecoder translates
+      // unpaired surrogates to REPLACEMENT CHARACTER (U+FFFD) whereas
+      // [Utf8Decoder] leaves the surrogate intact.
+      return JS('', 'new TextDecoder("utf-8", {fatal: true})');
+    } catch (e) {}
+    return null;
+  }
+}
+
+@patch
+int _scanOneByteCharacters(List<int> units, int from, int endIndex) {
+  final to = endIndex;
+  for (var i = from; i < to; i++) {
+    final unit = units[i];
+    if ((unit & _ONE_BYTE_LIMIT) != unit) return i - from;
+  }
+  return to - from;
+}
diff --git a/sdk_nnbd/lib/_internal/js_runtime/lib/core_patch.dart b/sdk_nnbd/lib/_internal/js_runtime/lib/core_patch.dart
new file mode 100644
index 0000000..c655fc2
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_runtime/lib/core_patch.dart
@@ -0,0 +1,2928 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Patch file for dart:core classes.
+import "dart:_internal" hide Symbol, LinkedList, LinkedListEntry;
+import "dart:_internal" as _symbol_dev;
+import 'dart:_interceptors';
+import 'dart:_js_helper'
+    show
+        checkInt,
+        Closure,
+        ConstantMap,
+        getRuntimeType,
+        JsLinkedHashMap,
+        jsonEncodeNative,
+        JSSyntaxRegExp,
+        NoInline,
+        objectHashCode,
+        patch,
+        Primitives,
+        quoteStringForRegExp,
+        stringJoinUnchecked,
+        getTraceFromException,
+        RuntimeError;
+
+import 'dart:_foreign_helper' show JS, JS_GET_FLAG;
+
+import 'dart:_native_typed_data' show NativeUint8List;
+
+import "dart:convert" show Encoding, utf8;
+
+import 'dart:typed_data' show Endian, Uint8List, Uint16List;
+
+String _symbolToString(Symbol symbol) => _symbol_dev.Symbol.getName(symbol);
+
+Map<String, dynamic> _symbolMapToStringMap(Map<Symbol, dynamic> map) {
+  if (map == null) return null;
+  var result = new Map<String, dynamic>();
+  map.forEach((Symbol key, value) {
+    result[_symbolToString(key)] = value;
+  });
+  return result;
+}
+
+@patch
+int identityHashCode(Object object) => objectHashCode(object);
+
+// Patch for Object implementation.
+@patch
+class Object {
+  @patch
+  bool operator ==(other) => identical(this, other);
+
+  @patch
+  int get hashCode => Primitives.objectHashCode(this);
+
+  @patch
+  String toString() => Primitives.objectToHumanReadableString(this);
+
+  @patch
+  dynamic noSuchMethod(Invocation invocation) {
+    throw new NoSuchMethodError(this, invocation.memberName,
+        invocation.positionalArguments, invocation.namedArguments);
+  }
+
+  @patch
+  Type get runtimeType => getRuntimeType(this);
+}
+
+@patch
+class Null {
+  @patch
+  int get hashCode => super.hashCode;
+}
+
+// Patch for Function implementation.
+@patch
+class Function {
+  @patch
+  static apply(Function function, List positionalArguments,
+      [Map<Symbol, dynamic> namedArguments]) {
+    return Primitives.applyFunction(
+        function,
+        positionalArguments,
+        // Use this form so that if namedArguments is always null, we can
+        // tree-shake _symbolMapToStringMap.
+        namedArguments == null ? null : _symbolMapToStringMap(namedArguments));
+  }
+}
+
+// Patch for Expando implementation.
+@patch
+class Expando<T> {
+  static const String _EXPANDO_PROPERTY_NAME = 'expando\$values';
+
+  // Incremented to make unique keys.
+  static int _keyCount = 0;
+
+  // Stores either a JS WeakMap or a "unique" string key.
+  final Object _jsWeakMapOrKey;
+
+  @patch
+  Expando([String name])
+      : this.name = name,
+        _jsWeakMapOrKey = JS('bool', 'typeof WeakMap == "function"')
+            ? JS('=Object|Null', 'new WeakMap()')
+            : _createKey();
+
+  @patch
+  T operator [](Object object) {
+    if (_jsWeakMapOrKey is! String) {
+      _checkType(object); // WeakMap doesn't check on reading, only writing.
+      return JS('', '#.get(#)', _jsWeakMapOrKey, object);
+    }
+    return _getFromObject(_jsWeakMapOrKey, object);
+  }
+
+  @patch
+  void operator []=(Object object, T value) {
+    if (_jsWeakMapOrKey is! String) {
+      JS('void', '#.set(#, #)', _jsWeakMapOrKey, object, value);
+    } else {
+      _setOnObject(_jsWeakMapOrKey, object, value);
+    }
+  }
+
+  static Object _getFromObject(String key, Object object) {
+    var values = Primitives.getProperty(object, _EXPANDO_PROPERTY_NAME);
+    return (values == null) ? null : Primitives.getProperty(values, key);
+  }
+
+  static void _setOnObject(String key, Object object, Object value) {
+    var values = Primitives.getProperty(object, _EXPANDO_PROPERTY_NAME);
+    if (values == null) {
+      values = new Object();
+      Primitives.setProperty(object, _EXPANDO_PROPERTY_NAME, values);
+    }
+    Primitives.setProperty(values, key, value);
+  }
+
+  static String _createKey() => "expando\$key\$${_keyCount++}";
+
+  static _checkType(object) {
+    if (object == null || object is bool || object is num || object is String) {
+      throw new ArgumentError.value(object,
+          "Expandos are not allowed on strings, numbers, booleans or null");
+    }
+  }
+}
+
+@patch
+class int {
+  @patch
+  static int parse(String source,
+      {int radix, @deprecated int onError(String source)}) {
+    int value = tryParse(source, radix: radix);
+    if (value != null) return value;
+    if (onError != null) return onError(source);
+    throw new FormatException(source);
+  }
+
+  @patch
+  static int tryParse(String source, {int radix}) {
+    return Primitives.parseInt(source, radix);
+  }
+}
+
+@patch
+class double {
+  @patch
+  static double parse(String source,
+      [@deprecated double onError(String source)]) {
+    double value = tryParse(source);
+    if (value != null) return value;
+    if (onError != null) return onError(source);
+    throw new FormatException('Invalid double', source);
+  }
+
+  @patch
+  static double tryParse(String source) {
+    return Primitives.parseDouble(source);
+  }
+}
+
+@patch
+class BigInt implements Comparable<BigInt> {
+  @patch
+  static BigInt get zero => _BigIntImpl.zero;
+  @patch
+  static BigInt get one => _BigIntImpl.one;
+  @patch
+  static BigInt get two => _BigIntImpl.two;
+
+  @patch
+  static BigInt parse(String source, {int radix}) =>
+      _BigIntImpl.parse(source, radix: radix);
+
+  @patch
+  static BigInt tryParse(String source, {int radix}) =>
+      _BigIntImpl._tryParse(source, radix: radix);
+
+  @patch
+  factory BigInt.from(num value) = _BigIntImpl.from;
+}
+
+@patch
+class Error {
+  @patch
+  static String _objectToString(Object object) {
+    // Closures all have useful and safe toString methods.
+    if (object is Closure) return object.toString();
+    return Primitives.objectToHumanReadableString(object);
+  }
+
+  @patch
+  static String _stringToSafeString(String string) {
+    return jsonEncodeNative(string);
+  }
+
+  @patch
+  StackTrace get stackTrace => Primitives.extractStackTrace(this);
+}
+
+@patch
+class FallThroughError {
+  @patch
+  FallThroughError._create(String url, int line);
+
+  @patch
+  String toString() => super.toString();
+}
+
+@patch
+class AbstractClassInstantiationError {
+  @patch
+  String toString() => "Cannot instantiate abstract class: '$_className'";
+}
+
+// Patch for DateTime implementation.
+@patch
+class DateTime {
+  @patch
+  DateTime.fromMillisecondsSinceEpoch(int millisecondsSinceEpoch,
+      {bool isUtc: false})
+      // `0 + millisecondsSinceEpoch` forces the inferred result to be non-null.
+      : this._withValue(0 + millisecondsSinceEpoch, isUtc: isUtc);
+
+  @patch
+  DateTime.fromMicrosecondsSinceEpoch(int microsecondsSinceEpoch,
+      {bool isUtc: false})
+      : this._withValue(
+            _microsecondInRoundedMilliseconds(microsecondsSinceEpoch),
+            isUtc: isUtc);
+
+  @patch
+  DateTime._internal(int year, int month, int day, int hour, int minute,
+      int second, int millisecond, int microsecond, bool isUtc)
+      // checkBool is manually inlined here because dart2js doesn't inline it
+      // and [isUtc] is usually a constant.
+      : this.isUtc = isUtc is bool
+            ? isUtc
+            : throw new ArgumentError.value(isUtc, 'isUtc'),
+        _value = checkInt(Primitives.valueFromDecomposedDate(
+            year,
+            month,
+            day,
+            hour,
+            minute,
+            second,
+            millisecond + _microsecondInRoundedMilliseconds(microsecond),
+            isUtc));
+
+  @patch
+  DateTime._now()
+      : isUtc = false,
+        _value = Primitives.dateNow();
+
+  /// Rounds the given [microsecond] to the nearest milliseconds value.
+  ///
+  /// For example, invoked with argument `2600` returns `3`.
+  static int _microsecondInRoundedMilliseconds(int microsecond) {
+    return (microsecond / 1000).round();
+  }
+
+  @patch
+  static int _brokenDownDateToValue(int year, int month, int day, int hour,
+      int minute, int second, int millisecond, int microsecond, bool isUtc) {
+    return Primitives.valueFromDecomposedDate(
+        year,
+        month,
+        day,
+        hour,
+        minute,
+        second,
+        millisecond + _microsecondInRoundedMilliseconds(microsecond),
+        isUtc);
+  }
+
+  @patch
+  String get timeZoneName {
+    if (isUtc) return "UTC";
+    return Primitives.getTimeZoneName(this);
+  }
+
+  @patch
+  Duration get timeZoneOffset {
+    if (isUtc) return new Duration();
+    return new Duration(minutes: Primitives.getTimeZoneOffsetInMinutes(this));
+  }
+
+  @patch
+  DateTime add(Duration duration) {
+    return new DateTime._withValue(_value + duration.inMilliseconds,
+        isUtc: isUtc);
+  }
+
+  @patch
+  DateTime subtract(Duration duration) {
+    return new DateTime._withValue(_value - duration.inMilliseconds,
+        isUtc: isUtc);
+  }
+
+  @patch
+  Duration difference(DateTime other) {
+    return new Duration(milliseconds: _value - other._value);
+  }
+
+  @patch
+  int get millisecondsSinceEpoch => _value;
+
+  @patch
+  int get microsecondsSinceEpoch => 1000 * _value;
+
+  @patch
+  int get year => Primitives.getYear(this);
+
+  @patch
+  int get month => Primitives.getMonth(this);
+
+  @patch
+  int get day => Primitives.getDay(this);
+
+  @patch
+  int get hour => Primitives.getHours(this);
+
+  @patch
+  int get minute => Primitives.getMinutes(this);
+
+  @patch
+  int get second => Primitives.getSeconds(this);
+
+  @patch
+  int get millisecond => Primitives.getMilliseconds(this);
+
+  @patch
+  int get microsecond => 0;
+
+  @patch
+  int get weekday => Primitives.getWeekday(this);
+
+  @patch
+  bool operator ==(dynamic other) =>
+      other is DateTime &&
+      _value == other.millisecondsSinceEpoch &&
+      isUtc == other.isUtc;
+
+  @patch
+  bool isBefore(DateTime other) => _value < other.millisecondsSinceEpoch;
+
+  @patch
+  bool isAfter(DateTime other) => _value > other.millisecondsSinceEpoch;
+
+  @patch
+  bool isAtSameMomentAs(DateTime other) =>
+      _value == other.millisecondsSinceEpoch;
+
+  @patch
+  int compareTo(DateTime other) =>
+      _value.compareTo(other.millisecondsSinceEpoch);
+}
+
+// Patch for Stopwatch implementation.
+@patch
+class Stopwatch {
+  @patch
+  static void _initTicker() {
+    Primitives.initTicker();
+    _frequency = Primitives.timerFrequency;
+  }
+
+  @patch
+  static int _now() => Primitives.timerTicks();
+
+  @patch
+  int get elapsedMicroseconds {
+    int ticks = elapsedTicks;
+    if (_frequency == 1000000) return ticks;
+    assert(_frequency == 1000);
+    return ticks * 1000;
+  }
+
+  @patch
+  int get elapsedMilliseconds {
+    int ticks = elapsedTicks;
+    if (_frequency == 1000) return ticks;
+    assert(_frequency == 1000000);
+    return ticks ~/ 1000;
+  }
+}
+
+// Patch for List implementation.
+@patch
+class List<E> {
+  @patch
+  factory List([int length]) = JSArray<E>.list;
+
+  @patch
+  factory List.filled(int length, E fill, {bool growable: false}) {
+    List result = growable
+        ? new JSArray<E>.growable(length)
+        : new JSArray<E>.fixed(length);
+    if (length != 0 && fill != null) {
+      for (int i = 0; i < result.length; i++) {
+        result[i] = fill;
+      }
+    }
+    return result;
+  }
+
+  @patch
+  factory List.from(Iterable elements, {bool growable: true}) {
+    List<E> list = <E>[];
+    for (E e in elements) {
+      list.add(e);
+    }
+    if (growable) return list;
+    return makeListFixedLength(list);
+  }
+
+  @patch
+  factory List.unmodifiable(Iterable elements) {
+    List result = new List<E>.from(elements, growable: false);
+    return makeFixedListUnmodifiable(result);
+  }
+}
+
+@patch
+class Map<K, V> {
+  @patch
+  factory Map.unmodifiable(Map other) = ConstantMap<K, V>.from;
+
+  @patch
+  factory Map() = JsLinkedHashMap<K, V>.es6;
+}
+
+@patch
+class String {
+  @patch
+  factory String.fromCharCodes(Iterable<int> charCodes,
+      [int start = 0, int end]) {
+    if (charCodes is JSArray) {
+      JSArray<int> array = charCodes;
+      return _stringFromJSArray(array, start, end);
+    }
+    if (charCodes is NativeUint8List) {
+      return _stringFromUint8List(charCodes, start, end);
+    }
+    return _stringFromIterable(charCodes, start, end);
+  }
+
+  @patch
+  factory String.fromCharCode(int charCode) {
+    return Primitives.stringFromCharCode(charCode);
+  }
+
+  static String _stringFromJSArray(List list, int start, int endOrNull) {
+    int len = list.length;
+    int end = RangeError.checkValidRange(start, endOrNull, len);
+    if (start > 0 || end < len) {
+      list = list.sublist(start, end);
+    }
+    return Primitives.stringFromCharCodes(list);
+  }
+
+  static String _stringFromUint8List(
+      NativeUint8List charCodes, int start, int endOrNull) {
+    int len = charCodes.length;
+    int end = RangeError.checkValidRange(start, endOrNull, len);
+    return Primitives.stringFromNativeUint8List(charCodes, start, end);
+  }
+
+  static String _stringFromIterable(
+      Iterable<int> charCodes, int start, int end) {
+    if (start < 0) throw new RangeError.range(start, 0, charCodes.length);
+    if (end != null && end < start) {
+      throw new RangeError.range(end, start, charCodes.length);
+    }
+    var it = charCodes.iterator;
+    for (int i = 0; i < start; i++) {
+      if (!it.moveNext()) {
+        throw new RangeError.range(start, 0, i);
+      }
+    }
+    var list = [];
+    if (end == null) {
+      while (it.moveNext()) list.add(it.current);
+    } else {
+      for (int i = start; i < end; i++) {
+        if (!it.moveNext()) {
+          throw new RangeError.range(end, start, i);
+        }
+        list.add(it.current);
+      }
+    }
+    return Primitives.stringFromCharCodes(list);
+  }
+}
+
+@patch
+class bool {
+  @patch
+  int get hashCode => super.hashCode;
+}
+
+@patch
+class RegExp {
+  @pragma('dart2js:noInline')
+  @patch
+  factory RegExp(String source,
+          {bool multiLine: false,
+          bool caseSensitive: true,
+          bool unicode: false,
+          bool dotAll: false}) =>
+      new JSSyntaxRegExp(source,
+          multiLine: multiLine,
+          caseSensitive: caseSensitive,
+          unicode: unicode,
+          dotAll: dotAll);
+
+  @patch
+  static String escape(String text) => quoteStringForRegExp(text);
+}
+
+// Patch for 'identical' function.
+@pragma(
+    'dart2js:noInline') // No inlining since we recognize the call in optimizer.
+@patch
+bool identical(Object a, Object b) {
+  return JS('bool', '(# == null ? # == null : # === #)', a, b, a, b);
+}
+
+@patch
+class StringBuffer {
+  String _contents;
+
+  @patch
+  StringBuffer([Object content = ""]) : _contents = '$content';
+
+  @patch
+  int get length => _contents.length;
+
+  @patch
+  void write(Object obj) {
+    _writeString('$obj');
+  }
+
+  @patch
+  void writeCharCode(int charCode) {
+    _writeString(new String.fromCharCode(charCode));
+  }
+
+  @patch
+  void writeAll(Iterable objects, [String separator = ""]) {
+    _contents = _writeAll(_contents, objects, separator);
+  }
+
+  @patch
+  void writeln([Object obj = ""]) {
+    _writeString('$obj\n');
+  }
+
+  @patch
+  void clear() {
+    _contents = "";
+  }
+
+  @patch
+  String toString() => Primitives.flattenString(_contents);
+
+  void _writeString(str) {
+    _contents = Primitives.stringConcatUnchecked(_contents, str);
+  }
+
+  static String _writeAll(String string, Iterable objects, String separator) {
+    Iterator iterator = objects.iterator;
+    if (!iterator.moveNext()) return string;
+    if (separator.isEmpty) {
+      do {
+        string = _writeOne(string, iterator.current);
+      } while (iterator.moveNext());
+    } else {
+      string = _writeOne(string, iterator.current);
+      while (iterator.moveNext()) {
+        string = _writeOne(string, separator);
+        string = _writeOne(string, iterator.current);
+      }
+    }
+    return string;
+  }
+
+  static String _writeOne(String string, Object obj) {
+    return Primitives.stringConcatUnchecked(string, '$obj');
+  }
+}
+
+@patch
+class NoSuchMethodError {
+  final Object _receiver;
+  final Symbol _memberName;
+  final List _arguments;
+  final Map<Symbol, dynamic> _namedArguments;
+  final List _existingArgumentNames;
+
+  @patch
+  NoSuchMethodError.withInvocation(Object receiver, Invocation invocation)
+      : this(receiver, invocation.memberName, invocation.positionalArguments,
+            invocation.namedArguments);
+
+  @patch
+  NoSuchMethodError(Object receiver, Symbol memberName,
+      List positionalArguments, Map<Symbol, dynamic> namedArguments,
+      [List existingArgumentNames = null])
+      : _receiver = receiver,
+        _memberName = memberName,
+        _arguments = positionalArguments,
+        _namedArguments = namedArguments,
+        _existingArgumentNames = existingArgumentNames;
+
+  @patch
+  String toString() {
+    StringBuffer sb = new StringBuffer('');
+    String comma = '';
+    if (_arguments != null) {
+      for (var argument in _arguments) {
+        sb.write(comma);
+        sb.write(Error.safeToString(argument));
+        comma = ', ';
+      }
+    }
+    if (_namedArguments != null) {
+      _namedArguments.forEach((Symbol key, var value) {
+        sb.write(comma);
+        sb.write(_symbolToString(key));
+        sb.write(": ");
+        sb.write(Error.safeToString(value));
+        comma = ', ';
+      });
+    }
+    String memberName = _symbolToString(_memberName);
+    String receiverText = Error.safeToString(_receiver);
+    String actualParameters = '$sb';
+    if (_existingArgumentNames == null) {
+      return "NoSuchMethodError: method not found: '$memberName'\n"
+          "Receiver: ${receiverText}\n"
+          "Arguments: [$actualParameters]";
+    } else {
+      String formalParameters = _existingArgumentNames.join(', ');
+      return "NoSuchMethodError: incorrect number of arguments passed to "
+          "method named '$memberName'\n"
+          "Receiver: ${receiverText}\n"
+          "Tried calling: $memberName($actualParameters)\n"
+          "Found: $memberName($formalParameters)";
+    }
+  }
+}
+
+class _CompileTimeError extends Error {
+  final String _errorMsg;
+  // TODO(sigmund): consider calling `JS('', 'debugger')`.
+  _CompileTimeError(this._errorMsg);
+  String toString() => _errorMsg;
+}
+
+@patch
+class Uri {
+  @patch
+  static Uri get base {
+    String uri = Primitives.currentUri();
+    if (uri != null) return Uri.parse(uri);
+    throw new UnsupportedError("'Uri.base' is not supported");
+  }
+}
+
+@patch
+class _Uri {
+  @patch
+  static bool get _isWindows => _isWindowsCached;
+
+  static final bool _isWindowsCached = JS(
+      'bool',
+      'typeof process != "undefined" && '
+          'Object.prototype.toString.call(process) == "[object process]" && '
+          'process.platform == "win32"');
+
+  // Matches a String that _uriEncodes to itself regardless of the kind of
+  // component.  This corresponds to [_unreservedTable], i.e. characters that
+  // are not encoded by any encoding table.
+  static final RegExp _needsNoEncoding = new RegExp(r'^[\-\.0-9A-Z_a-z~]*$');
+
+  /// This is the internal implementation of JavaScript's encodeURI function.
+  /// It encodes all characters in the string [text] except for those
+  /// that appear in [canonicalTable], and returns the escaped string.
+  @patch
+  static String _uriEncode(List<int> canonicalTable, String text,
+      Encoding encoding, bool spaceToPlus) {
+    if (identical(encoding, utf8) && _needsNoEncoding.hasMatch(text)) {
+      return text;
+    }
+
+    // Encode the string into bytes then generate an ASCII only string
+    // by percent encoding selected bytes.
+    StringBuffer result = new StringBuffer('');
+    var bytes = encoding.encode(text);
+    for (int i = 0; i < bytes.length; i++) {
+      int byte = bytes[i];
+      if (byte < 128 &&
+          ((canonicalTable[byte >> 4] & (1 << (byte & 0x0f))) != 0)) {
+        result.writeCharCode(byte);
+      } else if (spaceToPlus && byte == _SPACE) {
+        result.write('+');
+      } else {
+        const String hexDigits = '0123456789ABCDEF';
+        result.write('%');
+        result.write(hexDigits[(byte >> 4) & 0x0f]);
+        result.write(hexDigits[byte & 0x0f]);
+      }
+    }
+    return result.toString();
+  }
+}
+
+bool _hasErrorStackProperty = JS('bool', 'new Error().stack != void 0');
+
+@patch
+class StackTrace {
+  @patch
+  @pragma('dart2js:noInline')
+  static StackTrace get current {
+    if (_hasErrorStackProperty) {
+      return getTraceFromException(JS('', 'new Error()'));
+    }
+    // Fallback if new Error().stack does not exist.
+    // Currently only required for IE 11.
+    try {
+      throw '';
+    } catch (_, stackTrace) {
+      return stackTrace;
+    }
+  }
+}
+
+// Called from kernel generated code.
+_malformedTypeError(message) => new RuntimeError(message);
+
+// Called from kernel generated code.
+_genericNoSuchMethod(receiver, memberName, positionalArguments, namedArguments,
+    existingArguments) {
+  return new NoSuchMethodError(
+      receiver, memberName, positionalArguments, namedArguments);
+}
+
+// Called from kernel generated code.
+_unresolvedConstructorError(receiver, memberName, positionalArguments,
+    namedArguments, existingArguments) {
+  // TODO(sra): Generate an error that reads:
+  //
+  //     No constructor '$memberName' declared in class '$receiver'.
+
+  return new NoSuchMethodError(
+      receiver, memberName, positionalArguments, namedArguments);
+}
+
+// Called from kernel generated code.
+_unresolvedStaticGetterError(receiver, memberName, positionalArguments,
+    namedArguments, existingArguments) {
+  // TODO(sra): Generate customized message.
+  return new NoSuchMethodError(
+      receiver, memberName, positionalArguments, namedArguments);
+}
+
+// Called from kernel generated code.
+_unresolvedStaticSetterError(receiver, memberName, positionalArguments,
+    namedArguments, existingArguments) {
+  // TODO(sra): Generate customized message.
+  return new NoSuchMethodError(
+      receiver, memberName, positionalArguments, namedArguments);
+}
+
+// Called from kernel generated code.
+_unresolvedStaticMethodError(receiver, memberName, positionalArguments,
+    namedArguments, existingArguments) {
+  // TODO(sra): Generate customized message.
+  return new NoSuchMethodError(
+      receiver, memberName, positionalArguments, namedArguments);
+}
+
+// Called from kernel generated code.
+_unresolvedTopLevelGetterError(receiver, memberName, positionalArguments,
+    namedArguments, existingArguments) {
+  // TODO(sra): Generate customized message.
+  return new NoSuchMethodError(
+      receiver, memberName, positionalArguments, namedArguments);
+}
+
+// Called from kernel generated code.
+_unresolvedTopLevelSetterError(receiver, memberName, positionalArguments,
+    namedArguments, existingArguments) {
+  // TODO(sra): Generate customized message.
+  return new NoSuchMethodError(
+      receiver, memberName, positionalArguments, namedArguments);
+}
+
+// Called from kernel generated code.
+_unresolvedTopLevelMethodError(receiver, memberName, positionalArguments,
+    namedArguments, existingArguments) {
+  // TODO(sra): Generate customized message.
+  return new NoSuchMethodError(
+      receiver, memberName, positionalArguments, namedArguments);
+}
+
+/// Used by Fasta to report a runtime error when a final field with an
+/// initializer is also initialized in a generative constructor.
+///
+/// Note: in strong mode, this is a compile-time error and this class becomes
+/// obsolete.
+class _DuplicatedFieldInitializerError extends Error {
+  final String _name;
+
+  _DuplicatedFieldInitializerError(this._name);
+
+  toString() => "Error: field '$_name' is already initialized.";
+}
+
+// TODO(sra): The rest of this core_patch.dart source should reside in an
+// included part file instead of being inlined. However, part files are not
+// properly supported here.
+
+// 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.
+
+// part of dart.core;
+
+int _max(int a, int b) => a > b ? a : b;
+int _min(int a, int b) => a < b ? a : b;
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+ * Copyright (c) 2003-2005  Tom Wu
+ * Copyright (c) 2012 Adam Singer (adam@solvr.io)
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL TOM WU BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF
+ * THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * In addition, the following condition applies:
+ *
+ * All redistributions must retain an intact copy of this copyright notice
+ * and disclaimer.
+ */
+
+/// An implementation for the arbitrarily large integer.
+///
+/// The integer number is represented by a sign, an array of 16-bit unsigned
+/// integers in little endian format, and a number of used digits in that array.
+class _BigIntImpl implements BigInt {
+  // Bits per digit.
+  static const int _digitBits = 16;
+  static const int _digitBase = 1 << _digitBits;
+  static const int _digitMask = (1 << _digitBits) - 1;
+
+  static final _BigIntImpl zero = new _BigIntImpl._fromInt(0);
+  static final _BigIntImpl one = new _BigIntImpl._fromInt(1);
+  static final _BigIntImpl two = new _BigIntImpl._fromInt(2);
+
+  static final _BigIntImpl _minusOne = -one;
+  static final _BigIntImpl _bigInt10000 = new _BigIntImpl._fromInt(10000);
+
+  // Result cache for last _divRem call.
+  // Result cache for last _divRem call.
+  static Uint16List _lastDividendDigits;
+  static int _lastDividendUsed;
+  static Uint16List _lastDivisorDigits;
+  static int _lastDivisorUsed;
+  static Uint16List _lastQuoRemDigits;
+  static int _lastQuoRemUsed;
+  static int _lastRemUsed;
+  static int _lastRem_nsh;
+
+  /// Whether this bigint is negative.
+  final bool _isNegative;
+
+  /// The unsigned digits of this bigint.
+  ///
+  /// The least significant digit is in slot 0.
+  /// The list may have more digits than needed. That is, `_digits.length` may
+  /// be strictly greater than `_used`.
+  final Uint16List _digits;
+
+  /// The number of used entries in [_digits].
+  ///
+  /// To avoid reallocating [Uint16List]s, lists that are too big are not
+  /// replaced.
+  final int _used;
+
+  /// Parses [source] as a, possibly signed, integer literal and returns its
+  /// value.
+  ///
+  /// The [source] must be a non-empty sequence of base-[radix] digits,
+  /// optionally prefixed with a minus or plus sign ('-' or '+').
+  ///
+  /// The [radix] must be in the range 2..36. The digits used are
+  /// first the decimal digits 0..9, and then the letters 'a'..'z' with
+  /// values 10 through 35. Also accepts upper-case letters with the same
+  /// values as the lower-case ones.
+  ///
+  /// If no [radix] is given then it defaults to 10. In this case, the [source]
+  /// digits may also start with `0x`, in which case the number is interpreted
+  /// as a hexadecimal literal, which effectively means that the `0x` is ignored
+  /// and the radix is instead set to 16.
+  ///
+  /// For any int `n` and radix `r`, it is guaranteed that
+  /// `n == int.parse(n.toRadixString(r), radix: r)`.
+  ///
+  /// Throws a [FormatException] if the [source] is not a valid integer literal,
+  /// optionally prefixed by a sign.
+  static _BigIntImpl parse(String source, {int radix}) {
+    var result = _tryParse(source, radix: radix);
+    if (result == null) {
+      throw new FormatException("Could not parse BigInt", source);
+    }
+    return result;
+  }
+
+  /// Parses a decimal bigint literal.
+  ///
+  /// The [source] must not contain leading or trailing whitespace.
+  static _BigIntImpl _parseDecimal(String source, bool isNegative) {
+    const _0 = 48;
+
+    int part = 0;
+    _BigIntImpl result = zero;
+    // Read in the source 4 digits at a time.
+    // The first part may have a few leading virtual '0's to make the remaining
+    // parts all have exactly 4 digits.
+    int digitInPartCount = 4 - source.length.remainder(4);
+    if (digitInPartCount == 4) digitInPartCount = 0;
+    for (int i = 0; i < source.length; i++) {
+      part = part * 10 + source.codeUnitAt(i) - _0;
+      if (++digitInPartCount == 4) {
+        result = result * _bigInt10000 + new _BigIntImpl._fromInt(part);
+        part = 0;
+        digitInPartCount = 0;
+      }
+    }
+    if (isNegative) return -result;
+    return result;
+  }
+
+  /// Returns the value of a given source digit.
+  ///
+  /// Source digits between "0" and "9" (inclusive) return their decimal value.
+  ///
+  /// Source digits between "a" and "z", or "A" and "Z" (inclusive) return
+  /// 10 + their position in the ASCII alphabet.
+  ///
+  /// The incoming [codeUnit] must be an ASCII code-unit.
+  static int _codeUnitToRadixValue(int codeUnit) {
+    // We know that the characters must be ASCII as otherwise the
+    // regexp wouldn't have matched. Lowercasing by doing `| 0x20` is thus
+    // guaranteed to be a safe operation, since it preserves digits
+    // and lower-cases ASCII letters.
+    const int _0 = 48;
+    const int _9 = 57;
+    const int _a = 97;
+    if (_0 <= codeUnit && codeUnit <= _9) return codeUnit - _0;
+    codeUnit |= 0x20;
+    var result = codeUnit - _a + 10;
+    return result;
+  }
+
+  /// Parses the given [source] string, starting at [startPos], as a hex
+  /// literal.
+  ///
+  /// If [isNegative] is true, negates the result before returning it.
+  ///
+  /// The [source] (substring) must be a valid hex literal.
+  static _BigIntImpl _parseHex(String source, int startPos, bool isNegative) {
+    int hexDigitsPerChunk = _digitBits ~/ 4;
+    int sourceLength = source.length - startPos;
+    int chunkCount = (sourceLength / hexDigitsPerChunk).ceil();
+    var digits = new Uint16List(chunkCount);
+
+    int lastDigitLength = sourceLength - (chunkCount - 1) * hexDigitsPerChunk;
+    int digitIndex = digits.length - 1;
+    int i = startPos;
+    int chunk = 0;
+    for (int j = 0; j < lastDigitLength; j++) {
+      var digitValue = _codeUnitToRadixValue(source.codeUnitAt(i++));
+      if (digitValue >= 16) return null;
+      chunk = chunk * 16 + digitValue;
+    }
+    digits[digitIndex--] = chunk;
+
+    while (i < source.length) {
+      chunk = 0;
+      for (int j = 0; j < hexDigitsPerChunk; j++) {
+        var digitValue = _codeUnitToRadixValue(source.codeUnitAt(i++));
+        if (digitValue >= 16) return null;
+        chunk = chunk * 16 + digitValue;
+      }
+      digits[digitIndex--] = chunk;
+    }
+    if (digits.length == 1 && digits[0] == 0) return zero;
+    return new _BigIntImpl._(isNegative, digits.length, digits);
+  }
+
+  /// Parses the given [source] as a [radix] literal.
+  ///
+  /// The [source] will be checked for invalid characters. If it is invalid,
+  /// this function returns `null`.
+  static _BigIntImpl _parseRadix(String source, int radix, bool isNegative) {
+    var result = zero;
+    var base = new _BigIntImpl._fromInt(radix);
+    for (int i = 0; i < source.length; i++) {
+      var digitValue = _codeUnitToRadixValue(source.codeUnitAt(i));
+      if (digitValue >= radix) return null;
+      result = result * base + new _BigIntImpl._fromInt(digitValue);
+    }
+    if (isNegative) return -result;
+    return result;
+  }
+
+  /// Tries to parse the given [source] as a [radix] literal.
+  ///
+  /// Returns the parsed big integer, or `null` if it failed.
+  ///
+  /// If the [radix] is `null` accepts decimal literals or `0x` hex literals.
+  static _BigIntImpl _tryParse(String source, {int radix}) {
+    if (source == "") return null;
+
+    var re = new RegExp(r'^\s*([+-]?)((0x[a-f0-9]+)|(\d+)|([a-z0-9]+))\s*$',
+        caseSensitive: false);
+    var match = re.firstMatch(source);
+    int signIndex = 1;
+    int hexIndex = 3;
+    int decimalIndex = 4;
+    int nonDecimalHexIndex = 5;
+    if (match == null) return null;
+
+    bool isNegative = match[signIndex] == "-";
+
+    String decimalMatch = match[decimalIndex];
+    String hexMatch = match[hexIndex];
+    String nonDecimalMatch = match[nonDecimalHexIndex];
+
+    if (radix == null) {
+      if (decimalMatch != null) {
+        // Cannot fail because we know that the digits are all decimal.
+        return _parseDecimal(decimalMatch, isNegative);
+      }
+      if (hexMatch != null) {
+        // Cannot fail because we know that the digits are all hex.
+        return _parseHex(hexMatch, 2, isNegative);
+      }
+      return null;
+    }
+
+    if (radix is! int) {
+      throw new ArgumentError.value(radix, 'radix', 'is not an integer');
+    }
+    if (radix < 2 || radix > 36) {
+      throw new RangeError.range(radix, 2, 36, 'radix');
+    }
+    if (radix == 10 && decimalMatch != null) {
+      return _parseDecimal(decimalMatch, isNegative);
+    }
+    if (radix == 16 && (decimalMatch != null || nonDecimalMatch != null)) {
+      return _parseHex(decimalMatch ?? nonDecimalMatch, 0, isNegative);
+    }
+
+    return _parseRadix(
+        decimalMatch ?? nonDecimalMatch ?? hexMatch, radix, isNegative);
+  }
+
+  /// Finds the amount significant digits in the provided [digits] array.
+  static int _normalize(int used, Uint16List digits) {
+    while (used > 0 && digits[used - 1] == 0) used--;
+    return 0 + used; // force inferred result to be non-null.
+  }
+
+  /// Factory returning an instance initialized with the given field values.
+  /// If the [digits] array contains leading 0s, the [used] value is adjusted
+  /// accordingly. The [digits] array is not modified.
+  _BigIntImpl._(bool isNegative, int used, Uint16List digits)
+      : this._normalized(isNegative, _normalize(used, digits), digits);
+
+  _BigIntImpl._normalized(bool isNegative, this._used, this._digits)
+      : _isNegative = _used == 0 ? false : isNegative;
+
+  /// Whether this big integer is zero.
+  bool get _isZero => _used == 0;
+
+  /// Allocates an array of the given [length] and copies the [digits] in the
+  /// range [from] to [to-1], starting at index 0, followed by leading zero
+  /// digits.
+  static Uint16List _cloneDigits(
+      Uint16List digits, int from, int to, int length) {
+    var resultDigits = new Uint16List(length);
+    var n = to - from;
+    for (var i = 0; i < n; i++) {
+      resultDigits[i] = digits[from + i];
+    }
+    return resultDigits;
+  }
+
+  /// Allocates a big integer from the provided [value] number.
+  factory _BigIntImpl.from(num value) {
+    if (value == 0) return zero;
+    if (value == 1) return one;
+    if (value == 2) return two;
+
+    // Given this order dart2js will use the `_fromInt` for smaller value and
+    // then use the bit-manipulating `_fromDouble` for all other values.
+    if (value.abs() < 0x100000000)
+      return new _BigIntImpl._fromInt(value.toInt());
+    if (value is double) return new _BigIntImpl._fromDouble(value);
+    return new _BigIntImpl._fromInt(value);
+  }
+
+  factory _BigIntImpl._fromInt(int value) {
+    bool isNegative = value < 0;
+    assert(_digitBits == 16);
+    if (isNegative) {
+      // Handle the min 64-bit value differently, since its negation is not
+      // positive.
+      const int minInt64 = -0x80000000 * 0x100000000;
+      if (value == minInt64) {
+        var digits = new Uint16List(4);
+        digits[3] = 0x8000;
+        return new _BigIntImpl._(true, 4, digits);
+      }
+      value = -value;
+    }
+    if (value < _digitBase) {
+      var digits = new Uint16List(1);
+      digits[0] = value;
+      return new _BigIntImpl._(isNegative, 1, digits);
+    }
+    if (value <= 0xFFFFFFFF) {
+      var digits = new Uint16List(2);
+      digits[0] = value & _digitMask;
+      digits[1] = value >> _digitBits;
+      return new _BigIntImpl._(isNegative, 2, digits);
+    }
+
+    var bits = value.bitLength;
+    var digits = new Uint16List((bits - 1) ~/ _digitBits + 1);
+    var i = 0;
+    while (value != 0) {
+      digits[i++] = value & _digitMask;
+      value = value ~/ _digitBase;
+    }
+    return new _BigIntImpl._(isNegative, digits.length, digits);
+  }
+
+  /// An 8-byte Uint8List we can reuse for [_fromDouble] to avoid generating
+  /// garbage.
+  static final Uint8List _bitsForFromDouble = new Uint8List(8);
+
+  factory _BigIntImpl._fromDouble(double value) {
+    const int exponentBias = 1075;
+
+    if (value.isNaN || value.isInfinite) {
+      throw new ArgumentError("Value must be finite: $value");
+    }
+    bool isNegative = value < 0;
+    if (isNegative) value = -value;
+
+    value = value.floorToDouble();
+    if (value == 0) return zero;
+
+    var bits = _bitsForFromDouble;
+    for (int i = 0; i < 8; i++) {
+      bits[i] = 0;
+    }
+    bits.buffer.asByteData().setFloat64(0, value, Endian.little);
+    // The exponent is in bits 53..63.
+    var biasedExponent = (bits[7] << 4) + (bits[6] >> 4);
+    var exponent = biasedExponent - exponentBias;
+
+    assert(_digitBits == 16);
+    // The significant bits are in 0 .. 52.
+    var unshiftedDigits = new Uint16List(4);
+    unshiftedDigits[0] = (bits[1] << 8) + bits[0];
+    unshiftedDigits[1] = (bits[3] << 8) + bits[2];
+    unshiftedDigits[2] = (bits[5] << 8) + bits[4];
+    // Don't forget to add the hidden bit.
+    unshiftedDigits[3] = 0x10 | (bits[6] & 0xF);
+
+    var unshiftedBig = new _BigIntImpl._normalized(false, 4, unshiftedDigits);
+    _BigIntImpl absResult = unshiftedBig;
+    if (exponent < 0) {
+      absResult = unshiftedBig >> -exponent;
+    } else if (exponent > 0) {
+      absResult = unshiftedBig << exponent;
+    }
+    if (isNegative) return -absResult;
+    return absResult;
+  }
+
+  /// Return the negative value of this integer.
+  ///
+  /// The result of negating an integer always has the opposite sign, except
+  /// for zero, which is its own negation.
+  _BigIntImpl operator -() {
+    if (_used == 0) return this;
+    return new _BigIntImpl._(!_isNegative, _used, _digits);
+  }
+
+  /// Returns the absolute value of this integer.
+  ///
+  /// For any integer `x`, the result is the same as `x < 0 ? -x : x`.
+  _BigIntImpl abs() => _isNegative ? -this : this;
+
+  /// Returns this << n *_DIGIT_BITS.
+  _BigIntImpl _dlShift(int n) {
+    final used = _used;
+    if (used == 0) {
+      return zero;
+    }
+    final resultUsed = used + n;
+    final digits = _digits;
+    final resultDigits = new Uint16List(resultUsed);
+    for (int i = used - 1; i >= 0; i--) {
+      resultDigits[i + n] = digits[i];
+    }
+    return new _BigIntImpl._(_isNegative, resultUsed, resultDigits);
+  }
+
+  /// Same as [_dlShift] but works on the decomposed big integers.
+  ///
+  /// Returns `resultUsed`.
+  ///
+  /// `resultDigits[0..resultUsed-1] = xDigits[0..xUsed-1] << n*_DIGIT_BITS`.
+  static int _dlShiftDigits(
+      Uint16List xDigits, int xUsed, int n, Uint16List resultDigits) {
+    if (xUsed == 0) {
+      return 0;
+    }
+    if (n == 0 && identical(resultDigits, xDigits)) {
+      return xUsed;
+    }
+    final resultUsed = xUsed + n;
+    for (int i = xUsed - 1; i >= 0; i--) {
+      resultDigits[i + n] = xDigits[i];
+    }
+    for (int i = n - 1; i >= 0; i--) {
+      resultDigits[i] = 0;
+    }
+    return resultUsed;
+  }
+
+  /// Returns `this >> n*_DIGIT_BITS`.
+  _BigIntImpl _drShift(int n) {
+    final used = _used;
+    if (used == 0) {
+      return zero;
+    }
+    final resultUsed = used - n;
+    if (resultUsed <= 0) {
+      return _isNegative ? _minusOne : zero;
+    }
+    final digits = _digits;
+    final resultDigits = new Uint16List(resultUsed);
+    for (var i = n; i < used; i++) {
+      resultDigits[i - n] = digits[i];
+    }
+    final result = new _BigIntImpl._(_isNegative, resultUsed, resultDigits);
+    if (_isNegative) {
+      // Round down if any bit was shifted out.
+      for (var i = 0; i < n; i++) {
+        if (digits[i] != 0) {
+          return result - one;
+        }
+      }
+    }
+    return result;
+  }
+
+  /// Shifts the digits of [xDigits] into the right place in [resultDigits].
+  ///
+  /// `resultDigits[ds..xUsed+ds] = xDigits[0..xUsed-1] << (n % _DIGIT_BITS)`
+  ///   where `ds = n ~/ _DIGIT_BITS`
+  ///
+  /// Does *not* clear digits below ds.
+  static void _lsh(
+      Uint16List xDigits, int xUsed, int n, Uint16List resultDigits) {
+    assert(xUsed > 0);
+    final digitShift = n ~/ _digitBits;
+    final bitShift = n % _digitBits;
+    final carryBitShift = _digitBits - bitShift;
+    final bitMask = (1 << carryBitShift) - 1;
+    var carry = 0;
+    for (int i = xUsed - 1; i >= 0; i--) {
+      final digit = xDigits[i];
+      resultDigits[i + digitShift + 1] = (digit >> carryBitShift) | carry;
+      carry = (digit & bitMask) << bitShift;
+    }
+    resultDigits[digitShift] = carry;
+  }
+
+  /// Shift the bits of this integer to the left by [shiftAmount].
+  ///
+  /// Shifting to the left makes the number larger, effectively multiplying
+  /// the number by `pow(2, shiftIndex)`.
+  ///
+  /// There is no limit on the size of the result. It may be relevant to
+  /// limit intermediate values by using the "and" operator with a suitable
+  /// mask.
+  ///
+  /// It is an error if [shiftAmount] is negative.
+  _BigIntImpl operator <<(int shiftAmount) {
+    if (shiftAmount < 0) {
+      throw new ArgumentError("shift-amount must be posititve $shiftAmount");
+    }
+    if (_isZero) return this;
+    final digitShift = shiftAmount ~/ _digitBits;
+    final bitShift = shiftAmount % _digitBits;
+    if (bitShift == 0) {
+      return _dlShift(digitShift);
+    }
+    var resultUsed = _used + digitShift + 1;
+    var resultDigits = new Uint16List(resultUsed);
+    _lsh(_digits, _used, shiftAmount, resultDigits);
+    return new _BigIntImpl._(_isNegative, resultUsed, resultDigits);
+  }
+
+  // resultDigits[0..resultUsed-1] = xDigits[0..xUsed-1] << n.
+  // Returns resultUsed.
+  static int _lShiftDigits(
+      Uint16List xDigits, int xUsed, int n, Uint16List resultDigits) {
+    final digitsShift = n ~/ _digitBits;
+    final bitShift = n % _digitBits;
+    if (bitShift == 0) {
+      return _dlShiftDigits(xDigits, xUsed, digitsShift, resultDigits);
+    }
+    var resultUsed = xUsed + digitsShift + 1;
+    _lsh(xDigits, xUsed, n, resultDigits);
+    var i = digitsShift;
+    while (--i >= 0) {
+      resultDigits[i] = 0;
+    }
+    if (resultDigits[resultUsed - 1] == 0) {
+      resultUsed--; // Clamp result.
+    }
+    return resultUsed;
+  }
+
+  // resultDigits[0..resultUsed-1] = xDigits[0..xUsed-1] >> n.
+  static void _rsh(
+      Uint16List xDigits, int xUsed, int n, Uint16List resultDigits) {
+    assert(xUsed > 0);
+    final digitsShift = n ~/ _digitBits;
+    final bitShift = n % _digitBits;
+    final carryBitShift = _digitBits - bitShift;
+    final bitMask = (1 << bitShift) - 1;
+    var carry = xDigits[digitsShift] >> bitShift;
+    final last = xUsed - digitsShift - 1;
+    for (var i = 0; i < last; i++) {
+      final digit = xDigits[i + digitsShift + 1];
+      resultDigits[i] = ((digit & bitMask) << carryBitShift) | carry;
+      carry = digit >> bitShift;
+    }
+    resultDigits[last] = carry;
+  }
+
+  /// Shift the bits of this integer to the right by [shiftAmount].
+  ///
+  /// Shifting to the right makes the number smaller and drops the least
+  /// significant bits, effectively doing an integer division by
+  /// `pow(2, shiftIndex)`.
+  ///
+  /// It is an error if [shiftAmount] is negative.
+  _BigIntImpl operator >>(int shiftAmount) {
+    if (shiftAmount < 0) {
+      throw new ArgumentError("shift-amount must be posititve $shiftAmount");
+    }
+    if (_isZero) return this;
+    final digitShift = shiftAmount ~/ _digitBits;
+    final bitShift = shiftAmount % _digitBits;
+    if (bitShift == 0) {
+      return _drShift(digitShift);
+    }
+    final used = _used;
+    final resultUsed = used - digitShift;
+    if (resultUsed <= 0) {
+      return _isNegative ? _minusOne : zero;
+    }
+    final digits = _digits;
+    final resultDigits = new Uint16List(resultUsed);
+    _rsh(digits, used, shiftAmount, resultDigits);
+    final result = new _BigIntImpl._(_isNegative, resultUsed, resultDigits);
+    if (_isNegative) {
+      // Round down if any bit was shifted out.
+      if ((digits[digitShift] & ((1 << bitShift) - 1)) != 0) {
+        return result - one;
+      }
+      for (var i = 0; i < digitShift; i++) {
+        if (digits[i] != 0) {
+          return result - one;
+        }
+      }
+    }
+    return result;
+  }
+
+  /// Compares this to [other] taking the absolute value of both operands.
+  ///
+  /// Returns 0 if abs(this) == abs(other); a positive number if
+  /// abs(this) > abs(other); and a negative number if abs(this) < abs(other).
+  int _absCompare(BigInt bigInt) {
+    _BigIntImpl other = bigInt;
+    return _compareDigits(_digits, _used, other._digits, other._used);
+  }
+
+  /// Compares this to `other`.
+  ///
+  /// Returns a negative number if `this` is less than `other`, zero if they are
+  /// equal, and a positive number if `this` is greater than `other`.
+  int compareTo(BigInt bigInt) {
+    _BigIntImpl other = bigInt;
+    if (_isNegative == other._isNegative) {
+      var result = _absCompare(other);
+      // Use 0 - result to avoid negative zero in JavaScript.
+      return _isNegative ? 0 - result : result;
+    }
+    return _isNegative ? -1 : 1;
+  }
+
+  /// Compares `digits[0..used-1]` with `otherDigits[0..otherUsed-1]`.
+  ///
+  /// Returns 0 if equal; a positive number if larger;
+  /// and a negative number if smaller.
+  static int _compareDigits(
+      Uint16List digits, int used, Uint16List otherDigits, int otherUsed) {
+    var result = used - otherUsed;
+    if (result == 0) {
+      for (int i = used - 1; i >= 0; i--) {
+        result = digits[i] - otherDigits[i];
+        if (result != 0) return result;
+      }
+    }
+    return result;
+  }
+
+  // resultDigits[0..used] = digits[0..used-1] + otherDigits[0..otherUsed-1].
+  // used >= otherUsed > 0.
+  static void _absAdd(Uint16List digits, int used, Uint16List otherDigits,
+      int otherUsed, Uint16List resultDigits) {
+    assert(used >= otherUsed && otherUsed > 0);
+    var carry = 0;
+    for (var i = 0; i < otherUsed; i++) {
+      carry += digits[i] + otherDigits[i];
+      resultDigits[i] = carry & _digitMask;
+      carry >>= _digitBits;
+    }
+    for (var i = otherUsed; i < used; i++) {
+      carry += digits[i];
+      resultDigits[i] = carry & _digitMask;
+      carry >>= _digitBits;
+    }
+    resultDigits[used] = carry;
+  }
+
+  // resultDigits[0..used-1] = digits[0..used-1] - otherDigits[0..otherUsed-1].
+  // used >= otherUsed > 0.
+  static void _absSub(Uint16List digits, int used, Uint16List otherDigits,
+      int otherUsed, Uint16List resultDigits) {
+    assert(used >= otherUsed && otherUsed > 0);
+
+    var carry = 0;
+    for (var i = 0; i < otherUsed; i++) {
+      carry += digits[i] - otherDigits[i];
+      resultDigits[i] = carry & _digitMask;
+      // Dart2js only supports unsigned shifts.
+      // Since the carry can only be -1 or 0 use this hack.
+      carry = 0 - ((carry >> _digitBits) & 1);
+    }
+    for (var i = otherUsed; i < used; i++) {
+      carry += digits[i];
+      resultDigits[i] = carry & _digitMask;
+      // Dart2js only supports unsigned shifts.
+      // Since the carry can only be -1 or 0 use this hack.
+      carry = 0 - ((carry >> _digitBits) & 1);
+    }
+  }
+
+  /// Returns `abs(this) + abs(other)` with sign set according to [isNegative].
+  _BigIntImpl _absAddSetSign(_BigIntImpl other, bool isNegative) {
+    var used = _used;
+    var otherUsed = other._used;
+    if (used < otherUsed) {
+      return other._absAddSetSign(this, isNegative);
+    }
+    if (used == 0) {
+      assert(!isNegative);
+      return zero;
+    }
+    if (otherUsed == 0) {
+      return _isNegative == isNegative ? this : -this;
+    }
+    var resultUsed = used + 1;
+    var resultDigits = new Uint16List(resultUsed);
+    _absAdd(_digits, used, other._digits, otherUsed, resultDigits);
+    return new _BigIntImpl._(isNegative, resultUsed, resultDigits);
+  }
+
+  /// Returns `abs(this) - abs(other)` with sign set according to [isNegative].
+  ///
+  /// Requirement: `abs(this) >= abs(other)`.
+  _BigIntImpl _absSubSetSign(_BigIntImpl other, bool isNegative) {
+    assert(_absCompare(other) >= 0);
+    var used = _used;
+    if (used == 0) {
+      assert(!isNegative);
+      return zero;
+    }
+    var otherUsed = other._used;
+    if (otherUsed == 0) {
+      return _isNegative == isNegative ? this : -this;
+    }
+    var resultDigits = new Uint16List(used);
+    _absSub(_digits, used, other._digits, otherUsed, resultDigits);
+    return new _BigIntImpl._(isNegative, used, resultDigits);
+  }
+
+  /// Returns `abs(this) & abs(other)` with sign set according to [isNegative].
+  _BigIntImpl _absAndSetSign(_BigIntImpl other, bool isNegative) {
+    var resultUsed = _min(_used, other._used);
+    var digits = _digits;
+    var otherDigits = other._digits;
+    var resultDigits = new Uint16List(resultUsed);
+    for (var i = 0; i < resultUsed; i++) {
+      resultDigits[i] = digits[i] & otherDigits[i];
+    }
+    return new _BigIntImpl._(isNegative, resultUsed, resultDigits);
+  }
+
+  /// Returns `abs(this) &~ abs(other)` with sign set according to [isNegative].
+  _BigIntImpl _absAndNotSetSign(_BigIntImpl other, bool isNegative) {
+    var resultUsed = _used;
+    var digits = _digits;
+    var otherDigits = other._digits;
+    var resultDigits = new Uint16List(resultUsed);
+    var m = _min(resultUsed, other._used);
+    for (var i = 0; i < m; i++) {
+      resultDigits[i] = digits[i] & ~otherDigits[i];
+    }
+    for (var i = m; i < resultUsed; i++) {
+      resultDigits[i] = digits[i];
+    }
+    return new _BigIntImpl._(isNegative, resultUsed, resultDigits);
+  }
+
+  /// Returns `abs(this) | abs(other)` with sign set according to [isNegative].
+  _BigIntImpl _absOrSetSign(_BigIntImpl other, bool isNegative) {
+    var used = _used;
+    var otherUsed = other._used;
+    var resultUsed = _max(used, otherUsed);
+    var digits = _digits;
+    var otherDigits = other._digits;
+    var resultDigits = new Uint16List(resultUsed);
+    var l, m;
+    if (used < otherUsed) {
+      l = other;
+      m = used;
+    } else {
+      l = this;
+      m = otherUsed;
+    }
+    for (var i = 0; i < m; i++) {
+      resultDigits[i] = digits[i] | otherDigits[i];
+    }
+    var lDigits = l._digits;
+    for (var i = m; i < resultUsed; i++) {
+      resultDigits[i] = lDigits[i];
+    }
+    return new _BigIntImpl._(isNegative, resultUsed, resultDigits);
+  }
+
+  /// Returns `abs(this) ^ abs(other)` with sign set according to [isNegative].
+  _BigIntImpl _absXorSetSign(_BigIntImpl other, bool isNegative) {
+    var used = _used;
+    var otherUsed = other._used;
+    var resultUsed = _max(used, otherUsed);
+    var digits = _digits;
+    var otherDigits = other._digits;
+    var resultDigits = new Uint16List(resultUsed);
+    var l, m;
+    if (used < otherUsed) {
+      l = other;
+      m = used;
+    } else {
+      l = this;
+      m = otherUsed;
+    }
+    for (var i = 0; i < m; i++) {
+      resultDigits[i] = digits[i] ^ otherDigits[i];
+    }
+    var lDigits = l._digits;
+    for (var i = m; i < resultUsed; i++) {
+      resultDigits[i] = lDigits[i];
+    }
+    return new _BigIntImpl._(isNegative, resultUsed, resultDigits);
+  }
+
+  /// Bit-wise and operator.
+  ///
+  /// Treating both `this` and [other] as sufficiently large two's component
+  /// integers, the result is a number with only the bits set that are set in
+  /// both `this` and [other]
+  ///
+  /// Of both operands are negative, the result is negative, otherwise
+  /// the result is non-negative.
+  _BigIntImpl operator &(BigInt bigInt) {
+    _BigIntImpl other = bigInt;
+    if (_isZero || other._isZero) return zero;
+    if (_isNegative == other._isNegative) {
+      if (_isNegative) {
+        // (-this) & (-other) == ~(this-1) & ~(other-1)
+        //                    == ~((this-1) | (other-1))
+        //                    == -(((this-1) | (other-1)) + 1)
+        _BigIntImpl this1 = _absSubSetSign(one, true);
+        _BigIntImpl other1 = other._absSubSetSign(one, true);
+        // Result cannot be zero if this and other are negative.
+        return this1._absOrSetSign(other1, true)._absAddSetSign(one, true);
+      }
+      return _absAndSetSign(other, false);
+    }
+    // _isNegative != other._isNegative
+    var p, n;
+    if (_isNegative) {
+      p = other;
+      n = this;
+    } else {
+      // & is symmetric.
+      p = this;
+      n = other;
+    }
+    // p & (-n) == p & ~(n-1) == p &~ (n-1)
+    var n1 = n._absSubSetSign(one, false);
+    return p._absAndNotSetSign(n1, false);
+  }
+
+  /// Bit-wise or operator.
+  ///
+  /// Treating both `this` and [other] as sufficiently large two's component
+  /// integers, the result is a number with the bits set that are set in either
+  /// of `this` and [other]
+  ///
+  /// If both operands are non-negative, the result is non-negative,
+  /// otherwise the result us negative.
+  _BigIntImpl operator |(BigInt bigInt) {
+    _BigIntImpl other = bigInt;
+    if (_isZero) return other;
+    if (other._isZero) return this;
+    if (_isNegative == other._isNegative) {
+      if (_isNegative) {
+        // (-this) | (-other) == ~(this-1) | ~(other-1)
+        //                    == ~((this-1) & (other-1))
+        //                    == -(((this-1) & (other-1)) + 1)
+        var this1 = _absSubSetSign(one, true);
+        var other1 = other._absSubSetSign(one, true);
+        // Result cannot be zero if this and a are negative.
+        return this1._absAndSetSign(other1, true)._absAddSetSign(one, true);
+      }
+      return _absOrSetSign(other, false);
+    }
+    // _neg != a._neg
+    var p, n;
+    if (_isNegative) {
+      p = other;
+      n = this;
+    } else {
+      // | is symmetric.
+      p = this;
+      n = other;
+    }
+    // p | (-n) == p | ~(n-1) == ~((n-1) &~ p) == -(~((n-1) &~ p) + 1)
+    var n1 = n._absSubSetSign(one, true);
+    // Result cannot be zero if only one of this or a is negative.
+    return n1._absAndNotSetSign(p, true)._absAddSetSign(one, true);
+  }
+
+  /// Bit-wise exclusive-or operator.
+  ///
+  /// Treating both `this` and [other] as sufficiently large two's component
+  /// integers, the result is a number with the bits set that are set in one,
+  /// but not both, of `this` and [other]
+  ///
+  /// If the operands have the same sign, the result is non-negative,
+  /// otherwise the result is negative.
+  _BigIntImpl operator ^(BigInt bigInt) {
+    _BigIntImpl other = bigInt;
+    if (_isZero) return other;
+    if (other._isZero) return this;
+    if (_isNegative == other._isNegative) {
+      if (_isNegative) {
+        // (-this) ^ (-other) == ~(this-1) ^ ~(other-1) == (this-1) ^ (other-1)
+        var this1 = _absSubSetSign(one, true);
+        var other1 = other._absSubSetSign(one, true);
+        return this1._absXorSetSign(other1, false);
+      }
+      return _absXorSetSign(other, false);
+    }
+    // _isNegative != a._isNegative
+    var p, n;
+    if (_isNegative) {
+      p = other;
+      n = this;
+    } else {
+      // ^ is symmetric.
+      p = this;
+      n = other;
+    }
+    // p ^ (-n) == p ^ ~(n-1) == ~(p ^ (n-1)) == -((p ^ (n-1)) + 1)
+    var n1 = n._absSubSetSign(one, true);
+    // Result cannot be zero if only one of this or a is negative.
+    return p._absXorSetSign(n1, true)._absAddSetSign(one, true);
+  }
+
+  /// The bit-wise negate operator.
+  ///
+  /// Treating `this` as a sufficiently large two's component integer,
+  /// the result is a number with the opposite bits set.
+  ///
+  /// This maps any integer `x` to `-x - 1`.
+  _BigIntImpl operator ~() {
+    if (_isZero) return _minusOne;
+    if (_isNegative) {
+      // ~(-this) == ~(~(this-1)) == this-1
+      return _absSubSetSign(one, false);
+    }
+    // ~this == -this-1 == -(this+1)
+    // Result cannot be zero if this is positive.
+    return _absAddSetSign(one, true);
+  }
+
+  /// Addition operator.
+  _BigIntImpl operator +(BigInt bigInt) {
+    _BigIntImpl other = bigInt;
+    if (_isZero) return other;
+    if (other._isZero) return this;
+    var isNegative = _isNegative;
+    if (isNegative == other._isNegative) {
+      // this + other == this + other
+      // (-this) + (-other) == -(this + other)
+      return _absAddSetSign(other, isNegative);
+    }
+    // this + (-other) == this - other == -(this - other)
+    // (-this) + other == other - this == -(this - other)
+    if (_absCompare(other) >= 0) {
+      return _absSubSetSign(other, isNegative);
+    }
+    return other._absSubSetSign(this, !isNegative);
+  }
+
+  /// Subtraction operator.
+  _BigIntImpl operator -(BigInt bigInt) {
+    _BigIntImpl other = bigInt;
+    if (_isZero) return -other;
+    if (other._isZero) return this;
+    var isNegative = _isNegative;
+    if (isNegative != other._isNegative) {
+      // this - (-other) == this + other
+      // (-this) - other == -(this + other)
+      return _absAddSetSign(other, isNegative);
+    }
+    // this - other == this - a == -(this - other)
+    // (-this) - (-other) == other - this == -(this - other)
+    if (_absCompare(other) >= 0) {
+      return _absSubSetSign(other, isNegative);
+    }
+    return other._absSubSetSign(this, !isNegative);
+  }
+
+  /// Multiplies [x] with [multiplicandDigits] and adds the result to
+  /// [accumulatorDigits].
+  ///
+  /// The [multiplicandDigits] in the range [i] to [i]+[n]-1 are the
+  /// multiplicand digits.
+  ///
+  /// The [acculumatorDigits] in the range [j] to [j]+[n]-1 are the accumulator
+  /// digits.
+  ///
+  /// Adds the result of the multiplicand-digits * [x] to the accumulator.
+  ///
+  /// Concretely: `accumulatorDigits[j..j+n] += x * m_digits[i..i+n-1]`.
+  static void _mulAdd(int x, Uint16List multiplicandDigits, int i,
+      Uint16List accumulatorDigits, int j, int n) {
+    if (x == 0) {
+      // No-op if x is 0.
+      return;
+    }
+    int c = 0;
+    while (--n >= 0) {
+      int product = x * multiplicandDigits[i++];
+      int combined = product + accumulatorDigits[j] + c;
+      accumulatorDigits[j++] = combined & _digitMask;
+      // Note that this works with 53 bits, as the division will not lose
+      // bits.
+      c = combined ~/ _digitBase;
+    }
+    while (c != 0) {
+      int l = accumulatorDigits[j] + c;
+      accumulatorDigits[j++] = l & _digitMask;
+      c = l ~/ _digitBase;
+    }
+  }
+
+  /// Multiplication operator.
+  _BigIntImpl operator *(BigInt bigInt) {
+    _BigIntImpl other = bigInt;
+    var used = _used;
+    var otherUsed = other._used;
+    if (used == 0 || otherUsed == 0) {
+      return zero;
+    }
+    var resultUsed = used + otherUsed;
+    var digits = _digits;
+    var otherDigits = other._digits;
+    var resultDigits = new Uint16List(resultUsed);
+    var i = 0;
+    while (i < otherUsed) {
+      _mulAdd(otherDigits[i], digits, 0, resultDigits, i, used);
+      i++;
+    }
+    return new _BigIntImpl._(
+        _isNegative != other._isNegative, resultUsed, resultDigits);
+  }
+
+  // r_digits[0..rUsed-1] = xDigits[0..xUsed-1]*otherDigits[0..otherUsed-1].
+  // Return resultUsed = xUsed + otherUsed.
+  static int _mulDigits(Uint16List xDigits, int xUsed, Uint16List otherDigits,
+      int otherUsed, Uint16List resultDigits) {
+    var resultUsed = xUsed + otherUsed;
+    var i = resultUsed;
+    assert(resultDigits.length >= i);
+    while (--i >= 0) {
+      resultDigits[i] = 0;
+    }
+    i = 0;
+    while (i < otherUsed) {
+      _mulAdd(otherDigits[i], xDigits, 0, resultDigits, i, xUsed);
+      i++;
+    }
+    return resultUsed;
+  }
+
+  /// Returns an estimate of `digits[i-1..i] ~/ topDigitDivisor`.
+  static int _estimateQuotientDigit(
+      int topDigitDivisor, Uint16List digits, int i) {
+    if (digits[i] == topDigitDivisor) return _digitMask;
+    var quotientDigit =
+        (digits[i] << _digitBits | digits[i - 1]) ~/ topDigitDivisor;
+    if (quotientDigit > _digitMask) return _digitMask;
+    return quotientDigit;
+  }
+
+  /// Returns `trunc(this / other)`, with `other != 0`.
+  _BigIntImpl _div(BigInt bigInt) {
+    _BigIntImpl other = bigInt;
+    assert(other._used > 0);
+    if (_used < other._used) {
+      return zero;
+    }
+    _divRem(other);
+    // Return quotient, i.e.
+    // _lastQuoRem_digits[_lastRem_used.._lastQuoRem_used-1] with proper sign.
+    var lastQuo_used = _lastQuoRemUsed - _lastRemUsed;
+    var quo_digits = _cloneDigits(
+        _lastQuoRemDigits, _lastRemUsed, _lastQuoRemUsed, lastQuo_used);
+    var quo = new _BigIntImpl._(false, lastQuo_used, quo_digits);
+    if ((_isNegative != other._isNegative) && (quo._used > 0)) {
+      quo = -quo;
+    }
+    return quo;
+  }
+
+  /// Returns `this - other * trunc(this / other)`, with `other != 0`.
+  _BigIntImpl _rem(BigInt bigInt) {
+    _BigIntImpl other = bigInt;
+    assert(other._used > 0);
+    if (_used < other._used) {
+      return this;
+    }
+    _divRem(other);
+    // Return remainder, i.e.
+    // denormalized _lastQuoRem_digits[0.._lastRem_used-1] with proper sign.
+    var remDigits =
+        _cloneDigits(_lastQuoRemDigits, 0, _lastRemUsed, _lastRemUsed);
+    var rem = new _BigIntImpl._(false, _lastRemUsed, remDigits);
+    if (_lastRem_nsh > 0) {
+      rem = rem >> _lastRem_nsh; // Denormalize remainder.
+    }
+    if (_isNegative && (rem._used > 0)) {
+      rem = -rem;
+    }
+    return rem;
+  }
+
+  /// Computes this ~/ other and this.remainder(other).
+  ///
+  /// Stores the result in [_lastQuoRemDigits], [_lastQuoRemUsed] and
+  /// [_lastRemUsed]. The [_lastQuoRemDigits] contains the digits of *both*, the
+  /// quotient and the remainder.
+  ///
+  /// Caches the input to avoid doing the work again when users write
+  /// `a ~/ b` followed by a `a % b`.
+  void _divRem(_BigIntImpl other) {
+    // Check if result is already cached.
+    if ((this._used == _lastDividendUsed) &&
+        (other._used == _lastDivisorUsed) &&
+        identical(this._digits, _lastDividendDigits) &&
+        identical(other._digits, _lastDivisorDigits)) {
+      return;
+    }
+    assert(_used >= other._used);
+
+    var nsh = _digitBits - other._digits[other._used - 1].bitLength;
+    // Concatenated positive quotient and normalized positive remainder.
+    // The resultDigits can have at most one more digit than the dividend.
+    Uint16List resultDigits;
+    int resultUsed;
+    // Normalized positive divisor.
+    // The normalized divisor has the most-significant bit of its most
+    // significant digit set.
+    // This makes estimating the quotient easier.
+    Uint16List yDigits;
+    int yUsed;
+    if (nsh > 0) {
+      yDigits = new Uint16List(other._used + 5);
+      yUsed = _lShiftDigits(other._digits, other._used, nsh, yDigits);
+      resultDigits = new Uint16List(_used + 5);
+      resultUsed = _lShiftDigits(_digits, _used, nsh, resultDigits);
+    } else {
+      yDigits = other._digits;
+      yUsed = other._used;
+      resultDigits = _cloneDigits(_digits, 0, _used, _used + 2);
+      resultUsed = _used;
+    }
+    var topDigitDivisor = yDigits[yUsed - 1];
+    var i = resultUsed;
+    var j = i - yUsed;
+    // tmpDigits is a temporary array of i (resultUsed) digits.
+    var tmpDigits = new Uint16List(i);
+    var tmpUsed = _dlShiftDigits(yDigits, yUsed, j, tmpDigits);
+    // Explicit first division step in case normalized dividend is larger or
+    // equal to shifted normalized divisor.
+    if (_compareDigits(resultDigits, resultUsed, tmpDigits, tmpUsed) >= 0) {
+      assert(i == resultUsed);
+      resultDigits[resultUsed++] = 1; // Quotient = 1.
+      // Subtract divisor from remainder.
+      _absSub(resultDigits, resultUsed, tmpDigits, tmpUsed, resultDigits);
+    } else {
+      // Account for possible carry in _mulAdd step.
+      resultDigits[resultUsed++] = 0;
+    }
+
+    // Negate y so we can later use _mulAdd instead of non-existent _mulSub.
+    var nyDigits = new Uint16List(yUsed + 2);
+    nyDigits[yUsed] = 1;
+    _absSub(nyDigits, yUsed + 1, yDigits, yUsed, nyDigits);
+    // nyDigits is read-only and has yUsed digits (possibly including several
+    // leading zeros).
+    // resultDigits is modified during iteration.
+    // resultDigits[0..yUsed-1] is the current remainder.
+    // resultDigits[yUsed..resultUsed-1] is the current quotient.
+    --i;
+
+    while (j > 0) {
+      var estimatedQuotientDigit =
+          _estimateQuotientDigit(topDigitDivisor, resultDigits, i);
+      j--;
+      _mulAdd(estimatedQuotientDigit, nyDigits, 0, resultDigits, j, yUsed);
+      if (resultDigits[i] < estimatedQuotientDigit) {
+        // Reusing the already existing tmpDigits array.
+        var tmpUsed = _dlShiftDigits(nyDigits, yUsed, j, tmpDigits);
+        _absSub(resultDigits, resultUsed, tmpDigits, tmpUsed, resultDigits);
+        while (resultDigits[i] < --estimatedQuotientDigit) {
+          _absSub(resultDigits, resultUsed, tmpDigits, tmpUsed, resultDigits);
+        }
+      }
+      i--;
+    }
+    // Cache result.
+    _lastDividendDigits = _digits;
+    _lastDividendUsed = _used;
+    _lastDivisorDigits = other._digits;
+    _lastDivisorUsed = other._used;
+    _lastQuoRemDigits = resultDigits;
+    _lastQuoRemUsed = resultUsed;
+    _lastRemUsed = yUsed;
+    _lastRem_nsh = nsh;
+  }
+
+  int get hashCode {
+    // This is the [Jenkins hash function][1] but using masking to keep
+    // values in SMI range.
+    //
+    // [1]: http://en.wikipedia.org/wiki/Jenkins_hash_function
+
+    int combine(int hash, int value) {
+      hash = 0x1fffffff & (hash + value);
+      hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10));
+      return hash ^ (hash >> 6);
+    }
+
+    int finish(int hash) {
+      hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3));
+      hash = hash ^ (hash >> 11);
+      return 0x1fffffff & (hash + ((0x00003fff & hash) << 15));
+    }
+
+    if (_isZero) return 6707; // Just a random number.
+    var hash = _isNegative ? 83585 : 429689; // Also random.
+    for (int i = 0; i < _used; i++) {
+      hash = combine(hash, _digits[i]);
+    }
+    return finish(hash);
+  }
+
+  /// Test whether this value is numerically equal to `other`.
+  ///
+  /// If [other] is a [_BigIntImpl] returns whether the two operands have the
+  /// same value.
+  ///
+  /// Returns false if `other` is not a [_BigIntImpl].
+  bool operator ==(Object other) =>
+      other is _BigIntImpl && compareTo(other) == 0;
+
+  /// Returns the minimum number of bits required to store this big integer.
+  ///
+  /// The number of bits excludes the sign bit, which gives the natural length
+  /// for non-negative (unsigned) values.  Negative values are complemented to
+  /// return the bit position of the first bit that differs from the sign bit.
+  ///
+  /// To find the number of bits needed to store the value as a signed value,
+  /// add one, i.e. use `x.bitLength + 1`.
+  ///
+  /// ```
+  /// x.bitLength == (-x-1).bitLength
+  ///
+  /// new BigInt.from(3).bitLength == 2;   // 00000011
+  /// new BigInt.from(2).bitLength == 2;   // 00000010
+  /// new BigInt.from(1).bitLength == 1;   // 00000001
+  /// new BigInt.from(0).bitLength == 0;   // 00000000
+  /// new BigInt.from(-1).bitLength == 0;  // 11111111
+  /// new BigInt.from(-2).bitLength == 1;  // 11111110
+  /// new BigInt.from(-3).bitLength == 2;  // 11111101
+  /// new BigInt.from(-4).bitLength == 2;  // 11111100
+  /// ```
+  int get bitLength {
+    if (_used == 0) return 0;
+    if (_isNegative) return (~this).bitLength;
+    return _digitBits * (_used - 1) + _digits[_used - 1].bitLength;
+  }
+
+  /// Truncating division operator.
+  ///
+  /// Performs a truncating integer division, where the remainder is discarded.
+  ///
+  /// The remainder can be computed using the [remainder] method.
+  ///
+  /// Examples:
+  /// ```
+  /// var seven = new BigInt.from(7);
+  /// var three = new BigInt.from(3);
+  /// seven ~/ three;    // => 2
+  /// (-seven) ~/ three; // => -2
+  /// seven ~/ -three;   // => -2
+  /// seven.remainder(three);    // => 1
+  /// (-seven).remainder(three); // => -1
+  /// seven.remainder(-three);   // => 1
+  /// ```
+  _BigIntImpl operator ~/(BigInt bigInt) {
+    _BigIntImpl other = bigInt;
+    if (other._used == 0) {
+      throw const IntegerDivisionByZeroException();
+    }
+    return _div(other);
+  }
+
+  /// Returns the remainder of the truncating division of `this` by [other].
+  ///
+  /// The result `r` of this operation satisfies:
+  /// `this == (this ~/ other) * other + r`.
+  /// As a consequence the remainder `r` has the same sign as the divider
+  /// `this`.
+  _BigIntImpl remainder(BigInt bigInt) {
+    _BigIntImpl other = bigInt;
+    if (other._used == 0) {
+      throw const IntegerDivisionByZeroException();
+    }
+    return _rem(other);
+  }
+
+  /// Division operator.
+  double operator /(BigInt other) => this.toDouble() / other.toDouble();
+
+  /// Relational less than operator.
+  bool operator <(BigInt other) => compareTo(other) < 0;
+
+  /// Relational less than or equal operator.
+  bool operator <=(BigInt other) => compareTo(other) <= 0;
+
+  /// Relational greater than operator.
+  bool operator >(BigInt other) => compareTo(other) > 0;
+
+  /// Relational greater than or equal operator.
+  bool operator >=(BigInt other) => compareTo(other) >= 0;
+
+  /// Euclidean modulo operator.
+  ///
+  /// Returns the remainder of the Euclidean division. The Euclidean division of
+  /// two integers `a` and `b` yields two integers `q` and `r` such that
+  /// `a == b * q + r` and `0 <= r < b.abs()`.
+  ///
+  /// The sign of the returned value `r` is always positive.
+  ///
+  /// See [remainder] for the remainder of the truncating division.
+  _BigIntImpl operator %(BigInt bigInt) {
+    _BigIntImpl other = bigInt;
+    if (other._used == 0) {
+      throw const IntegerDivisionByZeroException();
+    }
+    var result = _rem(other);
+    if (result._isNegative) {
+      if (other._isNegative) {
+        result = result - other;
+      } else {
+        result = result + other;
+      }
+    }
+    return result;
+  }
+
+  /// Returns the sign of this big integer.
+  ///
+  /// Returns 0 for zero, -1 for values less than zero and
+  /// +1 for values greater than zero.
+  int get sign {
+    if (_used == 0) return 0;
+    return _isNegative ? -1 : 1;
+  }
+
+  /// Whether this big integer is even.
+  bool get isEven => _used == 0 || (_digits[0] & 1) == 0;
+
+  /// Whether this big integer is odd.
+  bool get isOdd => !isEven;
+
+  /// Whether this number is negative.
+  bool get isNegative => _isNegative;
+
+  _BigIntImpl pow(int exponent) {
+    if (exponent < 0) {
+      throw new ArgumentError("Exponent must not be negative: $exponent");
+    }
+    if (exponent == 0) return one;
+
+    // Exponentiation by squaring.
+    var result = one;
+    var base = this;
+    while (exponent != 0) {
+      if ((exponent & 1) == 1) {
+        result *= base;
+      }
+      exponent >>= 1;
+      // Skip unnecessary operation.
+      if (exponent != 0) {
+        base *= base;
+      }
+    }
+    return result;
+  }
+
+  /// Returns this integer to the power of [exponent] modulo [modulus].
+  ///
+  /// The [exponent] must be non-negative and [modulus] must be
+  /// positive.
+  _BigIntImpl modPow(BigInt bigExponent, BigInt bigModulus) {
+    _BigIntImpl exponent = bigExponent;
+    _BigIntImpl modulus = bigModulus;
+    if (exponent._isNegative) {
+      throw new ArgumentError("exponent must be positive: $exponent");
+    }
+    if (modulus <= zero) {
+      throw new ArgumentError("modulus must be strictly positive: $modulus");
+    }
+    if (exponent._isZero) return one;
+
+    final modulusUsed = modulus._used;
+    final modulusUsed2p4 = 2 * modulusUsed + 4;
+    final exponentBitlen = exponent.bitLength;
+    if (exponentBitlen <= 0) return one;
+    _BigIntReduction z = new _BigIntClassic(modulus);
+    var resultDigits = new Uint16List(modulusUsed2p4);
+    var result2Digits = new Uint16List(modulusUsed2p4);
+    var gDigits = new Uint16List(modulusUsed);
+    var gUsed = z.convert(this, gDigits);
+    // Initialize result with g.
+    // Copy leading zero if any.
+    for (int j = gUsed - 1; j >= 0; j--) {
+      resultDigits[j] = gDigits[j];
+    }
+    var resultUsed = gUsed;
+    var result2Used;
+    for (int i = exponentBitlen - 2; i >= 0; i--) {
+      result2Used = z.sqr(resultDigits, resultUsed, result2Digits);
+      if (!(exponent & (one << i))._isZero) {
+        resultUsed =
+            z.mul(result2Digits, result2Used, gDigits, gUsed, resultDigits);
+      } else {
+        // Swap result and result2.
+        var tmpDigits = resultDigits;
+        var tmpUsed = resultUsed;
+        resultDigits = result2Digits;
+        resultUsed = result2Used;
+        result2Digits = tmpDigits;
+        result2Used = tmpUsed;
+      }
+    }
+    return z.revert(resultDigits, resultUsed);
+  }
+
+  // If inv is false, returns gcd(x, y).
+  // If inv is true and gcd(x, y) = 1, returns d, so that c*x + d*y = 1.
+  // If inv is true and gcd(x, y) != 1, throws Exception("Not coprime").
+  static _BigIntImpl _binaryGcd(_BigIntImpl x, _BigIntImpl y, bool inv) {
+    var xDigits = x._digits;
+    var yDigits = y._digits;
+    var xUsed = x._used;
+    var yUsed = y._used;
+    var maxUsed = xUsed > yUsed ? xUsed : yUsed;
+    var unshiftedMaxUsed = maxUsed; // Keep
+    xDigits = _cloneDigits(xDigits, 0, xUsed, maxUsed);
+    yDigits = _cloneDigits(yDigits, 0, yUsed, maxUsed);
+    int shiftAmount = 0;
+    if (inv) {
+      if ((yUsed == 1) && (yDigits[0] == 1)) return one;
+      if ((yUsed == 0) || (yDigits[0].isEven && xDigits[0].isEven)) {
+        throw new Exception("Not coprime");
+      }
+    } else {
+      if (x._isZero) {
+        throw new ArgumentError.value(0, "this", "must not be zero");
+      }
+      if (y._isZero) {
+        throw new ArgumentError.value(0, "other", "must not be zero");
+      }
+      if (((xUsed == 1) && (xDigits[0] == 1)) ||
+          ((yUsed == 1) && (yDigits[0] == 1))) return one;
+      while (((xDigits[0] & 1) == 0) && ((yDigits[0] & 1) == 0)) {
+        _rsh(xDigits, xUsed, 1, xDigits);
+        _rsh(yDigits, yUsed, 1, yDigits);
+        shiftAmount++;
+      }
+      if (shiftAmount >= _digitBits) {
+        var digitShiftAmount = shiftAmount ~/ _digitBits;
+        xUsed -= digitShiftAmount;
+        yUsed -= digitShiftAmount;
+        maxUsed -= digitShiftAmount;
+      }
+      if ((yDigits[0] & 1) == 1) {
+        // Swap x and y.
+        var tmpDigits = xDigits;
+        var tmpUsed = xUsed;
+        xDigits = yDigits;
+        xUsed = yUsed;
+        yDigits = tmpDigits;
+        yUsed = tmpUsed;
+      }
+    }
+    var uDigits = _cloneDigits(xDigits, 0, xUsed, unshiftedMaxUsed);
+    var vDigits =
+        _cloneDigits(yDigits, 0, yUsed, unshiftedMaxUsed + 2); // +2 for lsh.
+    final bool ac = (xDigits[0] & 1) == 0;
+
+    // Variables a, b, c, and d require one more digit.
+    final abcdUsed = maxUsed + 1;
+    final abcdLen = abcdUsed + 2; // +2 to satisfy _absAdd.
+    var aDigits, bDigits, cDigits, dDigits;
+    bool aIsNegative, bIsNegative, cIsNegative, dIsNegative;
+    if (ac) {
+      aDigits = new Uint16List(abcdLen);
+      aIsNegative = false;
+      aDigits[0] = 1;
+      cDigits = new Uint16List(abcdLen);
+      cIsNegative = false;
+    }
+    bDigits = new Uint16List(abcdLen);
+    bIsNegative = false;
+    dDigits = new Uint16List(abcdLen);
+    dIsNegative = false;
+    dDigits[0] = 1;
+
+    while (true) {
+      while ((uDigits[0] & 1) == 0) {
+        _rsh(uDigits, maxUsed, 1, uDigits);
+        if (ac) {
+          if (((aDigits[0] & 1) == 1) || ((bDigits[0] & 1) == 1)) {
+            // a += y
+            if (aIsNegative) {
+              if ((aDigits[maxUsed] != 0) ||
+                  (_compareDigits(aDigits, maxUsed, yDigits, maxUsed)) > 0) {
+                _absSub(aDigits, abcdUsed, yDigits, maxUsed, aDigits);
+              } else {
+                _absSub(yDigits, maxUsed, aDigits, maxUsed, aDigits);
+                aIsNegative = false;
+              }
+            } else {
+              _absAdd(aDigits, abcdUsed, yDigits, maxUsed, aDigits);
+            }
+            // b -= x
+            if (bIsNegative) {
+              _absAdd(bDigits, abcdUsed, xDigits, maxUsed, bDigits);
+            } else if ((bDigits[maxUsed] != 0) ||
+                (_compareDigits(bDigits, maxUsed, xDigits, maxUsed) > 0)) {
+              _absSub(bDigits, abcdUsed, xDigits, maxUsed, bDigits);
+            } else {
+              _absSub(xDigits, maxUsed, bDigits, maxUsed, bDigits);
+              bIsNegative = true;
+            }
+          }
+          _rsh(aDigits, abcdUsed, 1, aDigits);
+        } else if ((bDigits[0] & 1) == 1) {
+          // b -= x
+          if (bIsNegative) {
+            _absAdd(bDigits, abcdUsed, xDigits, maxUsed, bDigits);
+          } else if ((bDigits[maxUsed] != 0) ||
+              (_compareDigits(bDigits, maxUsed, xDigits, maxUsed) > 0)) {
+            _absSub(bDigits, abcdUsed, xDigits, maxUsed, bDigits);
+          } else {
+            _absSub(xDigits, maxUsed, bDigits, maxUsed, bDigits);
+            bIsNegative = true;
+          }
+        }
+        _rsh(bDigits, abcdUsed, 1, bDigits);
+      }
+      while ((vDigits[0] & 1) == 0) {
+        _rsh(vDigits, maxUsed, 1, vDigits);
+        if (ac) {
+          if (((cDigits[0] & 1) == 1) || ((dDigits[0] & 1) == 1)) {
+            // c += y
+            if (cIsNegative) {
+              if ((cDigits[maxUsed] != 0) ||
+                  (_compareDigits(cDigits, maxUsed, yDigits, maxUsed) > 0)) {
+                _absSub(cDigits, abcdUsed, yDigits, maxUsed, cDigits);
+              } else {
+                _absSub(yDigits, maxUsed, cDigits, maxUsed, cDigits);
+                cIsNegative = false;
+              }
+            } else {
+              _absAdd(cDigits, abcdUsed, yDigits, maxUsed, cDigits);
+            }
+            // d -= x
+            if (dIsNegative) {
+              _absAdd(dDigits, abcdUsed, xDigits, maxUsed, dDigits);
+            } else if ((dDigits[maxUsed] != 0) ||
+                (_compareDigits(dDigits, maxUsed, xDigits, maxUsed) > 0)) {
+              _absSub(dDigits, abcdUsed, xDigits, maxUsed, dDigits);
+            } else {
+              _absSub(xDigits, maxUsed, dDigits, maxUsed, dDigits);
+              dIsNegative = true;
+            }
+          }
+          _rsh(cDigits, abcdUsed, 1, cDigits);
+        } else if ((dDigits[0] & 1) == 1) {
+          // d -= x
+          if (dIsNegative) {
+            _absAdd(dDigits, abcdUsed, xDigits, maxUsed, dDigits);
+          } else if ((dDigits[maxUsed] != 0) ||
+              (_compareDigits(dDigits, maxUsed, xDigits, maxUsed) > 0)) {
+            _absSub(dDigits, abcdUsed, xDigits, maxUsed, dDigits);
+          } else {
+            _absSub(xDigits, maxUsed, dDigits, maxUsed, dDigits);
+            dIsNegative = true;
+          }
+        }
+        _rsh(dDigits, abcdUsed, 1, dDigits);
+      }
+      if (_compareDigits(uDigits, maxUsed, vDigits, maxUsed) >= 0) {
+        // u -= v
+        _absSub(uDigits, maxUsed, vDigits, maxUsed, uDigits);
+        if (ac) {
+          // a -= c
+          if (aIsNegative == cIsNegative) {
+            var a_cmp_c = _compareDigits(aDigits, abcdUsed, cDigits, abcdUsed);
+            if (a_cmp_c > 0) {
+              _absSub(aDigits, abcdUsed, cDigits, abcdUsed, aDigits);
+            } else {
+              _absSub(cDigits, abcdUsed, aDigits, abcdUsed, aDigits);
+              aIsNegative = !aIsNegative && (a_cmp_c != 0);
+            }
+          } else {
+            _absAdd(aDigits, abcdUsed, cDigits, abcdUsed, aDigits);
+          }
+        }
+        // b -= d
+        if (bIsNegative == dIsNegative) {
+          var b_cmp_d = _compareDigits(bDigits, abcdUsed, dDigits, abcdUsed);
+          if (b_cmp_d > 0) {
+            _absSub(bDigits, abcdUsed, dDigits, abcdUsed, bDigits);
+          } else {
+            _absSub(dDigits, abcdUsed, bDigits, abcdUsed, bDigits);
+            bIsNegative = !bIsNegative && (b_cmp_d != 0);
+          }
+        } else {
+          _absAdd(bDigits, abcdUsed, dDigits, abcdUsed, bDigits);
+        }
+      } else {
+        // v -= u
+        _absSub(vDigits, maxUsed, uDigits, maxUsed, vDigits);
+        if (ac) {
+          // c -= a
+          if (cIsNegative == aIsNegative) {
+            var c_cmp_a = _compareDigits(cDigits, abcdUsed, aDigits, abcdUsed);
+            if (c_cmp_a > 0) {
+              _absSub(cDigits, abcdUsed, aDigits, abcdUsed, cDigits);
+            } else {
+              _absSub(aDigits, abcdUsed, cDigits, abcdUsed, cDigits);
+              cIsNegative = !cIsNegative && (c_cmp_a != 0);
+            }
+          } else {
+            _absAdd(cDigits, abcdUsed, aDigits, abcdUsed, cDigits);
+          }
+        }
+        // d -= b
+        if (dIsNegative == bIsNegative) {
+          var d_cmp_b = _compareDigits(dDigits, abcdUsed, bDigits, abcdUsed);
+          if (d_cmp_b > 0) {
+            _absSub(dDigits, abcdUsed, bDigits, abcdUsed, dDigits);
+          } else {
+            _absSub(bDigits, abcdUsed, dDigits, abcdUsed, dDigits);
+            dIsNegative = !dIsNegative && (d_cmp_b != 0);
+          }
+        } else {
+          _absAdd(dDigits, abcdUsed, bDigits, abcdUsed, dDigits);
+        }
+      }
+      // Exit loop if u == 0.
+      var i = maxUsed;
+      while ((i > 0) && (uDigits[i - 1] == 0)) --i;
+      if (i == 0) break;
+    }
+    if (!inv) {
+      if (shiftAmount > 0) {
+        maxUsed = _lShiftDigits(vDigits, maxUsed, shiftAmount, vDigits);
+      }
+      return new _BigIntImpl._(false, maxUsed, vDigits);
+    }
+    // No inverse if v != 1.
+    var i = maxUsed - 1;
+    while ((i > 0) && (vDigits[i] == 0)) --i;
+    if ((i != 0) || (vDigits[0] != 1)) {
+      throw new Exception("Not coprime");
+    }
+
+    if (dIsNegative) {
+      while ((dDigits[maxUsed] != 0) ||
+          (_compareDigits(dDigits, maxUsed, xDigits, maxUsed) > 0)) {
+        // d += x, d still negative
+        _absSub(dDigits, abcdUsed, xDigits, maxUsed, dDigits);
+      }
+      // d += x
+      _absSub(xDigits, maxUsed, dDigits, maxUsed, dDigits);
+      dIsNegative = false;
+    } else {
+      while ((dDigits[maxUsed] != 0) ||
+          (_compareDigits(dDigits, maxUsed, xDigits, maxUsed) >= 0)) {
+        // d -= x
+        _absSub(dDigits, abcdUsed, xDigits, maxUsed, dDigits);
+      }
+    }
+    return new _BigIntImpl._(false, maxUsed, dDigits);
+  }
+
+  /// Returns the modular multiplicative inverse of this big integer
+  /// modulo [modulus].
+  ///
+  /// The [modulus] must be positive.
+  ///
+  /// It is an error if no modular inverse exists.
+  // Returns 1/this % modulus, with modulus > 0.
+  _BigIntImpl modInverse(BigInt bigInt) {
+    _BigIntImpl modulus = bigInt;
+    if (modulus <= zero) {
+      throw new ArgumentError("Modulus must be strictly positive: $modulus");
+    }
+    if (modulus == one) return zero;
+    var tmp = this;
+    if (tmp._isNegative || (tmp._absCompare(modulus) >= 0)) {
+      tmp %= modulus;
+    }
+    return _binaryGcd(modulus, tmp, true);
+  }
+
+  /// Returns the greatest common divisor of this big integer and [other].
+  ///
+  /// If either number is non-zero, the result is the numerically greatest
+  /// integer dividing both `this` and `other`.
+  ///
+  /// The greatest common divisor is independent of the order,
+  /// so `x.gcd(y)` is  always the same as `y.gcd(x)`.
+  ///
+  /// For any integer `x`, `x.gcd(x)` is `x.abs()`.
+  ///
+  /// If both `this` and `other` is zero, the result is also zero.
+  _BigIntImpl gcd(BigInt bigInt) {
+    _BigIntImpl other = bigInt;
+    if (_isZero) return other.abs();
+    if (other._isZero) return this.abs();
+    return _binaryGcd(this, other, false);
+  }
+
+  /// Returns the least significant [width] bits of this big integer as a
+  /// non-negative number (i.e. unsigned representation).  The returned value
+  /// has zeros in all bit positions higher than [width].
+  ///
+  /// ```
+  /// new BigInt.from(-1).toUnsigned(5) == 31   // 11111111  ->  00011111
+  /// ```
+  ///
+  /// This operation can be used to simulate arithmetic from low level
+  /// languages.  For example, to increment an 8 bit quantity:
+  ///
+  /// ```
+  /// q = (q + 1).toUnsigned(8);
+  /// ```
+  ///
+  /// `q` will count from `0` up to `255` and then wrap around to `0`.
+  ///
+  /// If the input fits in [width] bits without truncation, the result is the
+  /// same as the input.  The minimum width needed to avoid truncation of `x` is
+  /// given by `x.bitLength`, i.e.
+  ///
+  /// ```
+  /// x == x.toUnsigned(x.bitLength);
+  /// ```
+  _BigIntImpl toUnsigned(int width) {
+    return this & ((one << width) - one);
+  }
+
+  /// Returns the least significant [width] bits of this integer, extending the
+  /// highest retained bit to the sign.  This is the same as truncating the
+  /// value to fit in [width] bits using an signed 2-s complement
+  /// representation.  The returned value has the same bit value in all
+  /// positions higher than [width].
+  ///
+  /// ```
+  /// var big15 = new BigInt.from(15);
+  /// var big16 = new BigInt.from(16);
+  /// var big239 = new BigInt.from(239);
+  ///                                      V--sign bit-V
+  /// big16.toSigned(5) == -big16   //  00010000 -> 11110000
+  /// big239.toSigned(5) == big15   //  11101111 -> 00001111
+  ///                                      ^           ^
+  /// ```
+  ///
+  /// This operation can be used to simulate arithmetic from low level
+  /// languages.  For example, to increment an 8 bit signed quantity:
+  ///
+  /// ```
+  /// q = (q + 1).toSigned(8);
+  /// ```
+  ///
+  /// `q` will count from `0` up to `127`, wrap to `-128` and count back up to
+  /// `127`.
+  ///
+  /// If the input value fits in [width] bits without truncation, the result is
+  /// the same as the input.  The minimum width needed to avoid truncation of
+  /// `x` is `x.bitLength + 1`, i.e.
+  ///
+  /// ```
+  /// x == x.toSigned(x.bitLength + 1);
+  /// ```
+  _BigIntImpl toSigned(int width) {
+    // The value of binary number weights each bit by a power of two.  The
+    // twos-complement value weights the sign bit negatively.  We compute the
+    // value of the negative weighting by isolating the sign bit with the
+    // correct power of two weighting and subtracting it from the value of the
+    // lower bits.
+    var signMask = one << (width - 1);
+    return (this & (signMask - one)) - (this & signMask);
+  }
+
+  // Maximum number of digits that always fit in mantissa.
+  static const _simpleValidIntDigits = 53 ~/ _digitBits;
+
+  bool get isValidInt {
+    if (_used <= _simpleValidIntDigits) return true;
+    var asInt = toInt();
+    if (!asInt.toDouble().isFinite) return false;
+    return this == new _BigIntImpl._fromInt(asInt);
+  }
+
+  int toInt() {
+    var result = 0;
+    for (int i = _used - 1; i >= 0; i--) {
+      result = result * _digitBase + _digits[i];
+    }
+    return _isNegative ? -result : result;
+  }
+
+  /// Returns this [_BigIntImpl] as a [double].
+  ///
+  /// If the number is not representable as a [double], an
+  /// approximation is returned. For numerically large integers, the
+  /// approximation may be infinite.
+  double toDouble() {
+    const int exponentBias = 1075;
+    // There are 11 bits for the exponent.
+    // 2047 (all bits set to 1) is reserved for infinity and NaN.
+    // When storing the exponent in the 11 bits, it is biased by exponentBias
+    // to support negative exponents.
+    const int maxDoubleExponent = 2046 - exponentBias;
+    if (_isZero) return 0.0;
+
+    // We fill the 53 bits little-endian.
+    var resultBits = new Uint8List(8);
+
+    var length = _digitBits * (_used - 1) + _digits[_used - 1].bitLength;
+    if (length > maxDoubleExponent + 53) {
+      return _isNegative ? double.negativeInfinity : double.infinity;
+    }
+
+    // The most significant bit is for the sign.
+    if (_isNegative) resultBits[7] = 0x80;
+
+    // Write the exponent into bits 1..12:
+    var biasedExponent = length - 53 + exponentBias;
+    resultBits[6] = (biasedExponent & 0xF) << 4;
+    resultBits[7] |= biasedExponent >> 4;
+
+    int cachedBits = 0;
+    int cachedBitsLength = 0;
+    int digitIndex = _used - 1;
+    int readBits(int n) {
+      // Ensure that we have enough bits in [cachedBits].
+      while (cachedBitsLength < n) {
+        int nextDigit;
+        int nextDigitLength = _digitBits; // May get updated.
+        if (digitIndex < 0) {
+          nextDigit = 0;
+          digitIndex--;
+        } else {
+          nextDigit = _digits[digitIndex];
+          if (digitIndex == _used - 1) nextDigitLength = nextDigit.bitLength;
+          digitIndex--;
+        }
+        cachedBits = (cachedBits << nextDigitLength) + nextDigit;
+        cachedBitsLength += nextDigitLength;
+      }
+      // Read the top [n] bits.
+      var result = cachedBits >> (cachedBitsLength - n);
+      // Remove the bits from the cache.
+      cachedBits -= result << (cachedBitsLength - n);
+      cachedBitsLength -= n;
+      return result;
+    }
+
+    // The first leading 1 bit is implicit in the double-representation and can
+    // be discarded.
+    var leadingBits = readBits(5) & 0xF;
+    resultBits[6] |= leadingBits;
+
+    for (int i = 5; i >= 0; i--) {
+      // Get the remaining 48 bits.
+      resultBits[i] = readBits(8);
+    }
+
+    void roundUp() {
+      // Simply consists of adding 1 to the whole 64 bit "number".
+      // It will update the exponent, if necessary.
+      // It might even round up to infinity (which is what we want).
+      var carry = 1;
+      for (int i = 0; i < 8; i++) {
+        if (carry == 0) break;
+        var sum = resultBits[i] + carry;
+        resultBits[i] = sum & 0xFF;
+        carry = sum >> 8;
+      }
+    }
+
+    if (readBits(1) == 1) {
+      if (resultBits[0].isOdd) {
+        // Rounds to even all the time.
+        roundUp();
+      } else {
+        // Round up, if there is at least one other digit that is not 0.
+        if (cachedBits != 0) {
+          // There is already one in the cachedBits.
+          roundUp();
+        } else {
+          for (int i = digitIndex; digitIndex >= 0; i--) {
+            if (_digits[i] != 0) {
+              roundUp();
+              break;
+            }
+          }
+        }
+      }
+    }
+    return resultBits.buffer.asByteData().getFloat64(0, Endian.little);
+  }
+
+  /// Returns a String-representation of this integer.
+  ///
+  /// The returned string is parsable by [parse].
+  /// For any `_BigIntImpl` `i`, it is guaranteed that
+  /// `i == _BigIntImpl.parse(i.toString())`.
+  String toString() {
+    if (_used == 0) return "0";
+    if (_used == 1) {
+      if (_isNegative) return (-_digits[0]).toString();
+      return _digits[0].toString();
+    }
+
+    // Generate in chunks of 4 digits.
+    // The chunks are in reversed order.
+    var decimalDigitChunks = <String>[];
+    var rest = isNegative ? -this : this;
+    while (rest._used > 1) {
+      var digits4 = rest.remainder(_bigInt10000).toString();
+      decimalDigitChunks.add(digits4);
+      if (digits4.length == 1) decimalDigitChunks.add("000");
+      if (digits4.length == 2) decimalDigitChunks.add("00");
+      if (digits4.length == 3) decimalDigitChunks.add("0");
+      rest = rest ~/ _bigInt10000;
+    }
+    decimalDigitChunks.add(rest._digits[0].toString());
+    if (_isNegative) decimalDigitChunks.add("-");
+    return decimalDigitChunks.reversed.join();
+  }
+
+  int _toRadixCodeUnit(int digit) {
+    const int _0 = 48;
+    const int _a = 97;
+    if (digit < 10) return _0 + digit;
+    return _a + digit - 10;
+  }
+
+  /// Converts [this] to a string representation in the given [radix].
+  ///
+  /// In the string representation, lower-case letters are used for digits above
+  /// '9', with 'a' being 10 an 'z' being 35.
+  ///
+  /// The [radix] argument must be an integer in the range 2 to 36.
+  String toRadixString(int radix) {
+    if (radix > 36) throw new RangeError.range(radix, 2, 36);
+
+    if (_used == 0) return "0";
+
+    if (_used == 1) {
+      var digitString = _digits[0].toRadixString(radix);
+      if (_isNegative) return "-" + digitString;
+      return digitString;
+    }
+
+    if (radix == 16) return _toHexString();
+
+    var base = new _BigIntImpl._fromInt(radix);
+    var reversedDigitCodeUnits = <int>[];
+    var rest = this.abs();
+    while (!rest._isZero) {
+      var digit = rest.remainder(base).toInt();
+      rest = rest ~/ base;
+      reversedDigitCodeUnits.add(_toRadixCodeUnit(digit));
+    }
+    var digitString = new String.fromCharCodes(reversedDigitCodeUnits.reversed);
+    if (_isNegative) return "-" + digitString;
+    return digitString;
+  }
+
+  String _toHexString() {
+    var chars = <int>[];
+    for (int i = 0; i < _used - 1; i++) {
+      int chunk = _digits[i];
+      for (int j = 0; j < (_digitBits ~/ 4); j++) {
+        chars.add(_toRadixCodeUnit(chunk & 0xF));
+        chunk >>= 4;
+      }
+    }
+    var msbChunk = _digits[_used - 1];
+    while (msbChunk != 0) {
+      chars.add(_toRadixCodeUnit(msbChunk & 0xF));
+      msbChunk >>= 4;
+    }
+    if (_isNegative) {
+      const _dash = 45;
+      chars.add(_dash);
+    }
+    return new String.fromCharCodes(chars.reversed);
+  }
+}
+
+// Interface for modular reduction.
+abstract class _BigIntReduction {
+  // Return the number of digits used by r_digits.
+  int convert(_BigIntImpl x, Uint16List r_digits);
+  int mul(Uint16List xDigits, int xUsed, Uint16List yDigits, int yUsed,
+      Uint16List resultDigits);
+  int sqr(Uint16List xDigits, int xUsed, Uint16List resultDigits);
+
+  // Return x reverted to _BigIntImpl.
+  _BigIntImpl revert(Uint16List xDigits, int xUsed);
+}
+
+// Modular reduction using "classic" algorithm.
+class _BigIntClassic implements _BigIntReduction {
+  final _BigIntImpl _modulus; // Modulus.
+  final _BigIntImpl _normalizedModulus; // Normalized _modulus.
+
+  _BigIntClassic(this._modulus)
+      : _normalizedModulus = _modulus <<
+            (_BigIntImpl._digitBits -
+                _modulus._digits[_modulus._used - 1].bitLength);
+
+  int convert(_BigIntImpl x, Uint16List resultDigits) {
+    var digits;
+    var used;
+    if (x._isNegative || x._absCompare(_modulus) >= 0) {
+      var remainder = x._rem(_modulus);
+      if (x._isNegative && remainder._used > 0) {
+        assert(remainder._isNegative);
+        remainder += _modulus;
+      }
+      assert(!remainder._isNegative);
+      used = remainder._used;
+      digits = remainder._digits;
+    } else {
+      used = x._used;
+      digits = x._digits;
+    }
+    var i = used; // Copy leading zero if any.
+    while (--i >= 0) {
+      resultDigits[i] = digits[i];
+    }
+    return used;
+  }
+
+  _BigIntImpl revert(Uint16List xDigits, int xUsed) {
+    return new _BigIntImpl._(false, xUsed, xDigits);
+  }
+
+  int _reduce(Uint16List xDigits, int xUsed) {
+    if (xUsed < _modulus._used) {
+      return xUsed;
+    }
+    var reverted = revert(xDigits, xUsed);
+    var rem = reverted._rem(_normalizedModulus);
+    return convert(rem, xDigits);
+  }
+
+  int sqr(Uint16List xDigits, int xUsed, Uint16List resultDigits) {
+    var b = new _BigIntImpl._(false, xUsed, xDigits);
+    var b2 = b * b;
+    for (int i = 0; i < b2._used; i++) {
+      resultDigits[i] = b2._digits[i];
+    }
+    for (int i = b2._used; i < 2 * xUsed; i++) {
+      resultDigits[i] = 0;
+    }
+    return _reduce(resultDigits, 2 * xUsed);
+  }
+
+  int mul(Uint16List xDigits, int xUsed, Uint16List yDigits, int yUsed,
+      Uint16List resultDigits) {
+    var resultUsed =
+        _BigIntImpl._mulDigits(xDigits, xUsed, yDigits, yUsed, resultDigits);
+    return _reduce(resultDigits, resultUsed);
+  }
+}
+
+/// Creates an invocation object used in noSuchMethod forwarding stubs.
+///
+/// The signature is hardwired to the kernel nodes generated in the
+/// `Dart2jsTarget` and read in the `KernelSsaGraphBuilder`.
+external Invocation _createInvocationMirror(
+    String memberName,
+    List typeArguments,
+    List positionalArguments,
+    Map<String, dynamic> namedArguments,
+    int kind);
diff --git a/sdk_nnbd/lib/_internal/js_runtime/lib/developer_patch.dart b/sdk_nnbd/lib/_internal/js_runtime/lib/developer_patch.dart
new file mode 100644
index 0000000..0ff0f66
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_runtime/lib/developer_patch.dart
@@ -0,0 +1,172 @@
+// Copyright (c) 2015, 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.
+
+// Patch file for dart:developer library.
+
+import 'dart:_js_helper' show patch, ForceInline;
+import 'dart:_foreign_helper' show JS;
+import 'dart:async' show Zone;
+import 'dart:isolate';
+
+@patch
+@pragma('dart2js:tryInline')
+bool debugger({bool when: true, String message}) {
+  if (when) {
+    JS('', 'debugger');
+  }
+  return when;
+}
+
+@patch
+Object inspect(Object object) {
+  return object;
+}
+
+@patch
+void log(String message,
+    {DateTime time,
+    int sequenceNumber,
+    int level: 0,
+    String name: '',
+    Zone zone,
+    Object error,
+    StackTrace stackTrace}) {
+  // TODO.
+}
+
+final _extensions = new Map<String, ServiceExtensionHandler>();
+
+@patch
+ServiceExtensionHandler _lookupExtension(String method) {
+  return _extensions[method];
+}
+
+@patch
+_registerExtension(String method, ServiceExtensionHandler handler) {
+  _extensions[method] = handler;
+}
+
+@patch
+void _postEvent(String eventKind, String eventData) {
+  // TODO.
+}
+
+@patch
+bool _isDartStreamEnabled() {
+  return false;
+}
+
+@patch
+int _getTraceClock() {
+  // TODO.
+  return _clockValue++;
+}
+
+int _clockValue = 0;
+
+@patch
+int _getThreadCpuClock() {
+  return -1;
+}
+
+@patch
+void _reportCompleteEvent(int start, int startCpu, String category, String name,
+    String argumentsAsJson) {
+  // TODO.
+}
+
+@patch
+void _reportFlowEvent(int start, int startCpu, String category, String name,
+    int type, int id, String argumentsAsJson) {
+  // TODO.
+}
+
+@patch
+void _reportInstantEvent(
+    int start, String category, String name, String argumentsAsJson) {
+  // TODO.
+}
+
+@patch
+int _getNextAsyncId() {
+  return 0;
+}
+
+@patch
+void _reportTaskEvent(int start, int taskId, String phase, String category,
+    String name, String argumentsAsJson) {
+  // TODO.
+}
+
+@patch
+int _getServiceMajorVersion() {
+  return 0;
+}
+
+@patch
+int _getServiceMinorVersion() {
+  return 0;
+}
+
+@patch
+void _getServerInfo(SendPort sendPort) {
+  sendPort.send(null);
+}
+
+@patch
+void _webServerControl(SendPort sendPort, bool enable) {
+  sendPort.send(null);
+}
+
+@patch
+String _getIsolateIDFromSendPort(SendPort sendPort) {
+  return null;
+}
+
+@patch
+class UserTag {
+  @patch
+  factory UserTag(String label) = _FakeUserTag;
+
+  @patch
+  static UserTag get defaultTag => _FakeUserTag._defaultTag;
+}
+
+class _FakeUserTag implements UserTag {
+  static Map _instances = {};
+
+  _FakeUserTag.real(this.label);
+
+  factory _FakeUserTag(String label) {
+    // Canonicalize by name.
+    var existingTag = _instances[label];
+    if (existingTag != null) {
+      return existingTag;
+    }
+    // Throw an exception if we've reached the maximum number of user tags.
+    if (_instances.length == UserTag.MAX_USER_TAGS) {
+      throw new UnsupportedError(
+          'UserTag instance limit (${UserTag.MAX_USER_TAGS}) reached.');
+    }
+    // Create a new instance and add it to the instance map.
+    var instance = new _FakeUserTag.real(label);
+    _instances[label] = instance;
+    return instance;
+  }
+
+  final String label;
+
+  UserTag makeCurrent() {
+    var old = _currentTag;
+    _currentTag = this;
+    return old;
+  }
+
+  static final UserTag _defaultTag = new _FakeUserTag('Default');
+}
+
+var _currentTag = _FakeUserTag._defaultTag;
+
+@patch
+UserTag getCurrentTag() => _currentTag;
diff --git a/sdk_nnbd/lib/_internal/js_runtime/lib/foreign_helper.dart b/sdk_nnbd/lib/_internal/js_runtime/lib/foreign_helper.dart
new file mode 100644
index 0000000..0cecf96
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_runtime/lib/foreign_helper.dart
@@ -0,0 +1,272 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library _foreign_helper;
+
+import 'dart:_js_embedded_names' show JsGetName, JsBuiltin;
+
+/// Emits a JavaScript code fragment parametrized by arguments.
+///
+/// Hash characters `#` in the [codeTemplate] are replaced in left-to-right
+/// order with expressions that contain the values of, or evaluate to, the
+/// arguments.  The number of hash marks must match the number or arguments.
+/// Although declared with arguments [arg0] through [arg2], the form actually
+/// has no limit on the number of arguments.
+///
+/// The [typeDescription] argument is interpreted as a description of the
+/// behavior of the JavaScript code.  Currently it describes the side effects
+/// types that may be returned by the expression, with the additional behavior
+/// that the returned values may be fresh instances of the types.  The type
+/// information must be correct as it is trusted by the compiler in
+/// optimizations, and it must be precise as possible since it is used for
+/// native live type analysis to tree-shake large parts of the DOM libraries.
+/// If poorly written, the [typeDescription] will cause unnecessarily bloated
+/// programs.  (You can check for this by compiling with `--verbose`; there is
+/// an info message describing the number of native (DOM) types that can be
+/// removed, which usually should be greater than zero.)
+///
+/// The [typeDescription] must be a [String]. Two forms of it are supported:
+///
+/// 1) a union of types separated by vertical bar `|` symbols, e.g.
+///    `"num|String"` describes the union of numbers and Strings.  There is no
+///    type in Dart that is this precise.  The Dart alternative would be
+///    `Object` or `dynamic`, but these types imply that the JS-code might also
+///    be creating instances of all the DOM types.
+///
+///    If `null` is possible, it must be specified explicitly, e.g.
+///    `"String|Null"`. [typeDescription] has several extensions to help
+///    describe the behavior more accurately.  In addition to the union type
+///    already described:
+///
+///    + `=Object` is a plain JavaScript object.  Some DOM methods return
+///       instances that have no corresponding Dart type (e.g. cross-frame
+///       documents), `=Object` can be used to describe these untyped' values.
+///
+///    + `var` or empty string.  If the entire [typeDescription] is `var` (or
+///      empty string) then the type is `dynamic` but the code is known to not
+///      create any instances.
+///
+///   Examples:
+///
+///       // Parent window might be an opaque cross-frame window.
+///       var thing = JS('=Object|Window', '#.parent', myWindow);
+///
+/// 2) a sequence of the form `<tag>:<value>;` where `<tag>` is one of
+///    `creates`, `returns`, `effects` or `depends`.
+///
+///    The first two tags are used to specify the created and returned types of
+///    the expression. The value of `creates` and `returns` is a type string as
+///    defined in 1).
+///
+///    The tags `effects` and `depends` encode the side effects of this call.
+///    They can be omitted, in which case the expression is parsed and a safe
+///    conservative side-effect estimation is computed.
+///
+///    The values of `effects` and `depends` may be 'all', 'none' or a
+///    comma-separated list of 'no-index', 'no-instance' and 'no-static'.
+///
+///    The value 'all' indicates that the call affects/depends on every
+///    side-effect. The flag 'none' signals that the call does not affect
+///    (resp. depends on) anything.
+///
+///    The value 'no-index' indicates that the call does *not* do (resp. depends
+///    on) any array index-store. The flag 'no-instance' indicates that the call
+///    does not modify (resp. depends on) any instance variable. Similarly,
+///    the 'no-static' value indicates that the call does not modify (resp.
+///    depends on) any static variable.
+///
+///    The `effects` and `depends` flag must be used in tandem. Either both are
+///    specified or none is.
+///
+///    Each tag (including the type tags) may only occur once in the sequence.
+///
+/// Guidelines:
+///
+///  + Do not use any parameter, local, method or field names in the
+///    [codeTemplate].  These names are all subject to arbitrary renaming by the
+///    compiler.  Pass the values in via `#` substition, and test with the
+///    `--minify` dart2js command-line option.
+///
+///  + The substituted expressions are values, not locations.
+///
+///        JS('void', '# += "x"', this.field);
+///
+///    `this.field` might not be a substituted as a reference to the field.  The
+///    generated code might accidentally work as intended, but it also might be
+///
+///        var t1 = this.field;
+///        t1 += "x";
+///
+///    or
+///
+///        this.get$field() += "x";
+///
+///    The remedy in this case is to expand the `+=` operator, leaving all
+///    references to the Dart field as Dart code:
+///
+///        this.field = JS('String', '# + "x"', this.field);
+///
+///  + Never use `#` in function bodies.
+///
+///    This is a variation on the previous guideline.  Since `#` is replaced
+///    with an *expression* and the expression is only valid in the immediate
+///    context, `#` should never appear in a function body.  Doing so might
+///    defer the evaluation of the expression, and its side effects, until the
+///    function is called.
+///
+///    For example,
+///
+///        var value = foo();
+///        var f = JS('', 'function(){return #}', value)
+///
+///    might result in no immediate call to `foo` and a call to `foo` on every
+///    call to the JavaScript function bound to `f`.  This is better:
+///
+///        var f = JS('',
+///            '(function(val) { return function(){return val}; })(#)', value);
+///
+///    Since `#` occurs in the immediately evaluated expression, the expression
+///    is immediately evaluated and bound to `val` in the immediate call.
+///
+///
+/// Type argument.
+///
+/// In Dart 2.0, the type argument additionally constrains the returned type.
+/// So, with type inference filling in the type argumemnt,
+///
+///     String s = JS('', 'JSON.stringify(#)', x);
+///
+/// will be the same as the current meaning of
+///
+///     var s = JS('String|Null', 'JSON.stringify(#)', x);
+///
+///
+/// Additional notes.
+///
+/// In the future we may extend [typeDescription] to include other aspects of
+/// the behavior, for example, separating the returned types from the
+/// instantiated types to allow the compiler to perform more optimizations
+/// around the code.
+///
+/// This might be an extension of [JS] or a new function similar to [JS] with
+/// additional arguments for the new information.
+// Add additional optional arguments if needed. The method is treated internally
+// as a variable argument method.
+external T JS<T>(String typeDescription, String codeTemplate,
+    [arg0,
+    arg1,
+    arg2,
+    arg3,
+    arg4,
+    arg5,
+    arg6,
+    arg7,
+    arg8,
+    arg9,
+    arg10,
+    arg11,
+    arg12,
+    arg13,
+    arg14,
+    arg51,
+    arg16,
+    arg17,
+    arg18,
+    arg19]);
+
+/// Converts the Dart closure [function] into a JavaScript closure.
+///
+/// Warning: This is no different from [RAW_DART_FUNCTION_REF] which means care
+/// must be taken to store the current isolate.
+external DART_CLOSURE_TO_JS(Function function);
+
+/// Returns a raw reference to the JavaScript function which implements
+/// [function].
+///
+/// Warning: this is dangerous, you should probably use
+/// [DART_CLOSURE_TO_JS] instead. The returned object is not a valid
+/// Dart closure, does not store the isolate context or arity.
+///
+/// A valid example of where this can be used is as the second argument
+/// to V8's Error.captureStackTrace. See
+/// https://code.google.com/p/v8/wiki/JavaScriptStackTraceApi.
+external RAW_DART_FUNCTION_REF(Function function);
+
+/// Sets the current static state to [staticState].
+external void JS_SET_STATIC_STATE(staticState);
+
+/// Returns the interceptor for class [type].  The interceptor is the type's
+/// constructor's `prototype` property.  [type] will typically be the class, not
+/// an interface, e.g. `JS_INTERCEPTOR_CONSTANT(JSInt)`, not
+/// `JS_INTERCEPTOR_CONSTANT(int)`.
+external JS_INTERCEPTOR_CONSTANT(Type type);
+
+/// Returns the interceptor for [object].
+///
+/// Calls are replaced with the [HInterceptor] SSA instruction.
+external getInterceptor(object);
+
+/// Returns the Rti object for the type for JavaScript arrays via JS-interop.
+///
+/// Calls are replaced with a [HLoadType] SSA instruction.
+external Object getJSArrayInteropRti();
+
+/// Returns the object corresponding to Namer.staticStateHolder.
+external JS_GET_STATIC_STATE();
+
+/// Returns the JS name for [name] from the Namer.
+external String JS_GET_NAME(JsGetName name);
+
+/// Reads an embedded global.
+///
+/// The [name] should be a constant defined in the `_embedded_names` library.
+external JS_EMBEDDED_GLOBAL(String typeDescription, String name);
+
+/// Instructs the compiler to execute the [builtinName] action at the call-site.
+///
+/// The [builtin] should be a constant defined in the `_embedded_names`
+/// library.
+// Add additional optional arguments if needed. The method is treated internally
+// as a variable argument method.
+external JS_BUILTIN(String typeDescription, JsBuiltin builtin,
+    [arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11]);
+
+/// Returns the state of a flag that is determined by the state of the compiler
+/// when the program has been analyzed.
+external bool JS_GET_FLAG(String name);
+
+/// Pretend [code] is executed.  Generates no executable code.  This is used to
+/// model effects at some other point in external code.  For example, the
+/// following models an assignment to foo with an unknown value.
+///
+///     var foo;
+///
+///     main() {
+///       JS_EFFECT((_){ foo = _; })
+///     }
+///
+/// TODO(sra): Replace this hack with something to mark the volatile or
+/// externally initialized elements.
+void JS_EFFECT(Function code) {
+  code(null);
+}
+
+/// Use this class for creating constants that hold JavaScript code.
+/// For example:
+///
+/// const constant = JS_CONST('typeof window != "undefined");
+///
+/// This code will generate:
+/// $.JS_CONST_1 = typeof window != "undefined";
+class JS_CONST {
+  final String code;
+  const JS_CONST(this.code);
+}
+
+/// JavaScript string concatenation. Inputs must be Strings.  Corresponds to the
+/// HStringConcat SSA instruction and may be constant-folded.
+String JS_STRING_CONCAT(String a, String b) {
+  // This body is unused, only here for type analysis.
+  return JS('String', '# + #', a, b);
+}
diff --git a/sdk_nnbd/lib/_internal/js_runtime/lib/instantiation.dart b/sdk_nnbd/lib/_internal/js_runtime/lib/instantiation.dart
new file mode 100644
index 0000000..bb003e6
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_runtime/lib/instantiation.dart
@@ -0,0 +1,334 @@
+// 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.
+
+part of _js_helper;
+
+/// Support class for generic function type instantiation (binding of types).
+///
+abstract class Instantiation extends Closure {
+  final Closure _genericClosure;
+  Instantiation(this._genericClosure) {
+    // TODO(sra): Copy some metadata used by Function.apply.
+
+    // Mark support code as used.  The JS condition is inscrutable to dart2js,
+    // so the 'if (false)' is in the final program.
+    // TODO(sra): Find a better way to do this. Generating the signature methods
+    // earlier as SSA on the instantiation closures should achieve this.
+    if (JS('bool', 'false')) {
+      // [instantiatedGenericFunctionType] is called from injected $signature
+      // methods with runtime type representations.
+      if (JS_GET_FLAG('USE_NEW_RTI')) {
+        newRti.instantiatedGenericFunctionType(JS('', '0'), JS('', '0'));
+      } else {
+        instantiatedGenericFunctionType(JS('', '0'), JS('', '0'));
+      }
+    }
+  }
+
+  /// Returns a list of the bound types.
+  List get _types;
+
+  String toString() {
+    var types = "<${_types.join(', ')}>";
+    // TODO(sra): Refactor Closure formatting to place type arguments inside,
+    // e.g. "Closure 'map<String>' of Instance of 'JSArray<int>'".
+    return '$_genericClosure with $types';
+  }
+}
+
+/// Instantiation classes are subclasses of [Instantiation]. For now we have a
+/// fixed number of subclasses. Later we might generate the classes on demand.
+class Instantiation1<T1> extends Instantiation {
+  Instantiation1(Closure f) : super(f);
+  List get _types => [T1];
+}
+
+class Instantiation2<T1, T2> extends Instantiation {
+  Instantiation2(Closure f) : super(f);
+  List get _types => [T1, T2];
+}
+
+class Instantiation3<T1, T2, T3> extends Instantiation {
+  Instantiation3(Closure f) : super(f);
+  List get _types => [T1, T2, T3];
+}
+
+class Instantiation4<T1, T2, T3, T4> extends Instantiation {
+  Instantiation4(Closure f) : super(f);
+  List get _types => [T1, T2, T3, T4];
+}
+
+class Instantiation5<T1, T2, T3, T4, T5> extends Instantiation {
+  Instantiation5(Closure f) : super(f);
+  List get _types => [T1, T2, T3, T4, T5];
+}
+
+class Instantiation6<T1, T2, T3, T4, T5, T6> extends Instantiation {
+  Instantiation6(Closure f) : super(f);
+  List get _types => [T1, T2, T3, T4, T5, T6];
+}
+
+class Instantiation7<T1, T2, T3, T4, T5, T6, T7> extends Instantiation {
+  Instantiation7(Closure f) : super(f);
+  List get _types => [T1, T2, T3, T4, T5, T6, T7];
+}
+
+class Instantiation8<T1, T2, T3, T4, T5, T6, T7, T8> extends Instantiation {
+  Instantiation8(Closure f) : super(f);
+  List get _types => [T1, T2, T3, T4, T5, T6, T7, T8];
+}
+
+class Instantiation9<T1, T2, T3, T4, T5, T6, T7, T8, T9> extends Instantiation {
+  Instantiation9(Closure f) : super(f);
+  List get _types => [T1, T2, T3, T4, T5, T6, T7, T8, T9];
+}
+
+class Instantiation10<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>
+    extends Instantiation {
+  Instantiation10(Closure f) : super(f);
+  List get _types => [T1, T2, T3, T4, T5, T6, T7, T8, T9, T10];
+}
+
+class Instantiation11<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11>
+    extends Instantiation {
+  Instantiation11(Closure f) : super(f);
+  List get _types => [T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11];
+}
+
+class Instantiation12<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12>
+    extends Instantiation {
+  Instantiation12(Closure f) : super(f);
+  List get _types => [T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12];
+}
+
+class Instantiation13<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13>
+    extends Instantiation {
+  Instantiation13(Closure f) : super(f);
+  List get _types => [T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13];
+}
+
+class Instantiation14<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14> extends Instantiation {
+  Instantiation14(Closure f) : super(f);
+  List get _types =>
+      [T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14];
+}
+
+class Instantiation15<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15> extends Instantiation {
+  Instantiation15(Closure f) : super(f);
+  List get _types =>
+      [T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15];
+}
+
+class Instantiation16<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15, T16> extends Instantiation {
+  Instantiation16(Closure f) : super(f);
+  List get _types =>
+      [T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16];
+}
+
+class Instantiation17<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15, T16, T17> extends Instantiation {
+  Instantiation17(Closure f) : super(f);
+  List get _types => [
+        T1,
+        T2,
+        T3,
+        T4,
+        T5,
+        T6,
+        T7,
+        T8,
+        T9,
+        T10,
+        T11,
+        T12,
+        T13,
+        T14,
+        T15,
+        T16,
+        T17
+      ];
+}
+
+class Instantiation18<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15, T16, T17, T18> extends Instantiation {
+  Instantiation18(Closure f) : super(f);
+  List get _types => [
+        T1,
+        T2,
+        T3,
+        T4,
+        T5,
+        T6,
+        T7,
+        T8,
+        T9,
+        T10,
+        T11,
+        T12,
+        T13,
+        T14,
+        T15,
+        T16,
+        T17,
+        T18
+      ];
+}
+
+class Instantiation19<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15, T16, T17, T18, T19> extends Instantiation {
+  Instantiation19(Closure f) : super(f);
+  List get _types => [
+        T1,
+        T2,
+        T3,
+        T4,
+        T5,
+        T6,
+        T7,
+        T8,
+        T9,
+        T10,
+        T11,
+        T12,
+        T13,
+        T14,
+        T15,
+        T16,
+        T17,
+        T18,
+        T19
+      ];
+}
+
+class Instantiation20<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15, T16, T17, T18, T19, T20> extends Instantiation {
+  Instantiation20(Closure f) : super(f);
+  List get _types => [
+        T1,
+        T2,
+        T3,
+        T4,
+        T5,
+        T6,
+        T7,
+        T8,
+        T9,
+        T10,
+        T11,
+        T12,
+        T13,
+        T14,
+        T15,
+        T16,
+        T17,
+        T18,
+        T19,
+        T20
+      ];
+}
+
+Instantiation instantiate1<T1>(Closure f) {
+  return new Instantiation1<T1>(f);
+}
+
+Instantiation instantiate2<T1, T2>(Closure f) {
+  return new Instantiation2<T1, T2>(f);
+}
+
+Instantiation instantiate3<T1, T2, T3>(Closure f) {
+  return new Instantiation3<T1, T2, T3>(f);
+}
+
+Instantiation instantiate4<T1, T2, T3, T4>(Closure f) {
+  return new Instantiation4<T1, T2, T3, T4>(f);
+}
+
+Instantiation instantiate5<T1, T2, T3, T4, T5>(Closure f) {
+  return new Instantiation5<T1, T2, T3, T4, T5>(f);
+}
+
+Instantiation instantiate6<T1, T2, T3, T4, T5, T6>(Closure f) {
+  return new Instantiation6<T1, T2, T3, T4, T5, T6>(f);
+}
+
+Instantiation instantiate7<T1, T2, T3, T4, T5, T6, T7>(Closure f) {
+  return new Instantiation7<T1, T2, T3, T4, T5, T6, T7>(f);
+}
+
+Instantiation instantiate8<T1, T2, T3, T4, T5, T6, T7, T8>(Closure f) {
+  return new Instantiation8<T1, T2, T3, T4, T5, T6, T7, T8>(f);
+}
+
+Instantiation instantiate9<T1, T2, T3, T4, T5, T6, T7, T8, T9>(Closure f) {
+  return new Instantiation9<T1, T2, T3, T4, T5, T6, T7, T8, T9>(f);
+}
+
+Instantiation instantiate10<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>(
+    Closure f) {
+  return new Instantiation10<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>(f);
+}
+
+Instantiation instantiate11<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11>(
+    Closure f) {
+  return new Instantiation11<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11>(f);
+}
+
+Instantiation instantiate12<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12>(
+    Closure f) {
+  return new Instantiation12<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12>(
+      f);
+}
+
+Instantiation
+    instantiate13<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13>(
+        Closure f) {
+  return new Instantiation13<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13>(f);
+}
+
+Instantiation
+    instantiate14<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14>(
+        Closure f) {
+  return new Instantiation14<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14>(f);
+}
+
+Instantiation instantiate15<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+    T13, T14, T15>(Closure f) {
+  return new Instantiation15<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15>(f);
+}
+
+Instantiation instantiate16<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+    T13, T14, T15, T16>(Closure f) {
+  return new Instantiation16<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15, T16>(f);
+}
+
+Instantiation instantiate17<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+    T13, T14, T15, T16, T17>(Closure f) {
+  return new Instantiation17<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15, T16, T17>(f);
+}
+
+Instantiation instantiate18<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+    T13, T14, T15, T16, T17, T18>(Closure f) {
+  return new Instantiation18<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15, T16, T17, T18>(f);
+}
+
+Instantiation instantiate19<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+    T13, T14, T15, T16, T17, T18, T19>(Closure f) {
+  return new Instantiation19<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15, T16, T17, T18, T19>(f);
+}
+
+Instantiation instantiate20<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+    T13, T14, T15, T16, T17, T18, T19, T20>(Closure f) {
+  return new Instantiation20<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15, T16, T17, T18, T19, T20>(f);
+}
diff --git a/sdk_nnbd/lib/_internal/js_runtime/lib/interceptors.dart b/sdk_nnbd/lib/_internal/js_runtime/lib/interceptors.dart
new file mode 100644
index 0000000..b676c1b
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_runtime/lib/interceptors.dart
@@ -0,0 +1,455 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library _interceptors;
+
+import 'dart:_js_embedded_names'
+    show DISPATCH_PROPERTY_NAME, TYPE_TO_INTERCEPTOR_MAP;
+
+import 'dart:collection' hide LinkedList, LinkedListEntry;
+import 'dart:_internal' hide Symbol;
+import "dart:_internal" as _symbol_dev show Symbol;
+import 'dart:_js_helper'
+    show
+        allMatchesInStringUnchecked,
+        JSSyntaxRegExp,
+        Primitives,
+        argumentErrorValue,
+        checkBool,
+        checkInt,
+        checkNull,
+        checkNum,
+        checkString,
+        defineProperty,
+        diagnoseIndexError,
+        getIsolateAffinityTag,
+        getRuntimeType,
+        initNativeDispatch,
+        initNativeDispatchFlag,
+        regExpGetNative,
+        regExpCaptureCount,
+        stringContainsUnchecked,
+        stringIndexOfStringUnchecked,
+        stringLastIndexOfUnchecked,
+        stringReplaceAllFuncUnchecked,
+        stringReplaceAllUnchecked,
+        stringReplaceFirstUnchecked,
+        stringReplaceFirstMappedUnchecked,
+        stringReplaceRangeUnchecked,
+        stringSplitUnchecked,
+        throwConcurrentModificationError,
+        lookupAndCacheInterceptor,
+        StringMatch,
+        firstMatchAfter,
+        NoInline;
+
+import 'dart:_foreign_helper'
+    show
+        getInterceptor,
+        JS,
+        JS_EFFECT,
+        JS_EMBEDDED_GLOBAL,
+        JS_INTERCEPTOR_CONSTANT,
+        JS_STRING_CONCAT;
+import 'dart:math' show Random, ln2;
+
+part 'js_array.dart';
+part 'js_number.dart';
+part 'js_string.dart';
+
+final String DART_CLOSURE_PROPERTY_NAME =
+    getIsolateAffinityTag(r'_$dart_dartClosure');
+
+String _symbolToString(Symbol symbol) => _symbol_dev.Symbol.getName(symbol);
+
+_symbolMapToStringMap(Map<Symbol, dynamic> map) {
+  if (map == null) return null;
+  var result = new Map<String, dynamic>();
+  map.forEach((Symbol key, value) {
+    result[_symbolToString(key)] = value;
+  });
+  return result;
+}
+
+getDispatchProperty(object) {
+  return JS(
+      '', '#[#]', object, JS_EMBEDDED_GLOBAL('String', DISPATCH_PROPERTY_NAME));
+}
+
+setDispatchProperty(object, value) {
+  defineProperty(
+      object, JS_EMBEDDED_GLOBAL('String', DISPATCH_PROPERTY_NAME), value);
+}
+
+// Avoid inlining this method because inlining gives us multiple allocation
+// points for records which is bad because it leads to polymorphic access.
+@pragma('dart2js:noInline')
+makeDispatchRecord(interceptor, proto, extension, indexability) {
+  // Dispatch records are stored in the prototype chain, and in some cases, on
+  // instances.
+  //
+  // The record layout and field usage is designed to minimize the number of
+  // operations on the common paths.
+  //
+  // [interceptor] is the interceptor - a holder of methods for the object,
+  // i.e. the prototype of the interceptor class.
+  //
+  // [proto] is usually the prototype, used to check that the dispatch record
+  // matches the object and is not the dispatch record of a superclass.  Other
+  // values:
+  //  - `false` for leaf classes that need no check.
+  //  - `true` for Dart classes where the object is its own interceptor (unused)
+  //  - a function used to continue matching.
+  //
+  // [extension] is used for irregular cases.
+  //
+  // [indexability] is used to cache whether or not the object
+  // implements JavaScriptIndexingBehavior.
+  //
+  //     proto  interceptor extension action
+  //     -----  ----------- --------- ------
+  //     false  I                     use interceptor I
+  //     true   -                     use object
+  //     P      I                     if object's prototype is P, use I
+  //     F      -           P         if object's prototype is P, call F
+
+  return JS('', '{i: #, p: #, e: #, x: #}', interceptor, proto, extension,
+      indexability);
+}
+
+dispatchRecordInterceptor(record) => JS('', '#.i', record);
+dispatchRecordProto(record) => JS('', '#.p', record);
+dispatchRecordExtension(record) => JS('', '#.e', record);
+dispatchRecordIndexability(record) => JS('bool|Null', '#.x', record);
+
+/// Returns the interceptor for a native class instance. Used by
+/// [getInterceptor].
+getNativeInterceptor(object) {
+  var record = getDispatchProperty(object);
+
+  if (record == null) {
+    if (initNativeDispatchFlag == null) {
+      initNativeDispatch();
+      record = getDispatchProperty(object);
+    }
+  }
+
+  if (record != null) {
+    var proto = dispatchRecordProto(record);
+    if (false == proto) return dispatchRecordInterceptor(record);
+    if (true == proto) return object;
+    var objectProto = JS('', 'Object.getPrototypeOf(#)', object);
+    if (JS('bool', '# === #', proto, objectProto)) {
+      return dispatchRecordInterceptor(record);
+    }
+
+    var extension = dispatchRecordExtension(record);
+    if (JS('bool', '# === #', extension, objectProto)) {
+      // TODO(sra): The discriminator returns a tag.  The tag is an uncached or
+      // instance-cached tag, defaulting to instance-cached if caching
+      // unspecified.
+      var discriminatedTag = JS('', '(#)(#, #)', proto, object, record);
+      throw new UnimplementedError('Return interceptor for $discriminatedTag');
+    }
+  }
+
+  // Check for cached UnknownJavaScriptObject. This avoids doing the slow
+  // dispatch-record based lookup for repeated js-interop classes.
+  var constructor = JS('', '#.constructor', object);
+  var interceptor = lookupInterceptorByConstructor(constructor);
+  if (interceptor != null) return interceptor;
+
+  // This takes care of dispatch-record based caching, but not constructor based
+  // caching of [UnknownJavaScriptObject]s.
+  interceptor = lookupAndCacheInterceptor(object);
+  if (interceptor != null) return interceptor;
+
+  // JavaScript Objects created via object literals and `Object.create(null)`
+  // are 'plain' Objects.  This test could be simplified and the dispatch path
+  // be faster if Object.prototype was pre-patched with a non-leaf dispatch
+  // record.
+  if (JS('bool', 'typeof # == "function"', object)) {
+    interceptor = JS_INTERCEPTOR_CONSTANT(JavaScriptFunction);
+    // TODO(sra): Investigate caching on `Function`. It might be impossible if
+    // some HTML embedded objects on some browsers are (still) JS functions.
+    return interceptor;
+  }
+  var proto = JS('', 'Object.getPrototypeOf(#)', object);
+  if (JS('bool', '# == null', proto)) {
+    // Nowhere to cache output.
+    return JS_INTERCEPTOR_CONSTANT(PlainJavaScriptObject);
+  }
+  interceptor = JS_INTERCEPTOR_CONSTANT(UnknownJavaScriptObject);
+  if (JS('bool', '# === Object.prototype', proto)) {
+    interceptor = JS_INTERCEPTOR_CONSTANT(PlainJavaScriptObject);
+    // TODO(sra): Investigate caching on 'Object'. It might be impossible if
+    // some native class is plain Object (e.g. like Firefox's ImageData).
+    return interceptor;
+  }
+  if (JS('bool', 'typeof # == "function"', constructor)) {
+    cacheInterceptorOnConstructor(constructor, interceptor);
+    return interceptor;
+  }
+  return JS_INTERCEPTOR_CONSTANT(UnknownJavaScriptObject);
+}
+
+// A JS String or Symbol.
+final JS_INTEROP_INTERCEPTOR_TAG = getIsolateAffinityTag(r'_$dart_js');
+
+lookupInterceptorByConstructor(constructor) {
+  return constructor == null
+      ? null
+      : JS('', '#[#]', constructor, JS_INTEROP_INTERCEPTOR_TAG);
+}
+
+void cacheInterceptorOnConstructor(constructor, interceptor) {
+  defineProperty(constructor, JS_INTEROP_INTERCEPTOR_TAG, interceptor);
+}
+
+var constructorToInterceptor =
+    JS('', 'typeof(self.WeakMap) == "undefined" ? new Map() : new WeakMap()');
+
+XlookupInterceptorByConstructor(constructor) {
+  return JS('', '#.get(#)', constructorToInterceptor, constructor);
+}
+
+void XcacheInterceptorOnConstructor(constructor, interceptor) {
+  JS('', '#.set(#, #)', constructorToInterceptor, constructor, interceptor);
+}
+
+/// Data structure used to map a [Type] to the [Interceptor] and constructors
+/// for that type.  It is JavaScript array of 3N entries of adjacent slots
+/// containing a [Type], followed by an [Interceptor] class for the type,
+/// followed by a JavaScript object map for the constructors.
+///
+/// The value of this variable is set by the compiler and contains only types
+/// that are user extensions of native classes where the type occurs as a
+/// constant in the program.
+///
+/// The compiler, in CustomElementsAnalysis, assumes that [typeToInterceptorMap]
+/// is accessed only by code that also calls [findIndexForWebComponentType].  If
+/// this assumption is invalidated, the compiler will have to be updated.
+get typeToInterceptorMap {
+  return JS_EMBEDDED_GLOBAL('', TYPE_TO_INTERCEPTOR_MAP);
+}
+
+int findIndexForNativeSubclassType(Type type) {
+  if (JS('bool', '# == null', typeToInterceptorMap)) return null;
+  List map = JS('JSFixedArray', '#', typeToInterceptorMap);
+  for (int i = 0; i + 1 < map.length; i += 3) {
+    if (type == map[i]) {
+      return i;
+    }
+  }
+  return null;
+}
+
+findInterceptorConstructorForType(Type type) {
+  var index = findIndexForNativeSubclassType(type);
+  if (index == null) return null;
+  List map = JS('JSFixedArray', '#', typeToInterceptorMap);
+  return map[index + 1];
+}
+
+/// Returns a JavaScript function that runs the constructor on its argument, or
+/// `null` if there is no such constructor.
+///
+/// The returned function takes one argument, the web component object.
+findConstructorForNativeSubclassType(Type type, String name) {
+  var index = findIndexForNativeSubclassType(type);
+  if (index == null) return null;
+  List map = JS('JSFixedArray', '#', typeToInterceptorMap);
+  var constructorMap = map[index + 2];
+  var constructorFn = JS('', '#[#]', constructorMap, name);
+  return constructorFn;
+}
+
+findInterceptorForType(Type type) {
+  var constructor = findInterceptorConstructorForType(type);
+  if (constructor == null) return null;
+  return JS('', '#.prototype', constructor);
+}
+
+/// The base interceptor class.
+///
+/// The code `r.foo(a)` is compiled to `getInterceptor(r).foo$1(r, a)`.  The
+/// value returned by [getInterceptor] holds the methods separately from the
+/// state of the instance.  The compiler converts the methods on an interceptor
+/// to take the Dart `this` argument as an explicit `receiver` argument.  The
+/// JavaScript `this` parameter is bound to the interceptor.
+///
+/// In order to have uniform call sites, if a method is defined on an
+/// interceptor, methods of that name on plain unintercepted classes also use
+/// the interceptor calling convention.  The plain classes are
+/// _self-interceptors_, and for them, `getInterceptor(r)` returns `r`.  Methods
+/// on plain unintercepted classes have a redundant `receiver` argument and, to
+/// enable some optimizations, must ignore `receiver` in favour of `this`.
+///
+/// In the case of mixins, a method may be placed on both an intercepted class
+/// and an unintercepted class.  In this case, the method must use the
+/// `receiver` parameter.
+///
+///
+/// There are various optimizations of the general call pattern.
+///
+/// When the interceptor can be statically determined, it can be used directly:
+///
+///     CONSTANT_INTERCEPTOR.foo$1(r, a)
+///
+/// If there are only a few classes, [getInterceptor] can be specialized with a
+/// more efficient dispatch:
+///
+///     getInterceptor$specialized(r).foo$1(r, a)
+///
+/// If it can be determined that the receiver is an unintercepted class, it can
+/// be called directly:
+///
+///     r.foo$1(r, a)
+///
+/// If, further, it is known that the call site cannot call a foo that is
+/// mixed-in to a native class, then it is known that the explicit receiver is
+/// ignored, and space-saving dummy value can be passed instead:
+///
+///     r.foo$1(0, a)
+///
+/// This class defines implementations of *all* methods on [Object] so no
+/// interceptor inherits an implementation from [Object].  This enables the
+/// implementations on Object to ignore the explicit receiver argument, which
+/// allows dummy receiver optimization.
+abstract class Interceptor {
+  const Interceptor();
+
+  bool operator ==(other) => identical(this, other);
+
+  int get hashCode => Primitives.objectHashCode(this);
+
+  String toString() => Primitives.objectToHumanReadableString(this);
+
+  // [Interceptor.noSuchMethod] is identical to [Object.noSuchMethod].  However,
+  // each copy is compiled differently.  The presence of the method on an
+  // Interceptor class forces [noSuchMethod] to use interceptor calling
+  // convention.  In the [Interceptor] version, `this` is the explicit receiver
+  // argument. In the [Object] version, as Object is not an intercepted class,
+  // `this` is the JavaScript receiver, and the explicit receiver is ignored.
+  // The noSuchMethod stubs for selectors that use the interceptor calling
+  // convention do not know the calling convention and forward `this` and
+  // `receiver` to one of these noSuchMethod implementations which selects the
+  // correct Dart receiver.
+  //
+  // We don't allow [noSuchMethod] on intercepted classes (that would force all
+  // calls to use interceptor calling convention).  If we did allow it, the
+  // interceptor context would select the correct `this`.
+  dynamic noSuchMethod(Invocation invocation) {
+    throw new NoSuchMethodError(this, invocation.memberName,
+        invocation.positionalArguments, invocation.namedArguments);
+  }
+
+  Type get runtimeType => getRuntimeType(this);
+}
+
+/// The interceptor class for [bool].
+class JSBool extends Interceptor implements bool {
+  const JSBool();
+
+  // Note: if you change this, also change the function [S].
+  String toString() => JS('String', r'String(#)', this);
+
+  bool operator &(bool other) => JS('bool', "# && #", checkBool(other), this);
+
+  bool operator |(bool other) => JS('bool', "# || #", checkBool(other), this);
+
+  bool operator ^(bool other) => !identical(this, checkBool(other));
+
+  // The values here are SMIs, co-prime and differ about half of the bit
+  // positions, including the low bit, so they are different mod 2^k.
+  int get hashCode => this ? (2 * 3 * 23 * 3761) : (269 * 811);
+
+  Type get runtimeType => bool;
+}
+
+/// The interceptor class for [Null].
+///
+/// This class defines implementations for *all* methods on [Object] since
+/// the methods on Object assume the receiver is non-null.  This means that
+/// JSNull will always be in the interceptor set for methods defined on Object.
+class JSNull extends Interceptor implements Null {
+  const JSNull();
+
+  bool operator ==(other) => identical(null, other);
+
+  // Note: if you change this, also change the function [S].
+  String toString() => 'null';
+
+  int get hashCode => 0;
+
+  // The spec guarantees that `null` is the singleton instance of the `Null`
+  // class. In the mirrors library we also have to patch the `type` getter to
+  // special case `null`.
+  Type get runtimeType => Null;
+
+  dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+}
+
+/// The supertype for JSString and JSArray. Used by the backend as to
+/// have a type mask that contains the objects that we can use the
+/// native JS [] operator and length on.
+abstract class JSIndexable<E> {
+  int get length;
+  E operator [](int index);
+}
+
+/// The supertype for JSMutableArray and
+/// JavaScriptIndexingBehavior. Used by the backend to have a type mask
+/// that contains the objects we can use the JS []= operator on.
+abstract class JSMutableIndexable<E> extends JSIndexable<E> {
+  operator []=(int index, E value);
+}
+
+/// The interface implemented by JavaScript objects.  These are methods in
+/// addition to the regular Dart Object methods like [Object.hashCode].
+///
+/// This is the type that should be exported by a JavaScript interop library.
+abstract class JSObject {}
+
+/// Interceptor base class for JavaScript objects not recognized as some more
+/// specific native type.
+class JavaScriptObject extends Interceptor implements JSObject {
+  const JavaScriptObject();
+
+  // It would be impolite to stash a property on the object.
+  int get hashCode => 0;
+
+  Type get runtimeType => JSObject;
+
+  /// Returns the result of the JavaScript objects `toString` method.
+  String toString() => JS('String', 'String(#)', this);
+}
+
+/// Interceptor for plain JavaScript objects created as JavaScript object
+/// literals or `new Object()`.
+class PlainJavaScriptObject extends JavaScriptObject {
+  const PlainJavaScriptObject();
+}
+
+/// Interceptor for unclassified JavaScript objects, typically objects with a
+/// non-trivial prototype chain.
+///
+/// This class also serves as a fallback for unknown JavaScript exceptions.
+class UnknownJavaScriptObject extends JavaScriptObject {
+  const UnknownJavaScriptObject();
+}
+
+/// Interceptor for JavaScript function objects and Dart functions that have
+/// been converted to JavaScript functions.
+/// These interceptor methods are not always used as the JavaScript function
+/// object has also been mangled to support Dart function calling conventions.
+class JavaScriptFunction extends JavaScriptObject implements Function {
+  const JavaScriptFunction();
+
+  String toString() {
+    var dartClosure = JS('', '#.#', this, DART_CLOSURE_PROPERTY_NAME);
+    if (dartClosure == null) return super.toString();
+    return 'JavaScript function for ${dartClosure.toString()}';
+  }
+}
diff --git a/sdk_nnbd/lib/_internal/js_runtime/lib/internal_patch.dart b/sdk_nnbd/lib/_internal/js_runtime/lib/internal_patch.dart
new file mode 100644
index 0000000..77884e2
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_runtime/lib/internal_patch.dart
@@ -0,0 +1,59 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:core' hide Symbol;
+import 'dart:core' as core;
+import 'dart:_js_primitives' show printString;
+import 'dart:_js_helper' show patch, NoInline;
+import 'dart:_interceptors' show JSArray;
+import 'dart:_foreign_helper' show JS, JS_GET_FLAG;
+
+@patch
+class Symbol implements core.Symbol {
+  @patch
+  const Symbol(String name) : this._name = name;
+
+  @patch
+  int get hashCode {
+    int hash = JS('int|Null', '#._hashCode', this);
+    if (hash != null) return hash;
+    const arbitraryPrime = 664597;
+    hash = 0x1fffffff & (arbitraryPrime * _name.hashCode);
+    JS('', '#._hashCode = #', this, hash);
+    return hash;
+  }
+
+  @patch
+  toString() => 'Symbol("$_name")';
+
+  @patch
+  static String computeUnmangledName(Symbol symbol) {
+    throw "unsupported operation";
+  }
+}
+
+@patch
+void printToConsole(String line) {
+  printString('$line');
+}
+
+@patch
+List<T> makeListFixedLength<T>(List<T> growableList) {
+  return JSArray.markFixedList(growableList);
+}
+
+@patch
+List<T> makeFixedListUnmodifiable<T>(List<T> fixedLengthList) {
+  return JSArray.markUnmodifiableList(fixedLengthList);
+}
+
+@patch
+@pragma('dart2js:noInline')
+Object extractTypeArguments<T>(T instance, Function extract) {
+  // This function is recognized and replaced with calls to js_runtime.
+
+  // This call to [extract] is required to model that the function is called and
+  // the returned value flows to the result of extractTypeArguments.
+  return extract();
+}
diff --git a/sdk_nnbd/lib/_internal/js_runtime/lib/io_patch.dart b/sdk_nnbd/lib/_internal/js_runtime/lib/io_patch.dart
new file mode 100644
index 0000000..4f3894d
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_runtime/lib/io_patch.dart
@@ -0,0 +1,690 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:_js_helper' show patch;
+import 'dart:_internal' hide Symbol;
+import 'dart:async';
+import 'dart:convert';
+import 'dart:isolate';
+import 'dart:typed_data';
+
+@patch
+class _Directory {
+  @patch
+  static _current(_Namespace namespace) {
+    throw new UnsupportedError("Directory._current");
+  }
+
+  @patch
+  static _setCurrent(_Namespace namespace, Uint8List path) {
+    throw new UnsupportedError("Directory_SetCurrent");
+  }
+
+  @patch
+  static _createTemp(_Namespace namespace, Uint8List path) {
+    throw new UnsupportedError("Directory._createTemp");
+  }
+
+  @patch
+  static String _systemTemp(_Namespace namespace) {
+    throw new UnsupportedError("Directory._systemTemp");
+  }
+
+  @patch
+  static _exists(_Namespace namespace, Uint8List path) {
+    throw new UnsupportedError("Directory._exists");
+  }
+
+  @patch
+  static _create(_Namespace namespace, Uint8List path) {
+    throw new UnsupportedError("Directory._create");
+  }
+
+  @patch
+  static _deleteNative(_Namespace namespace, Uint8List path, bool recursive) {
+    throw new UnsupportedError("Directory._deleteNative");
+  }
+
+  @patch
+  static _rename(_Namespace namespace, Uint8List path, String newPath) {
+    throw new UnsupportedError("Directory._rename");
+  }
+
+  @patch
+  static void _fillWithDirectoryListing(
+      _Namespace namespace,
+      List<FileSystemEntity> list,
+      Uint8List path,
+      bool recursive,
+      bool followLinks) {
+    throw new UnsupportedError("Directory._fillWithDirectoryListing");
+  }
+}
+
+@patch
+class _AsyncDirectoryListerOps {
+  @patch
+  factory _AsyncDirectoryListerOps(int pointer) {
+    throw new UnsupportedError("Directory._list");
+  }
+}
+
+@patch
+class _EventHandler {
+  @patch
+  static void _sendData(Object sender, SendPort sendPort, int data) {
+    throw new UnsupportedError("EventHandler._sendData");
+  }
+}
+
+@patch
+class FileStat {
+  @patch
+  static _statSync(_Namespace namespace, String path) {
+    throw new UnsupportedError("FileStat.stat");
+  }
+}
+
+@patch
+class FileSystemEntity {
+  @patch
+  static _getTypeNative(
+      _Namespace namespace, Uint8List path, bool followLinks) {
+    throw new UnsupportedError("FileSystemEntity._getType");
+  }
+
+  @patch
+  static _identicalNative(_Namespace namespace, String path1, String path2) {
+    throw new UnsupportedError("FileSystemEntity._identical");
+  }
+
+  @patch
+  static _resolveSymbolicLinks(_Namespace namespace, Uint8List path) {
+    throw new UnsupportedError("FileSystemEntity._resolveSymbolicLinks");
+  }
+}
+
+@patch
+class _File {
+  @patch
+  static _exists(_Namespace namespace, Uint8List path) {
+    throw new UnsupportedError("File._exists");
+  }
+
+  @patch
+  static _create(_Namespace namespace, Uint8List path) {
+    throw new UnsupportedError("File._create");
+  }
+
+  @patch
+  static _createLink(_Namespace namespace, Uint8List path, String target) {
+    throw new UnsupportedError("File._createLink");
+  }
+
+  @patch
+  static _linkTarget(_Namespace namespace, Uint8List path) {
+    throw new UnsupportedError("File._linkTarget");
+  }
+
+  @patch
+  static _deleteNative(_Namespace namespace, Uint8List path) {
+    throw new UnsupportedError("File._deleteNative");
+  }
+
+  @patch
+  static _deleteLinkNative(_Namespace namespace, Uint8List path) {
+    throw new UnsupportedError("File._deleteLinkNative");
+  }
+
+  @patch
+  static _rename(_Namespace namespace, Uint8List oldPath, String newPath) {
+    throw new UnsupportedError("File._rename");
+  }
+
+  @patch
+  static _renameLink(_Namespace namespace, Uint8List oldPath, String newPath) {
+    throw new UnsupportedError("File._renameLink");
+  }
+
+  @patch
+  static _copy(_Namespace namespace, Uint8List oldPath, String newPath) {
+    throw new UnsupportedError("File._copy");
+  }
+
+  @patch
+  static _lengthFromPath(_Namespace namespace, Uint8List path) {
+    throw new UnsupportedError("File._lengthFromPath");
+  }
+
+  @patch
+  static _lastModified(_Namespace namespace, Uint8List path) {
+    throw new UnsupportedError("File._lastModified");
+  }
+
+  @patch
+  static _lastAccessed(_Namespace namespace, Uint8List path) {
+    throw new UnsupportedError("File._lastAccessed");
+  }
+
+  @patch
+  static _setLastModified(_Namespace namespace, Uint8List path, int millis) {
+    throw new UnsupportedError("File._setLastModified");
+  }
+
+  @patch
+  static _setLastAccessed(_Namespace namespace, Uint8List path, int millis) {
+    throw new UnsupportedError("File._setLastAccessed");
+  }
+
+  @patch
+  static _open(_Namespace namespace, Uint8List path, int mode) {
+    throw new UnsupportedError("File._open");
+  }
+
+  @patch
+  static int _openStdio(int fd) {
+    throw new UnsupportedError("File._openStdio");
+  }
+}
+
+@patch
+class _Namespace {
+  @patch
+  static void _setupNamespace(var namespace) {
+    throw new UnsupportedError("_Namespace");
+  }
+
+  @patch
+  static _Namespace get _namespace {
+    throw new UnsupportedError("_Namespace");
+  }
+
+  @patch
+  static int get _namespacePointer {
+    throw new UnsupportedError("_Namespace");
+  }
+}
+
+@patch
+class _RandomAccessFileOps {
+  @patch
+  factory _RandomAccessFileOps(int pointer) {
+    throw new UnsupportedError("RandomAccessFile");
+  }
+}
+
+@patch
+class _IOCrypto {
+  @patch
+  static Uint8List getRandomBytes(int count) {
+    throw new UnsupportedError("_IOCrypto.getRandomBytes");
+  }
+}
+
+@patch
+class _Platform {
+  @patch
+  static int _numberOfProcessors() {
+    throw new UnsupportedError("Platform._numberOfProcessors");
+  }
+
+  @patch
+  static String _pathSeparator() {
+    throw new UnsupportedError("Platform._pathSeparator");
+  }
+
+  @patch
+  static String _operatingSystem() {
+    throw new UnsupportedError("Platform._operatingSystem");
+  }
+
+  @patch
+  static _operatingSystemVersion() {
+    throw new UnsupportedError("Platform._operatingSystemVersion");
+  }
+
+  @patch
+  static _localHostname() {
+    throw new UnsupportedError("Platform._localHostname");
+  }
+
+  @patch
+  static _executable() {
+    throw new UnsupportedError("Platform._executable");
+  }
+
+  @patch
+  static _resolvedExecutable() {
+    throw new UnsupportedError("Platform._resolvedExecutable");
+  }
+
+  @patch
+  static List<String> _executableArguments() {
+    throw new UnsupportedError("Platform._executableArguments");
+  }
+
+  @patch
+  static String _packageRoot() {
+    throw new UnsupportedError("Platform._packageRoot");
+  }
+
+  @patch
+  static String _packageConfig() {
+    throw new UnsupportedError("Platform._packageConfig");
+  }
+
+  @patch
+  static _environment() {
+    throw new UnsupportedError("Platform._environment");
+  }
+
+  @patch
+  static String _version() {
+    throw new UnsupportedError("Platform._version");
+  }
+
+  @patch
+  static String _localeName() {
+    throw new UnsupportedError("Platform._localeName");
+  }
+
+  @patch
+  static Uri _script() {
+    throw new UnsupportedError("Platform._script");
+  }
+}
+
+@patch
+class _ProcessUtils {
+  @patch
+  static void _exit(int status) {
+    throw new UnsupportedError("ProcessUtils._exit");
+  }
+
+  @patch
+  static void _setExitCode(int status) {
+    throw new UnsupportedError("ProcessUtils._setExitCode");
+  }
+
+  @patch
+  static int _getExitCode() {
+    throw new UnsupportedError("ProcessUtils._getExitCode");
+  }
+
+  @patch
+  static void _sleep(int millis) {
+    throw new UnsupportedError("ProcessUtils._sleep");
+  }
+
+  @patch
+  static int _pid(Process process) {
+    throw new UnsupportedError("ProcessUtils._pid");
+  }
+
+  @patch
+  static Stream<ProcessSignal> _watchSignal(ProcessSignal signal) {
+    throw new UnsupportedError("ProcessUtils._watchSignal");
+  }
+}
+
+@patch
+class ProcessInfo {
+  @patch
+  static int get currentRss {
+    throw new UnsupportedError("ProcessInfo.currentRss");
+  }
+
+  @patch
+  static int get maxRss {
+    throw new UnsupportedError("ProcessInfo.maxRss");
+  }
+}
+
+@patch
+class Process {
+  @patch
+  static Future<Process> start(String executable, List<String> arguments,
+      {String workingDirectory,
+      Map<String, String> environment,
+      bool includeParentEnvironment: true,
+      bool runInShell: false,
+      ProcessStartMode mode: ProcessStartMode.normal}) {
+    throw new UnsupportedError("Process.start");
+  }
+
+  @patch
+  static Future<ProcessResult> run(String executable, List<String> arguments,
+      {String workingDirectory,
+      Map<String, String> environment,
+      bool includeParentEnvironment: true,
+      bool runInShell: false,
+      Encoding stdoutEncoding: systemEncoding,
+      Encoding stderrEncoding: systemEncoding}) {
+    throw new UnsupportedError("Process.run");
+  }
+
+  @patch
+  static ProcessResult runSync(String executable, List<String> arguments,
+      {String workingDirectory,
+      Map<String, String> environment,
+      bool includeParentEnvironment: true,
+      bool runInShell: false,
+      Encoding stdoutEncoding: systemEncoding,
+      Encoding stderrEncoding: systemEncoding}) {
+    throw new UnsupportedError("Process.runSync");
+  }
+
+  @patch
+  static bool killPid(int pid, [ProcessSignal signal = ProcessSignal.sigterm]) {
+    throw new UnsupportedError("Process.killPid");
+  }
+}
+
+@patch
+class InternetAddress {
+  @patch
+  static InternetAddress get LOOPBACK_IP_V4 {
+    throw new UnsupportedError("InternetAddress.LOOPBACK_IP_V4");
+  }
+
+  @patch
+  static InternetAddress get LOOPBACK_IP_V6 {
+    throw new UnsupportedError("InternetAddress.LOOPBACK_IP_V6");
+  }
+
+  @patch
+  static InternetAddress get ANY_IP_V4 {
+    throw new UnsupportedError("InternetAddress.ANY_IP_V4");
+  }
+
+  @patch
+  static InternetAddress get ANY_IP_V6 {
+    throw new UnsupportedError("InternetAddress.ANY_IP_V6");
+  }
+
+  @patch
+  factory InternetAddress(String address) {
+    throw new UnsupportedError("InternetAddress");
+  }
+  @patch
+  static Future<List<InternetAddress>> lookup(String host,
+      {InternetAddressType type: InternetAddressType.any}) {
+    throw new UnsupportedError("InternetAddress.lookup");
+  }
+
+  @patch
+  static InternetAddress _cloneWithNewHost(
+      InternetAddress address, String host) {
+    throw new UnsupportedError("InternetAddress._cloneWithNewHost");
+  }
+}
+
+@patch
+class NetworkInterface {
+  @patch
+  static bool get listSupported {
+    throw new UnsupportedError("NetworkInterface.listSupported");
+  }
+
+  @patch
+  static Future<List<NetworkInterface>> list(
+      {bool includeLoopback: false,
+      bool includeLinkLocal: false,
+      InternetAddressType type: InternetAddressType.any}) {
+    throw new UnsupportedError("NetworkInterface.list");
+  }
+}
+
+@patch
+class RawServerSocket {
+  @patch
+  static Future<RawServerSocket> bind(address, int port,
+      {int backlog: 0, bool v6Only: false, bool shared: false}) {
+    throw new UnsupportedError("RawServerSocket.bind");
+  }
+}
+
+@patch
+class ServerSocket {
+  @patch
+  static Future<ServerSocket> bind(address, int port,
+      {int backlog: 0, bool v6Only: false, bool shared: false}) {
+    throw new UnsupportedError("ServerSocket.bind");
+  }
+}
+
+@patch
+class RawSocket {
+  @patch
+  static Future<RawSocket> connect(host, int port,
+      {sourceAddress, Duration timeout}) {
+    throw new UnsupportedError("RawSocket constructor");
+  }
+
+  @patch
+  static Future<ConnectionTask<RawSocket>> startConnect(host, int port,
+      {sourceAddress}) {
+    throw new UnsupportedError("RawSocket constructor");
+  }
+}
+
+@patch
+class Socket {
+  @patch
+  static Future<Socket> _connect(host, int port,
+      {sourceAddress, Duration timeout}) {
+    throw new UnsupportedError("Socket constructor");
+  }
+
+  @patch
+  static Future<ConnectionTask<Socket>> _startConnect(host, int port,
+      {sourceAddress}) {
+    throw new UnsupportedError("Socket constructor");
+  }
+}
+
+@patch
+class SecureSocket {
+  @patch
+  factory SecureSocket._(RawSecureSocket rawSocket) {
+    throw new UnsupportedError("SecureSocket constructor");
+  }
+}
+
+@patch
+class RawSynchronousSocket {
+  @patch
+  static RawSynchronousSocket connectSync(host, int port) {
+    throw new UnsupportedError("RawSynchronousSocket.connectSync");
+  }
+}
+
+@patch
+class RawSocketOption {
+  @patch
+  static int _getOptionValue(int key) {
+    throw UnsupportedError("RawSocketOption._getOptionValue");
+  }
+}
+
+@patch
+class SecurityContext {
+  @patch
+  factory SecurityContext({bool withTrustedRoots: false}) {
+    throw new UnsupportedError("SecurityContext constructor");
+  }
+
+  @patch
+  static SecurityContext get defaultContext {
+    throw new UnsupportedError("default SecurityContext getter");
+  }
+
+  @patch
+  static bool get alpnSupported {
+    throw new UnsupportedError("SecurityContext alpnSupported getter");
+  }
+}
+
+@patch
+class X509Certificate {
+  @patch
+  factory X509Certificate._() {
+    throw new UnsupportedError("X509Certificate constructor");
+  }
+}
+
+@patch
+class RawDatagramSocket {
+  @patch
+  static Future<RawDatagramSocket> bind(host, int port,
+      {bool reuseAddress: true, bool reusePort: false, int ttl: 1}) {
+    throw new UnsupportedError("RawDatagramSocket.bind");
+  }
+}
+
+@patch
+class _SecureFilter {
+  @patch
+  factory _SecureFilter._() {
+    throw new UnsupportedError("_SecureFilter._SecureFilter");
+  }
+}
+
+@patch
+class _StdIOUtils {
+  @patch
+  static Stdin _getStdioInputStream(int fd) {
+    throw new UnsupportedError("StdIOUtils._getStdioInputStream");
+  }
+
+  @patch
+  static _getStdioOutputStream(int fd) {
+    throw new UnsupportedError("StdIOUtils._getStdioOutputStream");
+  }
+
+  @patch
+  static int _socketType(Socket socket) {
+    throw new UnsupportedError("StdIOUtils._socketType");
+  }
+
+  @patch
+  static _getStdioHandleType(int fd) {
+    throw new UnsupportedError("StdIOUtils._getStdioHandleType");
+  }
+}
+
+@patch
+class _WindowsCodePageDecoder {
+  @patch
+  static String _decodeBytes(List<int> bytes) {
+    throw new UnsupportedError("_WindowsCodePageDecoder._decodeBytes");
+  }
+}
+
+@patch
+class _WindowsCodePageEncoder {
+  @patch
+  static List<int> _encodeString(String string) {
+    throw new UnsupportedError("_WindowsCodePageEncoder._encodeString");
+  }
+}
+
+@patch
+class RawZLibFilter {
+  @patch
+  static RawZLibFilter _makeZLibDeflateFilter(
+      bool gzip,
+      int level,
+      int windowBits,
+      int memLevel,
+      int strategy,
+      List<int> dictionary,
+      bool raw) {
+    throw new UnsupportedError("_newZLibDeflateFilter");
+  }
+
+  @patch
+  static RawZLibFilter _makeZLibInflateFilter(
+      int windowBits, List<int> dictionary, bool raw) {
+    throw new UnsupportedError("_newZLibInflateFilter");
+  }
+}
+
+@patch
+class Stdin {
+  @patch
+  int readByteSync() {
+    throw new UnsupportedError("Stdin.readByteSync");
+  }
+
+  @patch
+  bool get echoMode {
+    throw new UnsupportedError("Stdin.echoMode");
+  }
+
+  @patch
+  void set echoMode(bool enabled) {
+    throw new UnsupportedError("Stdin.echoMode");
+  }
+
+  @patch
+  bool get lineMode {
+    throw new UnsupportedError("Stdin.lineMode");
+  }
+
+  @patch
+  void set lineMode(bool enabled) {
+    throw new UnsupportedError("Stdin.lineMode");
+  }
+
+  @patch
+  bool get supportsAnsiEscapes {
+    throw new UnsupportedError("Stdin.supportsAnsiEscapes");
+  }
+}
+
+@patch
+class Stdout {
+  @patch
+  bool _hasTerminal(int fd) {
+    throw new UnsupportedError("Stdout.hasTerminal");
+  }
+
+  @patch
+  int _terminalColumns(int fd) {
+    throw new UnsupportedError("Stdout.terminalColumns");
+  }
+
+  @patch
+  int _terminalLines(int fd) {
+    throw new UnsupportedError("Stdout.terminalLines");
+  }
+
+  @patch
+  static bool _supportsAnsiEscapes(int fd) {
+    throw new UnsupportedError("Stdout.supportsAnsiEscapes");
+  }
+}
+
+@patch
+class _FileSystemWatcher {
+  @patch
+  static Stream<FileSystemEvent> _watch(
+      String path, int events, bool recursive) {
+    throw new UnsupportedError("_FileSystemWatcher.watch");
+  }
+
+  @patch
+  static bool get isSupported {
+    throw new UnsupportedError("_FileSystemWatcher.isSupported");
+  }
+}
+
+@patch
+class _IOService {
+  @patch
+  static Future _dispatch(int request, List data) {
+    throw new UnsupportedError("_IOService._dispatch");
+  }
+}
diff --git a/sdk_nnbd/lib/_internal/js_runtime/lib/isolate_patch.dart b/sdk_nnbd/lib/_internal/js_runtime/lib/isolate_patch.dart
new file mode 100644
index 0000000..d781e7a
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_runtime/lib/isolate_patch.dart
@@ -0,0 +1,152 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Patch file for the dart:isolate library.
+
+import "dart:async";
+import 'dart:_foreign_helper' show JS;
+import 'dart:_js_helper' show patch;
+import "dart:typed_data" show ByteData, TypedData, Uint8List;
+
+@patch
+class Isolate {
+  @patch
+  static Isolate get current {
+    throw new UnsupportedError("Isolate.current");
+  }
+
+  @patch
+  String get debugName {
+    throw new UnsupportedError("Isolate.debugName");
+  }
+
+  @patch
+  static Future<Uri> get packageRoot {
+    throw new UnsupportedError("Isolate.packageRoot");
+  }
+
+  @patch
+  static Future<Uri> get packageConfig {
+    throw new UnsupportedError("Isolate.packageConfig");
+  }
+
+  @patch
+  static Future<Uri> resolvePackageUri(Uri packageUri) {
+    throw new UnsupportedError("Isolate.resolvePackageUri");
+  }
+
+  @patch
+  static Future<Isolate> spawn<T>(void entryPoint(T message), T message,
+      {bool paused: false,
+      bool errorsAreFatal,
+      SendPort onExit,
+      SendPort onError}) {
+    throw new UnsupportedError("Isolate.spawn");
+  }
+
+  @patch
+  static Future<Isolate> spawnUri(Uri uri, List<String> args, var message,
+      {bool paused: false,
+      SendPort onExit,
+      SendPort onError,
+      bool errorsAreFatal,
+      bool checked,
+      Map<String, String> environment,
+      Uri packageRoot,
+      Uri packageConfig,
+      bool automaticPackageResolution: false}) {
+    throw new UnsupportedError("Isolate.spawnUri");
+  }
+
+  @patch
+  void _pause(Capability resumeCapability) {
+    throw new UnsupportedError("Isolate._pause");
+  }
+
+  @patch
+  void resume(Capability resumeCapability) {
+    throw new UnsupportedError("Isolate.resume");
+  }
+
+  @patch
+  void addOnExitListener(SendPort responsePort, {Object response}) {
+    throw new UnsupportedError("Isolate.addOnExitListener");
+  }
+
+  @patch
+  void removeOnExitListener(SendPort responsePort) {
+    throw new UnsupportedError("Isolate.removeOnExitListener");
+  }
+
+  @patch
+  void setErrorsFatal(bool errorsAreFatal) {
+    throw new UnsupportedError("Isolate.setErrorsFatal");
+  }
+
+  @patch
+  void kill({int priority: beforeNextEvent}) {
+    throw new UnsupportedError("Isolate.kill");
+  }
+
+  @patch
+  void ping(SendPort responsePort, {Object response, int priority: immediate}) {
+    throw new UnsupportedError("Isolate.ping");
+  }
+
+  @patch
+  void addErrorListener(SendPort port) {
+    throw new UnsupportedError("Isolate.addErrorListener");
+  }
+
+  @patch
+  void removeErrorListener(SendPort port) {
+    throw new UnsupportedError("Isolate.removeErrorListener");
+  }
+}
+
+@patch
+class ReceivePort {
+  @patch
+  factory ReceivePort() = _ReceivePortImpl;
+
+  @patch
+  factory ReceivePort.fromRawReceivePort(RawReceivePort rawPort) {
+    throw new UnsupportedError('new ReceivePort.fromRawReceivePort');
+  }
+}
+
+class _ReceivePortImpl extends Stream implements ReceivePort {
+  StreamSubscription listen(void onData(var event),
+      {Function onError, void onDone(), bool cancelOnError}) {
+    throw new UnsupportedError("ReceivePort.listen");
+  }
+
+  void close() {}
+
+  SendPort get sendPort => throw new UnsupportedError("ReceivePort.sendPort");
+}
+
+@patch
+class RawReceivePort {
+  @patch
+  factory RawReceivePort([Function handler]) {
+    throw new UnsupportedError('new RawReceivePort');
+  }
+}
+
+@patch
+class Capability {
+  @patch
+  factory Capability() {
+    throw new UnsupportedError('new Capability');
+  }
+}
+
+@patch
+abstract class TransferableTypedData {
+  @patch
+  factory TransferableTypedData.fromList(List<TypedData> list) {
+    throw new UnsupportedError('TransferableTypedData.fromList');
+  }
+}
diff --git a/sdk_nnbd/lib/_internal/js_runtime/lib/js_array.dart b/sdk_nnbd/lib/_internal/js_runtime/lib/js_array.dart
new file mode 100644
index 0000000..ff820d4
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_runtime/lib/js_array.dart
@@ -0,0 +1,734 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of _interceptors;
+
+class _Growable {
+  const _Growable();
+}
+
+const _ListConstructorSentinel = const _Growable();
+
+/// The interceptor class for [List]. The compiler recognizes this
+/// class as an interceptor, and changes references to [:this:] to
+/// actually use the receiver of the method, which is generated as an extra
+/// argument added to each member.
+class JSArray<E> extends Interceptor implements List<E>, JSIndexable {
+  const JSArray();
+
+  // This factory constructor is the redirection target of the List() factory
+  // constructor. [length] has no type to permit the sentinel value.
+  factory JSArray.list([length = _ListConstructorSentinel]) {
+    if (_ListConstructorSentinel == length) {
+      return new JSArray<E>.emptyGrowable();
+    }
+    return new JSArray<E>.fixed(length);
+  }
+
+  /// Returns a fresh JavaScript Array, marked as fixed-length.
+  ///
+  /// [length] must be a non-negative integer.
+  factory JSArray.fixed(int length) {
+    // Explicit type test is necessary to guard against JavaScript conversions
+    // in unchecked mode, and against `new Array(null)` which creates a single
+    // element Array containing `null`.
+    if (length is! int) {
+      throw new ArgumentError.value(length, 'length', 'is not an integer');
+    }
+    // The JavaScript Array constructor with one argument throws if
+    // the value is not a UInt32. Give a better error message.
+    int maxJSArrayLength = 0xFFFFFFFF;
+    if (length < 0 || length > maxJSArrayLength) {
+      throw new RangeError.range(length, 0, maxJSArrayLength, 'length');
+    }
+    return new JSArray<E>.markFixed(JS('', 'new Array(#)', length));
+  }
+
+  /// Returns a fresh growable JavaScript Array of zero length length.
+  factory JSArray.emptyGrowable() => new JSArray<E>.markGrowable(JS('', '[]'));
+
+  /// Returns a fresh growable JavaScript Array with initial length.
+  ///
+  /// [validatedLength] must be a non-negative integer.
+  factory JSArray.growable(int length) {
+    // Explicit type test is necessary to guard against JavaScript conversions
+    // in unchecked mode.
+    if ((length is! int) || (length < 0)) {
+      throw new ArgumentError('Length must be a non-negative integer: $length');
+    }
+    return new JSArray<E>.markGrowable(JS('', 'new Array(#)', length));
+  }
+
+  /// Constructor for adding type parameters to an existing JavaScript Array.
+  /// The compiler specially recognizes this constructor.
+  ///
+  ///     var a = new JSArray<int>.typed(JS('JSExtendableArray', '[]'));
+  ///     a is List<int>    --> true
+  ///     a is List<String> --> false
+  ///
+  /// Usually either the [JSArray.markFixed] or [JSArray.markGrowable]
+  /// constructors is used instead.
+  ///
+  /// The input must be a JavaScript Array.  The JS form is just a re-assertion
+  /// to help type analysis when the input type is sloppy.
+  factory JSArray.typed(allocation) => JS('JSArray', '#', allocation);
+
+  factory JSArray.markFixed(allocation) =>
+      JS('JSFixedArray', '#', markFixedList(new JSArray<E>.typed(allocation)));
+
+  factory JSArray.markGrowable(allocation) =>
+      JS('JSExtendableArray', '#', new JSArray<E>.typed(allocation));
+
+  static List markFixedList(List list) {
+    // Functions are stored in the hidden class and not as properties in
+    // the object. We never actually look at the value, but only want
+    // to know if the property exists.
+    JS('void', r'#.fixed$length = Array', list);
+    return JS('JSFixedArray', '#', list);
+  }
+
+  static List markUnmodifiableList(List list) {
+    // Functions are stored in the hidden class and not as properties in
+    // the object. We never actually look at the value, but only want
+    // to know if the property exists.
+    JS('void', r'#.fixed$length = Array', list);
+    JS('void', r'#.immutable$list = Array', list);
+    return JS('JSUnmodifiableArray', '#', list);
+  }
+
+  static bool isFixedLength(JSArray a) {
+    return !JS('bool', r'!#.fixed$length', a);
+  }
+
+  static bool isUnmodifiable(JSArray a) {
+    return !JS('bool', r'!#.immutable$list', a);
+  }
+
+  static bool isGrowable(JSArray a) {
+    return !isFixedLength(a);
+  }
+
+  static bool isMutable(JSArray a) {
+    return !isUnmodifiable(a);
+  }
+
+  checkMutable(String reason) {
+    if (!isMutable(this)) {
+      throw UnsupportedError(reason);
+    }
+  }
+
+  checkGrowable(String reason) {
+    if (!isGrowable(this)) {
+      throw UnsupportedError(reason);
+    }
+  }
+
+  List<R> cast<R>() => List.castFrom<E, R>(this);
+  void add(E value) {
+    checkGrowable('add');
+    JS('void', r'#.push(#)', this, value);
+  }
+
+  E removeAt(int index) {
+    checkGrowable('removeAt');
+    if (index is! int) throw argumentErrorValue(index);
+    if (index < 0 || index >= length) {
+      throw new RangeError.value(index);
+    }
+    return JS('', r'#.splice(#, 1)[0]', this, index);
+  }
+
+  void insert(int index, E value) {
+    checkGrowable('insert');
+    if (index is! int) throw argumentErrorValue(index);
+    if (index < 0 || index > length) {
+      throw new RangeError.value(index);
+    }
+    JS('void', r'#.splice(#, 0, #)', this, index, value);
+  }
+
+  void insertAll(int index, Iterable<E> iterable) {
+    checkGrowable('insertAll');
+    RangeError.checkValueInInterval(index, 0, this.length, 'index');
+    if (iterable is! EfficientLengthIterable) {
+      iterable = iterable.toList();
+    }
+    int insertionLength = iterable.length;
+    this.length += insertionLength;
+    int end = index + insertionLength;
+    this.setRange(end, this.length, this, index);
+    this.setRange(index, end, iterable);
+  }
+
+  void setAll(int index, Iterable<E> iterable) {
+    checkMutable('setAll');
+    RangeError.checkValueInInterval(index, 0, this.length, 'index');
+    for (var element in iterable) {
+      this[index++] = element;
+    }
+  }
+
+  E removeLast() {
+    checkGrowable('removeLast');
+    if (length == 0) throw diagnoseIndexError(this, -1);
+    return JS('', r'#.pop()', this);
+  }
+
+  bool remove(Object element) {
+    checkGrowable('remove');
+    for (int i = 0; i < this.length; i++) {
+      if (this[i] == element) {
+        JS('', r'#.splice(#, 1)', this, i);
+        return true;
+      }
+    }
+    return false;
+  }
+
+  /// Removes elements matching [test] from [this] List.
+  void removeWhere(bool test(E element)) {
+    checkGrowable('removeWhere');
+    _removeWhere(test, true);
+  }
+
+  void retainWhere(bool test(E element)) {
+    checkGrowable('retainWhere');
+    _removeWhere(test, false);
+  }
+
+  void _removeWhere(bool test(E element), bool removeMatching) {
+    // Performed in two steps, to avoid exposing an inconsistent state
+    // to the [test] function. First the elements to retain are found, and then
+    // the original list is updated to contain those elements.
+
+    // TODO(sra): Replace this algorithm with one that retains a list of ranges
+    // to be removed.  Most real uses remove 0, 1 or a few clustered elements.
+
+    List retained = [];
+    int end = this.length;
+    for (int i = 0; i < end; i++) {
+      // TODO(22407): Improve bounds check elimination to allow this JS code to
+      // be replaced by indexing.
+      var element = JS<E>('', '#[#]', this, i);
+      // !test() ensures bool conversion in checked mode.
+      if (!test(element) == removeMatching) {
+        retained.add(element);
+      }
+      if (this.length != end) throw new ConcurrentModificationError(this);
+    }
+    if (retained.length == end) return;
+    this.length = retained.length;
+    for (int i = 0; i < retained.length; i++) {
+      // We don't need a bounds check or an element type check.
+      JS('', '#[#] = #', this, i, retained[i]);
+    }
+  }
+
+  Iterable<E> where(bool f(E element)) {
+    return new WhereIterable<E>(this, f);
+  }
+
+  Iterable<T> expand<T>(Iterable<T> f(E element)) {
+    return new ExpandIterable<E, T>(this, f);
+  }
+
+  void addAll(Iterable<E> collection) {
+    int i = this.length;
+    checkGrowable('addAll');
+    for (E e in collection) {
+      assert(
+          i++ == this.length || (throw new ConcurrentModificationError(this)));
+      JS('void', r'#.push(#)', this, e);
+    }
+  }
+
+  void clear() {
+    length = 0;
+  }
+
+  void forEach(void f(E element)) {
+    int end = this.length;
+    for (int i = 0; i < end; i++) {
+      // TODO(22407): Improve bounds check elimination to allow this JS code to
+      // be replaced by indexing.
+      var element = JS<E>('', '#[#]', this, i);
+      f(element);
+      if (this.length != end) throw new ConcurrentModificationError(this);
+    }
+  }
+
+  Iterable<T> map<T>(T f(E element)) {
+    return new MappedListIterable<E, T>(this, f);
+  }
+
+  String join([String separator = '']) {
+    var list = new List(this.length);
+    for (int i = 0; i < this.length; i++) {
+      list[i] = '${this[i]}';
+    }
+    return JS('String', '#.join(#)', list, separator);
+  }
+
+  Iterable<E> take(int n) {
+    return new SubListIterable<E>(this, 0, n);
+  }
+
+  Iterable<E> takeWhile(bool test(E value)) {
+    return new TakeWhileIterable<E>(this, test);
+  }
+
+  Iterable<E> skip(int n) {
+    return new SubListIterable<E>(this, n, null);
+  }
+
+  Iterable<E> skipWhile(bool test(E value)) {
+    return new SkipWhileIterable<E>(this, test);
+  }
+
+  E reduce(E combine(E previousValue, E element)) {
+    int length = this.length;
+    if (length == 0) throw IterableElementError.noElement();
+    E value = this[0];
+    for (int i = 1; i < length; i++) {
+      // TODO(22407): Improve bounds check elimination to allow this JS code to
+      // be replaced by indexing.
+      var element = JS<E>('', '#[#]', this, i);
+      value = combine(value, element);
+      if (length != this.length) throw new ConcurrentModificationError(this);
+    }
+    return value;
+  }
+
+  T fold<T>(T initialValue, T combine(T previousValue, E element)) {
+    var value = initialValue;
+    int length = this.length;
+    for (int i = 0; i < length; i++) {
+      // TODO(22407): Improve bounds check elimination to allow this JS code to
+      // be replaced by indexing.
+      var element = JS<E>('', '#[#]', this, i);
+      value = combine(value, element);
+      if (this.length != length) throw new ConcurrentModificationError(this);
+    }
+    return value;
+  }
+
+  E firstWhere(bool test(E value), {E orElse()}) {
+    var end = this.length;
+    for (int i = 0; i < end; ++i) {
+      // TODO(22407): Improve bounds check elimination to allow this JS code to
+      // be replaced by indexing.
+      var element = JS<E>('', '#[#]', this, i);
+      if (test(element)) return element;
+      if (this.length != end) throw new ConcurrentModificationError(this);
+    }
+    if (orElse != null) return orElse();
+    throw IterableElementError.noElement();
+  }
+
+  E lastWhere(bool test(E element), {E orElse()}) {
+    int length = this.length;
+    for (int i = length - 1; i >= 0; i--) {
+      // TODO(22407): Improve bounds check elimination to allow this JS code to
+      // be replaced by indexing.
+      var element = JS<E>('', '#[#]', this, i);
+      if (test(element)) return element;
+      if (length != this.length) {
+        throw new ConcurrentModificationError(this);
+      }
+    }
+    if (orElse != null) return orElse();
+    throw IterableElementError.noElement();
+  }
+
+  E singleWhere(bool test(E element), {E orElse()}) {
+    int length = this.length;
+    E match = null;
+    bool matchFound = false;
+    for (int i = 0; i < length; i++) {
+      // TODO(22407): Improve bounds check elimination to allow this JS code to
+      // be replaced by indexing.
+      var element = JS<E>('', '#[#]', this, i);
+      if (test(element)) {
+        if (matchFound) {
+          throw IterableElementError.tooMany();
+        }
+        matchFound = true;
+        match = element;
+      }
+      if (length != this.length) {
+        throw new ConcurrentModificationError(this);
+      }
+    }
+    if (matchFound) return match;
+    if (orElse != null) return orElse();
+    throw IterableElementError.noElement();
+  }
+
+  E elementAt(int index) {
+    return this[index];
+  }
+
+  List<E> sublist(int start, [int end]) {
+    checkNull(start); // TODO(ahe): This is not specified but co19 tests it.
+    if (start is! int) throw argumentErrorValue(start);
+    if (start < 0 || start > length) {
+      throw new RangeError.range(start, 0, length, 'start');
+    }
+    if (end == null) {
+      end = length;
+    } else {
+      if (end is! int) throw argumentErrorValue(end);
+      if (end < start || end > length) {
+        throw new RangeError.range(end, start, length, 'end');
+      }
+    }
+    if (start == end) return <E>[];
+    return new JSArray<E>.markGrowable(
+        JS('', r'#.slice(#, #)', this, start, end));
+  }
+
+  Iterable<E> getRange(int start, int end) {
+    RangeError.checkValidRange(start, end, this.length);
+    return new SubListIterable<E>(this, start, end);
+  }
+
+  E get first {
+    if (length > 0) return this[0];
+    throw IterableElementError.noElement();
+  }
+
+  E get last {
+    if (length > 0) return this[length - 1];
+    throw IterableElementError.noElement();
+  }
+
+  E get single {
+    if (length == 1) return this[0];
+    if (length == 0) throw IterableElementError.noElement();
+    throw IterableElementError.tooMany();
+  }
+
+  void removeRange(int start, int end) {
+    checkGrowable('removeRange');
+    RangeError.checkValidRange(start, end, this.length);
+    int deleteCount = end - start;
+    JS('', '#.splice(#, #)', this, start, deleteCount);
+  }
+
+  void setRange(int start, int end, Iterable<E> iterable, [int skipCount = 0]) {
+    checkMutable('setRange');
+
+    RangeError.checkValidRange(start, end, this.length);
+    int length = end - start;
+    if (length == 0) return;
+    RangeError.checkNotNegative(skipCount, 'skipCount');
+
+    List<E> otherList;
+    int otherStart;
+    // TODO(floitsch): Make this accept more.
+    if (iterable is List) {
+      otherList = iterable;
+      otherStart = skipCount;
+    } else {
+      otherList = iterable.skip(skipCount).toList(growable: false);
+      otherStart = 0;
+    }
+    if (otherStart + length > otherList.length) {
+      throw IterableElementError.tooFew();
+    }
+    if (otherStart < start) {
+      // Copy backwards to ensure correct copy if [from] is this.
+      // TODO(sra): If [from] is the same Array as [this], we can copy without
+      // type annotation checks on the stores.
+      for (int i = length - 1; i >= 0; i--) {
+        // Use JS to avoid bounds check (the bounds check elimination
+        // optimzation is too weak). The 'E' type annotation is a store type
+        // check - we can't rely on iterable, it could be List<dynamic>.
+        E element = otherList[otherStart + i];
+        JS('', '#[#] = #', this, start + i, element);
+      }
+    } else {
+      for (int i = 0; i < length; i++) {
+        E element = otherList[otherStart + i];
+        JS('', '#[#] = #', this, start + i, element);
+      }
+    }
+  }
+
+  void fillRange(int start, int end, [E fillValue]) {
+    checkMutable('fill range');
+    RangeError.checkValidRange(start, end, this.length);
+    for (int i = start; i < end; i++) {
+      // Store is safe since [fillValue] type has been checked as parameter.
+      JS('', '#[#] = #', this, i, fillValue);
+    }
+  }
+
+  void replaceRange(int start, int end, Iterable<E> replacement) {
+    checkGrowable('replaceRange');
+    RangeError.checkValidRange(start, end, this.length);
+    if (replacement is! EfficientLengthIterable) {
+      replacement = replacement.toList();
+    }
+    int removeLength = end - start;
+    int insertLength = replacement.length;
+    if (removeLength >= insertLength) {
+      int delta = removeLength - insertLength;
+      int insertEnd = start + insertLength;
+      int newLength = this.length - delta;
+      this.setRange(start, insertEnd, replacement);
+      if (delta != 0) {
+        this.setRange(insertEnd, newLength, this, end);
+        this.length = newLength;
+      }
+    } else {
+      int delta = insertLength - removeLength;
+      int newLength = this.length + delta;
+      int insertEnd = start + insertLength; // aka. end + delta.
+      this.length = newLength;
+      this.setRange(insertEnd, newLength, this, end);
+      this.setRange(start, insertEnd, replacement);
+    }
+  }
+
+  bool any(bool test(E element)) {
+    int end = this.length;
+    for (int i = 0; i < end; i++) {
+      // TODO(22407): Improve bounds check elimination to allow this JS code to
+      // be replaced by indexing.
+      var element = JS<E>('', '#[#]', this, i);
+      if (test(element)) return true;
+      if (this.length != end) throw new ConcurrentModificationError(this);
+    }
+    return false;
+  }
+
+  bool every(bool test(E element)) {
+    int end = this.length;
+    for (int i = 0; i < end; i++) {
+      // TODO(22407): Improve bounds check elimination to allow this JS code to
+      // be replaced by indexing.
+      var element = JS<E>('', '#[#]', this, i);
+      if (!test(element)) return false;
+      if (this.length != end) throw new ConcurrentModificationError(this);
+    }
+    return true;
+  }
+
+  Iterable<E> get reversed => new ReversedListIterable<E>(this);
+
+  void sort([int compare(E a, E b)]) {
+    checkMutable('sort');
+    Sort.sort(this, compare ?? _compareAny);
+  }
+
+  static int _compareAny(a, b) {
+    // In strong mode Comparable.compare requires an implicit cast to ensure
+    // `a` and `b` are Comparable.
+    return Comparable.compare(a, b);
+  }
+
+  void shuffle([Random random]) {
+    checkMutable('shuffle');
+    if (random == null) random = new Random();
+    int length = this.length;
+    while (length > 1) {
+      int pos = random.nextInt(length);
+      length -= 1;
+      var tmp = this[length];
+      this[length] = this[pos];
+      this[pos] = tmp;
+    }
+  }
+
+  int indexOf(Object element, [int start = 0]) {
+    if (start >= this.length) {
+      return -1;
+    }
+    if (start < 0) {
+      start = 0;
+    }
+    for (int i = start; i < this.length; i++) {
+      if (this[i] == element) {
+        return i;
+      }
+    }
+    return -1;
+  }
+
+  int lastIndexOf(Object element, [int startIndex]) {
+    if (startIndex == null) {
+      startIndex = this.length - 1;
+    } else {
+      if (startIndex < 0) {
+        return -1;
+      }
+      if (startIndex >= this.length) {
+        startIndex = this.length - 1;
+      }
+    }
+    for (int i = startIndex; i >= 0; i--) {
+      if (this[i] == element) {
+        return i;
+      }
+    }
+    return -1;
+  }
+
+  bool contains(Object other) {
+    for (int i = 0; i < length; i++) {
+      if (this[i] == other) return true;
+    }
+    return false;
+  }
+
+  bool get isEmpty => length == 0;
+
+  bool get isNotEmpty => !isEmpty;
+
+  String toString() => ListBase.listToString(this);
+
+  List<E> toList({bool growable: true}) =>
+      growable ? _toListGrowable() : _toListFixed();
+
+  List<E> _toListGrowable() =>
+      // slice(0) is slightly faster than slice()
+      new JSArray<E>.markGrowable(JS('', '#.slice(0)', this));
+
+  List<E> _toListFixed() =>
+      new JSArray<E>.markFixed(JS('', '#.slice(0)', this));
+
+  Set<E> toSet() => new Set<E>.from(this);
+
+  Iterator<E> get iterator => new ArrayIterator<E>(this);
+
+  int get hashCode => Primitives.objectHashCode(this);
+
+  int get length => JS('JSUInt32', r'#.length', this);
+
+  set length(int newLength) {
+    checkGrowable('set length');
+    if (newLength is! int) {
+      throw new ArgumentError.value(newLength, 'newLength');
+    }
+    // TODO(sra): Remove this test and let JavaScript throw an error.
+    if (newLength < 0) {
+      throw new RangeError.range(newLength, 0, null, 'newLength');
+    }
+    // JavaScript with throw a RangeError for numbers that are too big. The
+    // message does not contain the value.
+    JS('void', r'#.length = #', this, newLength);
+  }
+
+  E operator [](int index) {
+    if (index is! int) throw diagnoseIndexError(this, index);
+    if (index >= length || index < 0) throw diagnoseIndexError(this, index);
+    return JS('', '#[#]', this, index);
+  }
+
+  void operator []=(int index, E value) {
+    checkMutable('indexed set');
+    if (index is! int) throw diagnoseIndexError(this, index);
+    if (index >= length || index < 0) throw diagnoseIndexError(this, index);
+    JS('void', r'#[#] = #', this, index, value);
+  }
+
+  Map<int, E> asMap() {
+    return new ListMapView<E>(this);
+  }
+
+  Iterable<E> followedBy(Iterable<E> other) =>
+      new FollowedByIterable<E>.firstEfficient(this, other);
+
+  Iterable<T> whereType<T>() => new WhereTypeIterable<T>(this);
+
+  List<E> operator +(List<E> other) {
+    int totalLength = this.length + other.length;
+    return <E>[]
+      ..length = totalLength
+      ..setRange(0, this.length, this)
+      ..setRange(this.length, totalLength, other);
+  }
+
+  int indexWhere(bool test(E element), [int start = 0]) {
+    if (start >= this.length) return -1;
+    if (start < 0) start = 0;
+    for (int i = start; i < this.length; i++) {
+      if (test(this[i])) return i;
+    }
+    return -1;
+  }
+
+  int lastIndexWhere(bool test(E element), [int start]) {
+    if (start == null) start = this.length - 1;
+    if (start < 0) return -1;
+    for (int i = start; i >= 0; i--) {
+      if (test(this[i])) return i;
+    }
+    return -1;
+  }
+
+  void set first(E element) {
+    if (this.isEmpty) throw IterableElementError.noElement();
+    this[0] = element;
+  }
+
+  void set last(E element) {
+    if (this.isEmpty) throw IterableElementError.noElement();
+    this[this.length - 1] = element;
+  }
+}
+
+/// Dummy subclasses that allow the backend to track more precise
+/// information about arrays through their type. The CPA type inference
+/// relies on the fact that these classes do not override [] nor []=.
+///
+/// These classes are really a fiction, and can have no methods, since
+/// getInterceptor always returns JSArray.  We should consider pushing the
+/// 'isGrowable' and 'isMutable' checks into the getInterceptor implementation
+/// so these classes can have specialized implementations. Doing so will
+/// challenge many assumptions in the JS backend.
+class JSMutableArray<E> extends JSArray<E> implements JSMutableIndexable {}
+
+class JSFixedArray<E> extends JSMutableArray<E> {}
+
+class JSExtendableArray<E> extends JSMutableArray<E> {}
+
+class JSUnmodifiableArray<E> extends JSArray<E> {} // Already is JSIndexable.
+
+/// An [Iterator] that iterates a JSArray.
+///
+class ArrayIterator<E> implements Iterator<E> {
+  final JSArray<E> _iterable;
+  final int _length;
+  int _index;
+  E _current;
+
+  ArrayIterator(JSArray<E> iterable)
+      : _iterable = iterable,
+        _length = iterable.length,
+        _index = 0;
+
+  E get current => _current;
+
+  bool moveNext() {
+    int length = _iterable.length;
+
+    // We have to do the length check even on fixed length Arrays.  If we can
+    // inline moveNext() we might be able to GVN the length and eliminate this
+    // check on known fixed length JSArray.
+    if (_length != length) {
+      throw throwConcurrentModificationError(_iterable);
+    }
+
+    if (_index >= length) {
+      _current = null;
+      return false;
+    }
+    _current = _iterable[_index];
+    _index++;
+    return true;
+  }
+}
diff --git a/sdk_nnbd/lib/_internal/js_runtime/lib/js_helper.dart b/sdk_nnbd/lib/_internal/js_runtime/lib/js_helper.dart
new file mode 100644
index 0000000..8c167115
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_runtime/lib/js_helper.dart
@@ -0,0 +1,3551 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library _js_helper;
+
+import 'dart:_js_embedded_names'
+    show
+        CURRENT_SCRIPT,
+        DEFERRED_LIBRARY_PARTS,
+        DEFERRED_PART_URIS,
+        DEFERRED_PART_HASHES,
+        GET_TYPE_FROM_NAME,
+        GET_ISOLATE_TAG,
+        INITIALIZE_LOADED_HUNK,
+        INTERCEPTED_NAMES,
+        INTERCEPTORS_BY_TAG,
+        IS_HUNK_LOADED,
+        IS_HUNK_INITIALIZED,
+        JsBuiltin,
+        JsGetName,
+        LEAF_TAGS,
+        NATIVE_SUPERCLASS_TAG_NAME,
+        STATIC_FUNCTION_NAME_PROPERTY_NAME;
+
+import 'dart:collection';
+
+import 'dart:async' show Completer, DeferredLoadException, Future;
+
+import 'dart:_foreign_helper'
+    show
+        DART_CLOSURE_TO_JS,
+        getInterceptor,
+        JS,
+        JS_BUILTIN,
+        JS_CONST,
+        JS_EFFECT,
+        JS_EMBEDDED_GLOBAL,
+        JS_GET_FLAG,
+        JS_GET_NAME,
+        JS_INTERCEPTOR_CONSTANT,
+        JS_STRING_CONCAT,
+        RAW_DART_FUNCTION_REF;
+
+import 'dart:_interceptors';
+import 'dart:_internal' as _symbol_dev;
+import 'dart:_internal'
+    show
+        EfficientLengthIterable,
+        MappedIterable,
+        IterableElementError,
+        SubListIterable;
+
+import 'dart:_native_typed_data';
+
+import 'dart:_js_names'
+    show
+        extractKeys,
+        unmangleGlobalNameIfPreservedAnyways,
+        unmangleAllIdentifiersIfPreservedAnyways;
+
+import 'dart:_rti' as newRti
+    show
+        createRuntimeType,
+        evalInInstance,
+        getRuntimeType,
+        getTypeFromTypesTable,
+        instanceTypeName,
+        instantiatedGenericFunctionType;
+
+part 'annotations.dart';
+part 'constant_map.dart';
+part 'instantiation.dart';
+part 'native_helper.dart';
+part 'regexp_helper.dart';
+part 'string_helper.dart';
+part 'js_rti.dart';
+part 'linked_hash_map.dart';
+
+/// Marks the internal map in dart2js, so that internal libraries can is-check
+/// them.
+abstract class InternalMap {}
+
+/// Extracts the JavaScript-constructor name from the given isCheckProperty.
+// TODO(floitsch): move this to foreign_helper.dart or similar.
+@pragma('dart2js:tryInline')
+String isCheckPropertyToJsConstructorName(String isCheckProperty) {
+  return JS_BUILTIN('returns:String;depends:none;effects:none',
+      JsBuiltin.isCheckPropertyToJsConstructorName, isCheckProperty);
+}
+
+/// Returns true if the given [type] is a function type object.
+// TODO(floitsch): move this to foreign_helper.dart or similar.
+@pragma('dart2js:tryInline')
+bool isDartFunctionType(Object type) {
+  // Function type test is using the `in` operator which doesn't work on
+  // primitive types.
+  assert(!(type == null || type is num || type is String));
+  return JS_BUILTIN(
+      'returns:bool;effects:none;depends:none', JsBuiltin.isFunctionType, type);
+}
+
+/// Returns true if the given [type] is a FutureOr type object.
+// TODO(floitsch): move this to foreign_helper.dart or similar.
+@pragma('dart2js:tryInline')
+bool isDartFutureOrType(Object type) {
+  // FutureOr test is using the `in` operator which doesn't work on primitive
+  // types.
+  assert(!(type == null || type is num || type is String));
+  return JS_BUILTIN(
+      'returns:bool;effects:none;depends:none', JsBuiltin.isFutureOrType, type);
+}
+
+@pragma('dart2js:tryInline')
+bool isDartVoidTypeRti(Object type) {
+  return JS_BUILTIN(
+      'returns:bool;effects:none;depends:none', JsBuiltin.isVoidType, type);
+}
+
+/// Retrieves the class name from type information stored on the constructor of
+/// [type].
+// TODO(floitsch): move this to foreign_helper.dart or similar.
+@pragma('dart2js:tryInline')
+String rawRtiToJsConstructorName(Object rti) {
+  return JS_BUILTIN('String', JsBuiltin.rawRtiToJsConstructorName, rti);
+}
+
+/// Given a raw constructor name, return the unminified name, if available,
+/// otherwise tag the name with `minified:`.
+String unminifyOrTag(String rawClassName) {
+  String preserved = unmangleGlobalNameIfPreservedAnyways(rawClassName);
+  if (preserved is String) return preserved;
+  if (JS_GET_FLAG('MINIFIED')) return 'minified:${rawClassName}';
+  return rawClassName;
+}
+
+/// Returns the rti from the given [constructorName].
+// TODO(floitsch): make this a builtin.
+jsConstructorNameToRti(String constructorName) {
+  var getTypeFromName = JS_EMBEDDED_GLOBAL('', GET_TYPE_FROM_NAME);
+  return JS('', '#(#)', getTypeFromName, constructorName);
+}
+
+/// Returns the raw runtime type of the given object [o].
+///
+/// The argument [o] must be the interceptor for primitive types. If
+/// necessary run it through [getInterceptor] first.
+// TODO(floitsch): move this to foreign_helper.dart or similar.
+// TODO(floitsch): we should call getInterceptor ourselves, but currently
+//    getInterceptor is not GVNed.
+@pragma('dart2js:tryInline')
+Object getRawRuntimeType(Object o) {
+  return JS_BUILTIN('', JsBuiltin.rawRuntimeType, o);
+}
+
+/// Returns whether the given [type] is a subtype of [other].
+///
+/// The argument [other] is the name of the other type, as computed by
+/// [runtimeTypeToString].
+@pragma('dart2js:tryInline')
+bool builtinIsSubtype(type, String other) {
+  return JS_BUILTIN('returns:bool;effects:none;depends:none',
+      JsBuiltin.isSubtype, other, type);
+}
+
+/// Returns true if the given [type] is _the_ `Function` type.
+// TODO(floitsch): move this to foreign_helper.dart or similar.
+@pragma('dart2js:tryInline')
+bool isDartFunctionTypeRti(Object type) {
+  return JS_BUILTIN(
+      'returns:bool;effects:none;depends:none',
+      JsBuiltin.isGivenTypeRti,
+      type,
+      JS_GET_NAME(JsGetName.FUNCTION_CLASS_TYPE_NAME));
+}
+
+/// Returns true if the given [type] is _the_ `Null` type.
+@pragma('dart2js:tryInline')
+bool isNullType(Object type) {
+  return JS_BUILTIN(
+      'returns:bool;effects:none;depends:none',
+      JsBuiltin.isGivenTypeRti,
+      type,
+      JS_GET_NAME(JsGetName.NULL_CLASS_TYPE_NAME));
+}
+
+/// Returns whether the given type is the dynamic type.
+// TODO(floitsch): move this to foreign_helper.dart or similar.
+@pragma('dart2js:tryInline')
+bool isDartDynamicTypeRti(type) {
+  return JS_BUILTIN(
+      'returns:bool;effects:none;depends:none', JsBuiltin.isDynamicType, type);
+}
+
+@pragma('dart2js:tryInline')
+bool isDartJsInteropTypeArgumentRti(type) {
+  return JS_BUILTIN('returns:bool;effects:none;depends:none',
+      JsBuiltin.isJsInteropTypeArgument, type);
+}
+
+/// Returns whether the given type is _the_ Dart Object type.
+// TODO(floitsch): move this to foreign_helper.dart or similar.
+@pragma('dart2js:tryInline')
+bool isDartObjectTypeRti(type) {
+  return JS_BUILTIN(
+      'returns:bool;effects:none;depends:none',
+      JsBuiltin.isGivenTypeRti,
+      type,
+      JS_GET_NAME(JsGetName.OBJECT_CLASS_TYPE_NAME));
+}
+
+/// Returns whether the given type is _the_ null type.
+// TODO(floitsch): move this to foreign_helper.dart or similar.
+@pragma('dart2js:tryInline')
+bool isNullTypeRti(type) {
+  return JS_BUILTIN(
+      'returns:bool;effects:none;depends:none',
+      JsBuiltin.isGivenTypeRti,
+      type,
+      JS_GET_NAME(JsGetName.NULL_CLASS_TYPE_NAME));
+}
+
+/// Returns the metadata of the given [index].
+// TODO(floitsch): move this to foreign_helper.dart or similar.
+@pragma('dart2js:tryInline')
+getMetadata(int index) {
+  return JS_BUILTIN(
+      'returns:var;effects:none;depends:none', JsBuiltin.getMetadata, index);
+}
+
+/// Returns the type of the given [index].
+// TODO(floitsch): move this to foreign_helper.dart or similar.
+@pragma('dart2js:tryInline')
+getType(int index) {
+  return JS_BUILTIN(
+      'returns:var;effects:none;depends:none', JsBuiltin.getType, index);
+}
+
+/// No-op method that is called to inform the compiler that preambles might
+/// be needed when executing the resulting JS file in a command-line
+/// JS engine.
+requiresPreamble() {}
+
+bool isJsIndexable(var object, var record) {
+  if (record != null) {
+    var result = dispatchRecordIndexability(record);
+    if (result != null) return result;
+  }
+  return object is JavaScriptIndexingBehavior;
+}
+
+String S(value) {
+  if (value is String) return value;
+  if (value is num) {
+    if (value != 0) {
+      // ""+x is faster than String(x) for integers on most browsers.
+      return JS('String', r'"" + (#)', value);
+    }
+  } else if (true == value) {
+    return 'true';
+  } else if (false == value) {
+    return 'false';
+  } else if (value == null) {
+    return 'null';
+  }
+  var res = value.toString();
+  if (res is! String) throw argumentErrorValue(value);
+  return res;
+}
+
+// Called from generated code.
+createInvocationMirror(
+    String name, internalName, kind, arguments, argumentNames, types) {
+  // TODO(sra): [types] (the number of type arguments) could be omitted in the
+  // generated stub code to save an argument. Then we would use `types ?? 0`.
+  return new JSInvocationMirror(
+      name, internalName, kind, arguments, argumentNames, types);
+}
+
+createUnmangledInvocationMirror(
+    Symbol symbol, internalName, kind, arguments, argumentNames, types) {
+  return new JSInvocationMirror(
+      symbol, internalName, kind, arguments, argumentNames, types);
+}
+
+void throwInvalidReflectionError(String memberName) {
+  throw new UnsupportedError("Can't use '$memberName' in reflection "
+      "because it is not included in a @MirrorsUsed annotation.");
+}
+
+/// Helper used to instrument calls when the compiler is invoked with
+/// `--experiment-call-instrumentation`.
+///
+/// By default, whenever a method is invoked for the first time, it prints an id
+/// and the method name to the console. This can be overriden by adding a top
+/// level `dartCallInstrumentation` hook in JavaScript.
+@pragma('dart2js:noInline')
+void traceHelper(dynamic /*int*/ id, dynamic /*String*/ qualifiedName) {
+  // Note: this method is written mostly in JavaScript to prevent a stack
+  // overflow. In particular, we use dynamic argument types because with with
+  // types, traceHelper would include type checks for the parameter types, those
+  // checks (intTypeCheck, stringTypeCheck) are themselves calls that end up
+  // invoking this traceHelper and produce a stack overflow.  Similarly if we
+  // had Dart code below using, for example, string interpolation, we would
+  // include extra calls to the Dart runtime that could also trigger a stack
+  // overflow. This approach here is simpler than making the compiler smart
+  // about how to generate traceHelper calls more carefully.
+  JS(
+      '',
+      r'''
+      (function (id, name) {
+        var hook = self.dartCallInstrumentation;
+        if (typeof hook === "function") {
+          hook(id, name);
+          return;
+        }
+        if (!this.callInstrumentationCache) {
+          this.callInstrumentationCache = Object.create(null);
+        }
+        if (!this.callInstrumentationCache[id]) {
+          console.log(id, name);
+          this.callInstrumentationCache[id] = true;
+        }
+      })(#, #)''',
+      id,
+      qualifiedName);
+}
+
+class JSInvocationMirror implements Invocation {
+  static const METHOD = 0;
+  static const GETTER = 1;
+  static const SETTER = 2;
+
+  /// When [_memberName] is a String, it holds the mangled name of this
+  /// invocation.  When it is a Symbol, it holds the unmangled name.
+  var /* String or Symbol */ _memberName;
+  final String _internalName;
+  final int _kind;
+  final List _arguments;
+  final List _namedArgumentNames;
+  final int _typeArgumentCount;
+
+  JSInvocationMirror(this._memberName, this._internalName, this._kind,
+      this._arguments, this._namedArgumentNames, this._typeArgumentCount);
+
+  Symbol get memberName {
+    if (_memberName is Symbol) return _memberName;
+    return _memberName = new _symbol_dev.Symbol.unvalidated(_memberName);
+  }
+
+  bool get isMethod => _kind == METHOD;
+  bool get isGetter => _kind == GETTER;
+  bool get isSetter => _kind == SETTER;
+  bool get isAccessor => _kind != METHOD;
+
+  List<Type> get typeArguments {
+    if (_typeArgumentCount == 0) return const <Type>[];
+    int start = _arguments.length - _typeArgumentCount;
+    var list = <Type>[];
+    if (JS_GET_FLAG('USE_NEW_RTI')) {
+      for (int index = 0; index < _typeArgumentCount; index++) {
+        list.add(newRti.createRuntimeType(_arguments[start + index]));
+      }
+    } else {
+      for (int index = 0; index < _typeArgumentCount; index++) {
+        list.add(createRuntimeType(_arguments[start + index]));
+      }
+    }
+    return list;
+  }
+
+  List get positionalArguments {
+    if (isGetter) return const [];
+    var argumentCount =
+        _arguments.length - _namedArgumentNames.length - _typeArgumentCount;
+    if (argumentCount == 0) return const [];
+    var list = [];
+    for (var index = 0; index < argumentCount; index++) {
+      list.add(_arguments[index]);
+    }
+    return JSArray.markUnmodifiableList(list);
+  }
+
+  Map<Symbol, dynamic> get namedArguments {
+    if (isAccessor) return const <Symbol, dynamic>{};
+    int namedArgumentCount = _namedArgumentNames.length;
+    int namedArgumentsStartIndex =
+        _arguments.length - namedArgumentCount - _typeArgumentCount;
+    if (namedArgumentCount == 0) return const <Symbol, dynamic>{};
+    var map = new Map<Symbol, dynamic>();
+    for (int i = 0; i < namedArgumentCount; i++) {
+      map[new _symbol_dev.Symbol.unvalidated(_namedArgumentNames[i])] =
+          _arguments[namedArgumentsStartIndex + i];
+    }
+    return new ConstantMapView<Symbol, dynamic>(map);
+  }
+}
+
+class Primitives {
+  static int objectHashCode(object) {
+    int hash = JS('int|Null', r'#.$identityHash', object);
+    if (hash == null) {
+      hash = JS('int', '(Math.random() * 0x3fffffff) | 0');
+      JS('void', r'#.$identityHash = #', object, hash);
+    }
+    return JS('int', '#', hash);
+  }
+
+  static int parseInt(String source, int radix) {
+    checkString(source);
+    var re = JS('', r'/^\s*[+-]?((0x[a-f0-9]+)|(\d+)|([a-z0-9]+))\s*$/i');
+    var match = JS('JSExtendableArray|Null', '#.exec(#)', re, source);
+    int digitsIndex = 1;
+    int hexIndex = 2;
+    int decimalIndex = 3;
+    int nonDecimalHexIndex = 4;
+    if (match == null) {
+      // TODO(sra): It might be that the match failed due to unrecognized U+0085
+      // spaces.  We could replace them with U+0020 spaces and try matching
+      // again.
+      return null;
+    }
+    String decimalMatch = match[decimalIndex];
+    if (radix == null) {
+      if (decimalMatch != null) {
+        // Cannot fail because we know that the digits are all decimal.
+        return JS('int', r'parseInt(#, 10)', source);
+      }
+      if (match[hexIndex] != null) {
+        // Cannot fail because we know that the digits are all hex.
+        return JS('int', r'parseInt(#, 16)', source);
+      }
+      return null;
+    }
+
+    if (radix is! int) {
+      throw new ArgumentError.value(radix, 'radix', 'is not an integer');
+    }
+    if (radix < 2 || radix > 36) {
+      throw new RangeError.range(radix, 2, 36, 'radix');
+    }
+    if (radix == 10 && decimalMatch != null) {
+      // Cannot fail because we know that the digits are all decimal.
+      return JS('int', r'parseInt(#, 10)', source);
+    }
+    // If radix >= 10 and we have only decimal digits the string is safe.
+    // Otherwise we need to check the digits.
+    if (radix < 10 || decimalMatch == null) {
+      // We know that the characters must be ASCII as otherwise the
+      // regexp wouldn't have matched. Lowercasing by doing `| 0x20` is thus
+      // guaranteed to be a safe operation, since it preserves digits
+      // and lower-cases ASCII letters.
+      int maxCharCode;
+      if (radix <= 10) {
+        // Allow all digits less than the radix. For example 0, 1, 2 for
+        // radix 3.
+        // "0".codeUnitAt(0) + radix - 1;
+        maxCharCode = (0x30 - 1) + radix;
+      } else {
+        // Letters are located after the digits in ASCII. Therefore we
+        // only check for the character code. The regexp above made already
+        // sure that the string does not contain anything but digits or
+        // letters.
+        // "a".codeUnitAt(0) + (radix - 10) - 1;
+        maxCharCode = (0x61 - 10 - 1) + radix;
+      }
+      assert(match[digitsIndex] is String);
+      String digitsPart = JS('String', '#[#]', match, digitsIndex);
+      for (int i = 0; i < digitsPart.length; i++) {
+        int characterCode = digitsPart.codeUnitAt(i) | 0x20;
+        if (characterCode > maxCharCode) {
+          return null;
+        }
+      }
+    }
+    // The above matching and checks ensures the source has at least one digits
+    // and all digits are suitable for the radix, so parseInt cannot return NaN.
+    return JS('int', r'parseInt(#, #)', source, radix);
+  }
+
+  static double parseDouble(String source) {
+    checkString(source);
+    // Notice that JS parseFloat accepts garbage at the end of the string.
+    // Accept only:
+    // - [+/-]NaN
+    // - [+/-]Infinity
+    // - a Dart double literal
+    // We do allow leading or trailing whitespace.
+    if (!JS(
+        'bool',
+        r'/^\s*[+-]?(?:Infinity|NaN|'
+            r'(?:\.\d+|\d+(?:\.\d*)?)(?:[eE][+-]?\d+)?)\s*$/.test(#)',
+        source)) {
+      return null;
+    }
+    var result = JS('num', r'parseFloat(#)', source);
+    if (result.isNaN) {
+      var trimmed = source.trim();
+      if (trimmed == 'NaN' || trimmed == '+NaN' || trimmed == '-NaN') {
+        return result;
+      }
+      return null;
+    }
+    return result;
+  }
+
+  /// [: r"$".codeUnitAt(0) :]
+  static const int DOLLAR_CHAR_VALUE = 36;
+
+  /// Creates a string containing the complete type for the class [className]
+  /// with the given type arguments.
+  ///
+  /// In minified mode, uses the unminified names if available.
+  ///
+  /// The given [className] string generally contains the name of the JavaScript
+  /// constructor of the given class.
+  static String formatType(String className, List typeArguments) {
+    return unmangleAllIdentifiersIfPreservedAnyways(
+        '$className${joinArguments(typeArguments, 0)}');
+  }
+
+  /// Returns the type of [object] as a string (including type arguments).
+  /// Tries to return a sensible name for non-Dart objects.
+  ///
+  /// In minified mode, uses the unminified names if available, otherwise tags
+  /// them with 'minified:'.
+  @pragma('dart2js:noInline')
+  static String objectTypeName(Object object) {
+    if (JS_GET_FLAG('USE_NEW_RTI')) {
+      return _objectTypeNameNewRti(object);
+    }
+    String className = _objectClassName(object);
+    String arguments = joinArguments(getRuntimeTypeInfo(object), 0);
+    return '${className}${arguments}';
+  }
+
+  static String _objectClassName(Object object) {
+    var interceptor = getInterceptor(object);
+    // The interceptor is either an object (self-intercepting plain Dart class),
+    // the prototype of the constructor for an Interceptor class (like
+    // `JSString.prototype`, `JSNull.prototype`), or an Interceptor object
+    // instance (`const JSString()`, should use `JSString.prototype`).
+    //
+    // These all should have a `constructor` property with a `name` property.
+    String name;
+    var interceptorConstructor = JS('', '#.constructor', interceptor);
+    if (JS('bool', 'typeof # == "function"', interceptorConstructor)) {
+      var interceptorConstructorName = JS('', '#.name', interceptorConstructor);
+      if (interceptorConstructorName is String) {
+        name = interceptorConstructorName;
+      }
+    }
+
+    if (name == null ||
+        identical(interceptor, JS_INTERCEPTOR_CONSTANT(Interceptor)) ||
+        object is UnknownJavaScriptObject) {
+      // Try to do better.  If we do not find something better, leave the name
+      // as 'UnknownJavaScriptObject' or 'Interceptor' (or the minified name).
+      //
+      // When we get here via the UnknownJavaScriptObject test (for JavaScript
+      // objects from outside the program), the object's constructor has a
+      // better name that 'UnknownJavaScriptObject'.
+      //
+      // When we get here the Interceptor test (for Native classes that are
+      // declared in the Dart program but have been 'folded' into Interceptor),
+      // the native class's constructor name is better than the generic
+      // 'Interceptor' (an abstract class).
+
+      // Try the [constructorNameFallback]. This gets the constructor name for
+      // any browser (used by [getNativeInterceptor]).
+      String dispatchName = constructorNameFallback(object);
+      name ??= dispatchName;
+      if (dispatchName == 'Object') {
+        // Try to decompile the constructor by turning it into a string and get
+        // the name out of that. If the decompiled name is a string containing
+        // an identifier, we use that instead of the very generic 'Object'.
+        var objectConstructor = JS('', '#.constructor', object);
+        if (JS('bool', 'typeof # == "function"', objectConstructor)) {
+          var match = JS('var', r'#.match(/^\s*function\s*([\w$]*)\s*\(/)',
+              JS('var', r'String(#)', objectConstructor));
+          var decompiledName = match == null ? null : JS('var', r'#[1]', match);
+          if (decompiledName is String &&
+              JS('bool', r'/^\w+$/.test(#)', decompiledName)) {
+            name = decompiledName;
+          }
+        }
+      }
+      return JS('String', '#', name);
+    }
+
+    // Type inference does not understand that [name] is now always a non-null
+    // String. (There is some imprecision in the negation of the disjunction.)
+    name = JS('String', '#', name);
+
+    // TODO(kasperl): If the namer gave us a fresh global name, we may
+    // want to remove the numeric suffix that makes it unique too.
+    if (name.length > 1 && identical(name.codeUnitAt(0), DOLLAR_CHAR_VALUE)) {
+      name = name.substring(1);
+    }
+    return unminifyOrTag(name);
+  }
+
+  /// Returns the type of [object] as a string (including type arguments).
+  /// Tries to return a sensible name for non-Dart objects.
+  ///
+  /// In minified mode, uses the unminified names if available, otherwise tags
+  /// them with 'minified:'.
+  static String _objectTypeNameNewRti(Object object) {
+    var dartObjectConstructor = JS_BUILTIN(
+        'depends:none;effects:none;', JsBuiltin.dartObjectConstructor);
+    if (JS('bool', '# instanceof #', object, dartObjectConstructor)) {
+      return newRti.instanceTypeName(object);
+    }
+
+    var interceptor = getInterceptor(object);
+    if (identical(interceptor, JS_INTERCEPTOR_CONSTANT(Interceptor)) ||
+        object is UnknownJavaScriptObject) {
+      // Try to do better.  If we do not find something better, fallthrough to
+      // Dart-type based name that leave the name as 'UnknownJavaScriptObject'
+      // or 'Interceptor' (or the minified versions thereof).
+      //
+      // When we get here via the UnknownJavaScriptObject test (for JavaScript
+      // objects from outside the program), the object's constructor has a
+      // better name that 'UnknownJavaScriptObject'.
+      //
+      // When we get here the Interceptor test (for Native classes that are
+      // declared in the Dart program but have been 'folded' into Interceptor),
+      // the native class's constructor name is better than the generic
+      // 'Interceptor' (an abstract class).
+
+      // Try the [constructorNameFallback]. This gets the constructor name for
+      // any browser (used by [getNativeInterceptor]).
+      String dispatchName = constructorNameFallback(object);
+      if (_saneNativeClassName(dispatchName)) return dispatchName;
+      var constructor = JS('', '#.constructor', object);
+      if (JS('bool', 'typeof # == "function"', constructor)) {
+        var constructorName = JS('', '#.name', constructor);
+        if (constructorName is String &&
+            _saneNativeClassName(constructorName)) {
+          return constructorName;
+        }
+      }
+    }
+
+    return newRti.instanceTypeName(object);
+  }
+
+  static bool _saneNativeClassName(name) =>
+      name != null && name != 'Object' && name != '';
+
+  /// In minified mode, uses the unminified names if available.
+  static String objectToHumanReadableString(Object object) {
+    String name = objectTypeName(object);
+    return "Instance of '$name'";
+  }
+
+  static int dateNow() => JS('int', r'Date.now()');
+
+  static void initTicker() {
+    if (timerFrequency != null) return;
+    // Start with low-resolution. We overwrite the fields if we find better.
+    timerFrequency = 1000;
+    timerTicks = dateNow;
+    if (JS('bool', 'typeof window == "undefined"')) return;
+    var window = JS('var', 'window');
+    if (window == null) return;
+    var performance = JS('var', '#.performance', window);
+    if (performance == null) return;
+    if (JS('bool', 'typeof #.now != "function"', performance)) return;
+    timerFrequency = 1000000;
+    timerTicks = () => (1000 * JS('num', '#.now()', performance)).floor();
+  }
+
+  static int timerFrequency;
+  static Function timerTicks;
+
+  static String currentUri() {
+    requiresPreamble();
+    // In a browser return self.location.href.
+    if (JS('bool', '!!self.location')) {
+      return JS('String', 'self.location.href');
+    }
+
+    return null;
+  }
+
+  /// Version of `String.fromCharCode.apply` that chunks the conversion to avoid
+  /// stack overflows due to very large argument arrays.
+  ///
+  /// [array] is pre-validated as a JSArray of int values but is not typed as
+  /// <int> so it can be called with any JSArray.
+  static String _fromCharCodeApply(List array) {
+    const kMaxApply = 500;
+    int end = array.length;
+    if (end <= kMaxApply) {
+      return JS('String', r'String.fromCharCode.apply(null, #)', array);
+    }
+    String result = '';
+    for (int i = 0; i < end; i += kMaxApply) {
+      int chunkEnd = (i + kMaxApply < end) ? i + kMaxApply : end;
+      result = JS(
+          'String',
+          r'# + String.fromCharCode.apply(null, #.slice(#, #))',
+          result,
+          array,
+          i,
+          chunkEnd);
+    }
+    return result;
+  }
+
+  static String stringFromCodePoints(codePoints) {
+    List<int> a = <int>[];
+    for (var i in codePoints) {
+      if (i is! int) throw argumentErrorValue(i);
+      if (i <= 0xffff) {
+        a.add(i);
+      } else if (i <= 0x10ffff) {
+        a.add(0xd800 + ((((i - 0x10000) >> 10) & 0x3ff)));
+        a.add(0xdc00 + (i & 0x3ff));
+      } else {
+        throw argumentErrorValue(i);
+      }
+    }
+    return _fromCharCodeApply(a);
+  }
+
+  static String stringFromCharCodes(charCodes) {
+    for (var i in charCodes) {
+      if (i is! int) throw argumentErrorValue(i);
+      if (i < 0) throw argumentErrorValue(i);
+      if (i > 0xffff) return stringFromCodePoints(charCodes);
+    }
+    return _fromCharCodeApply(charCodes);
+  }
+
+  // [start] and [end] are validated.
+  static String stringFromNativeUint8List(
+      NativeUint8List charCodes, int start, int end) {
+    const kMaxApply = 500;
+    if (end <= kMaxApply && start == 0 && end == charCodes.length) {
+      return JS('String', r'String.fromCharCode.apply(null, #)', charCodes);
+    }
+    String result = '';
+    for (int i = start; i < end; i += kMaxApply) {
+      int chunkEnd = (i + kMaxApply < end) ? i + kMaxApply : end;
+      result = JS(
+          'String',
+          r'# + String.fromCharCode.apply(null, #.subarray(#, #))',
+          result,
+          charCodes,
+          i,
+          chunkEnd);
+    }
+    return result;
+  }
+
+  static String stringFromCharCode(charCode) {
+    if (0 <= charCode) {
+      if (charCode <= 0xffff) {
+        return JS('returns:String;effects:none;depends:none',
+            'String.fromCharCode(#)', charCode);
+      }
+      if (charCode <= 0x10ffff) {
+        var bits = charCode - 0x10000;
+        var low = 0xDC00 | (bits & 0x3ff);
+        var high = 0xD800 | (bits >> 10);
+        return JS('returns:String;effects:none;depends:none',
+            'String.fromCharCode(#, #)', high, low);
+      }
+    }
+    throw new RangeError.range(charCode, 0, 0x10ffff);
+  }
+
+  static String stringConcatUnchecked(String string1, String string2) {
+    return JS_STRING_CONCAT(string1, string2);
+  }
+
+  static String flattenString(String str) {
+    return JS('returns:String;depends:none;effects:none;throws:never;gvn:true',
+        '#.charCodeAt(0) == 0 ? # : #', str, str, str);
+  }
+
+  static String getTimeZoneName(DateTime receiver) {
+    // Firefox and Chrome emit the timezone in parenthesis.
+    // Example: "Wed May 16 2012 21:13:00 GMT+0200 (CEST)".
+    // We extract this name using a regexp.
+    var d = lazyAsJsDate(receiver);
+    List match = JS('JSArray|Null', r'/\((.*)\)/.exec(#.toString())', d);
+    if (match != null) return match[1];
+
+    // Internet Explorer 10+ emits the zone name without parenthesis:
+    // Example: Thu Oct 31 14:07:44 PDT 2013
+    match = JS(
+        'JSArray|Null',
+        // Thu followed by a space.
+        r'/^[A-Z,a-z]{3}\s'
+            // Oct 31 followed by space.
+            r'[A-Z,a-z]{3}\s\d+\s'
+            // Time followed by a space.
+            r'\d{2}:\d{2}:\d{2}\s'
+            // The time zone name followed by a space.
+            r'([A-Z]{3,5})\s'
+            // The year.
+            r'\d{4}$/'
+            '.exec(#.toString())',
+        d);
+    if (match != null) return match[1];
+
+    // IE 9 and Opera don't provide the zone name. We fall back to emitting the
+    // UTC/GMT offset.
+    // Example (IE9): Wed Nov 20 09:51:00 UTC+0100 2013
+    //       (Opera): Wed Nov 20 2013 11:03:38 GMT+0100
+    match = JS('JSArray|Null', r'/(?:GMT|UTC)[+-]\d{4}/.exec(#.toString())', d);
+    if (match != null) return match[0];
+    return '';
+  }
+
+  static int getTimeZoneOffsetInMinutes(DateTime receiver) {
+    // Note that JS and Dart disagree on the sign of the offset.
+    // Subtract to avoid -0.0
+    return 0 - JS('int', r'#.getTimezoneOffset()', lazyAsJsDate(receiver));
+  }
+
+  static int valueFromDecomposedDate(
+      years, month, day, hours, minutes, seconds, milliseconds, isUtc) {
+    final int MAX_MILLISECONDS_SINCE_EPOCH = 8640000000000000;
+    checkInt(years);
+    checkInt(month);
+    checkInt(day);
+    checkInt(hours);
+    checkInt(minutes);
+    checkInt(seconds);
+    checkInt(milliseconds);
+    checkBool(isUtc);
+    var jsMonth = month - 1;
+    // The JavaScript Date constructor 'corrects' year NN to 19NN. Sidestep that
+    // correction by adjusting years out of that range and compensating with an
+    // adjustment of months. This hack should not be sensitive to leap years but
+    // use 400 just in case.
+    if (0 <= years && years < 100) {
+      years += 400;
+      jsMonth -= 400 * 12;
+    }
+    var value;
+    if (isUtc) {
+      value = JS('num', r'Date.UTC(#, #, #, #, #, #, #)', years, jsMonth, day,
+          hours, minutes, seconds, milliseconds);
+    } else {
+      value = JS('num', r'new Date(#, #, #, #, #, #, #).valueOf()', years,
+          jsMonth, day, hours, minutes, seconds, milliseconds);
+    }
+    if (value.isNaN ||
+        value < -MAX_MILLISECONDS_SINCE_EPOCH ||
+        value > MAX_MILLISECONDS_SINCE_EPOCH) {
+      return null;
+    }
+    return JS('int', '#', value);
+  }
+
+  // Lazily keep a JS Date stored in the JS object.
+  static lazyAsJsDate(DateTime receiver) {
+    if (JS('bool', r'#.date === (void 0)', receiver)) {
+      JS('void', r'#.date = new Date(#)', receiver,
+          receiver.millisecondsSinceEpoch);
+    }
+    return JS('var', r'#.date', receiver);
+  }
+
+  // The getters for date and time parts below add a positive integer to ensure
+  // that the result is really an integer, because the JavaScript implementation
+  // may return -0.0 instead of 0.
+  //
+  // They are marked as @pragma('dart2js:noThrows') because `receiver` comes from a receiver of
+  // a method on DateTime (i.e. is not `null`).
+
+  // TODO(sra): These methods are GVN-able. dart2js should implement an
+  // annotation for that.
+
+  // TODO(sra): These methods often occur in groups (e.g. day, month and
+  // year). Is it possible to factor them so that the `Date` is visible and can
+  // be GVN-ed without a lot of code bloat?
+
+  @pragma('dart2js:noSideEffects')
+  @pragma('dart2js:noThrows')
+  @pragma('dart2js:noInline')
+  static getYear(DateTime receiver) {
+    return (receiver.isUtc)
+        ? JS('int', r'(#.getUTCFullYear() + 0)', lazyAsJsDate(receiver))
+        : JS('int', r'(#.getFullYear() + 0)', lazyAsJsDate(receiver));
+  }
+
+  @pragma('dart2js:noSideEffects')
+  @pragma('dart2js:noThrows')
+  @pragma('dart2js:noInline')
+  static getMonth(DateTime receiver) {
+    return (receiver.isUtc)
+        ? JS('JSUInt31', r'#.getUTCMonth() + 1', lazyAsJsDate(receiver))
+        : JS('JSUInt31', r'#.getMonth() + 1', lazyAsJsDate(receiver));
+  }
+
+  @pragma('dart2js:noSideEffects')
+  @pragma('dart2js:noThrows')
+  @pragma('dart2js:noInline')
+  static getDay(DateTime receiver) {
+    return (receiver.isUtc)
+        ? JS('JSUInt31', r'(#.getUTCDate() + 0)', lazyAsJsDate(receiver))
+        : JS('JSUInt31', r'(#.getDate() + 0)', lazyAsJsDate(receiver));
+  }
+
+  @pragma('dart2js:noSideEffects')
+  @pragma('dart2js:noThrows')
+  @pragma('dart2js:noInline')
+  static getHours(DateTime receiver) {
+    return (receiver.isUtc)
+        ? JS('JSUInt31', r'(#.getUTCHours() + 0)', lazyAsJsDate(receiver))
+        : JS('JSUInt31', r'(#.getHours() + 0)', lazyAsJsDate(receiver));
+  }
+
+  @pragma('dart2js:noSideEffects')
+  @pragma('dart2js:noThrows')
+  @pragma('dart2js:noInline')
+  static getMinutes(DateTime receiver) {
+    return (receiver.isUtc)
+        ? JS('JSUInt31', r'(#.getUTCMinutes() + 0)', lazyAsJsDate(receiver))
+        : JS('JSUInt31', r'(#.getMinutes() + 0)', lazyAsJsDate(receiver));
+  }
+
+  @pragma('dart2js:noSideEffects')
+  @pragma('dart2js:noThrows')
+  @pragma('dart2js:noInline')
+  static getSeconds(DateTime receiver) {
+    return (receiver.isUtc)
+        ? JS('JSUInt31', r'(#.getUTCSeconds() + 0)', lazyAsJsDate(receiver))
+        : JS('JSUInt31', r'(#.getSeconds() + 0)', lazyAsJsDate(receiver));
+  }
+
+  @pragma('dart2js:noSideEffects')
+  @pragma('dart2js:noThrows')
+  @pragma('dart2js:noInline')
+  static getMilliseconds(DateTime receiver) {
+    return (receiver.isUtc)
+        ? JS(
+            'JSUInt31', r'(#.getUTCMilliseconds() + 0)', lazyAsJsDate(receiver))
+        : JS('JSUInt31', r'(#.getMilliseconds() + 0)', lazyAsJsDate(receiver));
+  }
+
+  @pragma('dart2js:noSideEffects')
+  @pragma('dart2js:noThrows')
+  @pragma('dart2js:noInline')
+  static getWeekday(DateTime receiver) {
+    int weekday = (receiver.isUtc)
+        ? JS('int', r'#.getUTCDay() + 0', lazyAsJsDate(receiver))
+        : JS('int', r'#.getDay() + 0', lazyAsJsDate(receiver));
+    // Adjust by one because JS weeks start on Sunday.
+    return (weekday + 6) % 7 + 1;
+  }
+
+  static valueFromDateString(str) {
+    if (str is! String) throw argumentErrorValue(str);
+    var value = JS('num', r'Date.parse(#)', str);
+    if (value.isNaN) throw argumentErrorValue(str);
+    return value;
+  }
+
+  static getProperty(object, key) {
+    if (object == null || object is bool || object is num || object is String) {
+      throw argumentErrorValue(object);
+    }
+    return JS('var', '#[#]', object, key);
+  }
+
+  static void setProperty(object, key, value) {
+    if (object == null || object is bool || object is num || object is String) {
+      throw argumentErrorValue(object);
+    }
+    JS('void', '#[#] = #', object, key, value);
+  }
+
+  static functionNoSuchMethod(
+      function, List positionalArguments, Map<String, dynamic> namedArguments) {
+    int argumentCount = 0;
+    List arguments = [];
+    List namedArgumentList = [];
+
+    if (positionalArguments != null) {
+      argumentCount += positionalArguments.length;
+      arguments.addAll(positionalArguments);
+    }
+
+    String names = '';
+    if (namedArguments != null && !namedArguments.isEmpty) {
+      namedArguments.forEach((String name, argument) {
+        names = '$names\$$name';
+        namedArgumentList.add(name);
+        arguments.add(argument);
+        argumentCount++;
+      });
+    }
+
+    String selectorName =
+        '${JS_GET_NAME(JsGetName.CALL_PREFIX)}\$$argumentCount$names';
+
+    return function.noSuchMethod(createUnmangledInvocationMirror(
+        #call,
+        selectorName,
+        JSInvocationMirror.METHOD,
+        arguments,
+        namedArgumentList,
+        0));
+  }
+
+  /// Implements [Function.apply] for the lazy and startup emitters.
+  ///
+  /// There are two types of closures that can reach this function:
+  ///
+  /// 1. tear-offs (including tear-offs of static functions).
+  /// 2. anonymous closures.
+  ///
+  /// They are treated differently (although there are lots of similarities).
+  /// Both have in common that they have
+  /// a [JsGetName.CALL_CATCH_ALL] and
+  /// a [JsGetName.REQUIRED_PARAMETER_PROPERTY] property.
+  ///
+  /// If the closure supports optional parameters, then they also feature
+  /// a [JsGetName.DEFAULT_VALUES_PROPERTY] property.
+  ///
+  /// The catch-all property is a method that takes all arguments (including
+  /// all optional positional or named arguments). If the function accepts
+  /// optional arguments, then the default-values property stores (potentially
+  /// wrapped in a function) the default values for the optional arguments. If
+  /// the function accepts optional positional arguments, then the value is a
+  /// JavaScript array with the default values. Otherwise, when the function
+  /// accepts optional named arguments, it is a JavaScript object.
+  ///
+  /// The default-values property may either contain the value directly, or
+  /// it can be a function that returns the default-values when invoked.
+  ///
+  /// If the function is an anonymous closure, then the catch-all property
+  /// only contains a string pointing to the property that should be used
+  /// instead. For example, if the catch-all property contains the string
+  /// "call$4", then the object's "call$4" property should be used as if it was
+  /// the value of the catch-all property.
+  static applyFunction(Function function, List positionalArguments,
+      Map<String, dynamic> namedArguments) {
+    // Fast shortcut for the common case.
+    if (JS('bool', '# instanceof Array', positionalArguments) &&
+        (namedArguments == null || namedArguments.isEmpty)) {
+      // Let the compiler know that we did a type-test.
+      List arguments = (JS('JSArray', '#', positionalArguments));
+      int argumentCount = arguments.length;
+      if (argumentCount == 0) {
+        String selectorName = JS_GET_NAME(JsGetName.CALL_PREFIX0);
+        if (JS('bool', '!!#[#]', function, selectorName)) {
+          return JS('', '#[#]()', function, selectorName);
+        }
+      } else if (argumentCount == 1) {
+        String selectorName = JS_GET_NAME(JsGetName.CALL_PREFIX1);
+        if (JS('bool', '!!#[#]', function, selectorName)) {
+          return JS('', '#[#](#[0])', function, selectorName, arguments);
+        }
+      } else if (argumentCount == 2) {
+        String selectorName = JS_GET_NAME(JsGetName.CALL_PREFIX2);
+        if (JS('bool', '!!#[#]', function, selectorName)) {
+          return JS('', '#[#](#[0],#[1])', function, selectorName, arguments,
+              arguments);
+        }
+      } else if (argumentCount == 3) {
+        String selectorName = JS_GET_NAME(JsGetName.CALL_PREFIX3);
+        if (JS('bool', '!!#[#]', function, selectorName)) {
+          return JS('', '#[#](#[0],#[1],#[2])', function, selectorName,
+              arguments, arguments, arguments);
+        }
+      } else if (argumentCount == 4) {
+        String selectorName = JS_GET_NAME(JsGetName.CALL_PREFIX4);
+        if (JS('bool', '!!#[#]', function, selectorName)) {
+          return JS('', '#[#](#[0],#[1],#[2],#[3])', function, selectorName,
+              arguments, arguments, arguments, arguments);
+        }
+      } else if (argumentCount == 5) {
+        String selectorName = JS_GET_NAME(JsGetName.CALL_PREFIX5);
+        if (JS('bool', '!!#[#]', function, selectorName)) {
+          return JS(
+              '',
+              '#[#](#[0],#[1],#[2],#[3],#[4])',
+              function,
+              selectorName,
+              arguments,
+              arguments,
+              arguments,
+              arguments,
+              arguments);
+        }
+      }
+      String selectorName =
+          '${JS_GET_NAME(JsGetName.CALL_PREFIX)}\$$argumentCount';
+      var jsStub = JS('var', r'#[#]', function, selectorName);
+      if (jsStub != null) {
+        return JS('var', '#.apply(#, #)', jsStub, function, arguments);
+      }
+    }
+
+    return _genericApplyFunction2(
+        function, positionalArguments, namedArguments);
+  }
+
+  static _genericApplyFunction2(Function function, List positionalArguments,
+      Map<String, dynamic> namedArguments) {
+    List arguments;
+    if (positionalArguments != null) {
+      if (JS('bool', '# instanceof Array', positionalArguments)) {
+        arguments = JS('JSArray', '#', positionalArguments);
+      } else {
+        arguments = new List.from(positionalArguments);
+      }
+    } else {
+      arguments = [];
+    }
+
+    int argumentCount = arguments.length;
+
+    int requiredParameterCount = JS('int', r'#[#]', function,
+        JS_GET_NAME(JsGetName.REQUIRED_PARAMETER_PROPERTY));
+
+    if (argumentCount < requiredParameterCount) {
+      return functionNoSuchMethod(function, arguments, namedArguments);
+    }
+
+    var defaultValuesClosure = JS('var', r'#[#]', function,
+        JS_GET_NAME(JsGetName.DEFAULT_VALUES_PROPERTY));
+
+    bool acceptsOptionalArguments = defaultValuesClosure != null;
+
+    // Default values are stored inside a JavaScript closure to avoid
+    // accessing them too early.
+    var defaultValues =
+        acceptsOptionalArguments ? JS('', '#()', defaultValuesClosure) : null;
+
+    var interceptor = getInterceptor(function);
+    var jsFunction =
+        JS('', '#[#]', interceptor, JS_GET_NAME(JsGetName.CALL_CATCH_ALL));
+    if (jsFunction is String) {
+      // Anonymous closures redirect to the catch-all property instead of
+      // storing the catch-all method directly in the catch-all property.
+      jsFunction = JS('', '#[#]', interceptor, jsFunction);
+    }
+
+    if (!acceptsOptionalArguments) {
+      if (namedArguments != null && namedArguments.isNotEmpty) {
+        // Tried to invoke a function that takes a fixed number of arguments
+        // with named (optional) arguments.
+        return functionNoSuchMethod(function, arguments, namedArguments);
+      }
+      if (argumentCount == requiredParameterCount) {
+        return JS('var', r'#.apply(#, #)', jsFunction, function, arguments);
+      }
+      return functionNoSuchMethod(function, arguments, namedArguments);
+    }
+
+    bool acceptsPositionalArguments =
+        JS('bool', '# instanceof Array', defaultValues);
+
+    if (acceptsPositionalArguments) {
+      if (namedArguments != null && namedArguments.isNotEmpty) {
+        // Tried to invoke a function that takes optional positional arguments
+        // with named arguments.
+        return functionNoSuchMethod(function, arguments, namedArguments);
+      }
+
+      int defaultsLength = JS('int', '#.length', defaultValues);
+      int maxArguments = requiredParameterCount + defaultsLength;
+      if (argumentCount > maxArguments) {
+        // The function expects fewer arguments.
+        return functionNoSuchMethod(function, arguments, null);
+      }
+      List missingDefaults = JS('JSArray', '#.slice(#)', defaultValues,
+          argumentCount - requiredParameterCount);
+      arguments.addAll(missingDefaults);
+      return JS('var', '#.apply(#, #)', jsFunction, function, arguments);
+    } else {
+      // Handle named arguments.
+
+      if (argumentCount > requiredParameterCount) {
+        // Tried to invoke a function that takes named parameters with
+        // too many positional arguments.
+        return functionNoSuchMethod(function, arguments, namedArguments);
+      }
+
+      List keys = JS('JSArray', r'Object.keys(#)', defaultValues);
+      if (namedArguments == null) {
+        for (String key in keys) {
+          arguments.add(JS('var', '#[#]', defaultValues, key));
+        }
+      } else {
+        int used = 0;
+        for (String key in keys) {
+          if (namedArguments.containsKey(key)) {
+            used++;
+            arguments.add(namedArguments[key]);
+          } else {
+            arguments.add(JS('var', r'#[#]', defaultValues, key));
+          }
+        }
+        if (used != namedArguments.length) {
+          return functionNoSuchMethod(function, arguments, namedArguments);
+        }
+      }
+      return JS('var', r'#.apply(#, #)', jsFunction, function, arguments);
+    }
+  }
+
+  static StackTrace extractStackTrace(Error error) {
+    return getTraceFromException(JS('', r'#.$thrownJsError', error));
+  }
+}
+
+/// Helper class for allocating and using JS object literals as caches.
+class JsCache {
+  /// Returns a JavaScript object suitable for use as a cache.
+  static allocate() {
+    var result = JS('=Object', 'Object.create(null)');
+    // Deleting a property makes V8 assume that it shouldn't create a hidden
+    // class for [result] and map transitions. Although these map transitions
+    // pay off if there are many cache hits for the same keys, it becomes
+    // really slow when there aren't many repeated hits.
+    JS('void', '#.x=0', result);
+    JS('void', 'delete #.x', result);
+    return result;
+  }
+
+  static fetch(cache, String key) {
+    return JS('', '#[#]', cache, key);
+  }
+
+  static void update(cache, String key, value) {
+    JS('void', '#[#] = #', cache, key, value);
+  }
+}
+
+/// Called by generated code to throw an illegal-argument exception,
+/// for example, if a non-integer index is given to an optimized
+/// indexed access.
+@pragma('dart2js:noInline')
+iae(argument) {
+  throw argumentErrorValue(argument);
+}
+
+/// Called by generated code to throw an index-out-of-range exception, for
+/// example, if a bounds check fails in an optimized indexed access.  This may
+/// also be called when the index is not an integer, in which case it throws an
+/// illegal-argument exception instead, like [iae], or when the receiver is
+/// null.
+@pragma('dart2js:noInline')
+ioore(receiver, index) {
+  if (receiver == null) receiver.length; // Force a NoSuchMethodError.
+  throw diagnoseIndexError(receiver, index);
+}
+
+/// Diagnoses an indexing error. Returns the ArgumentError or RangeError that
+/// describes the problem.
+@pragma('dart2js:noInline')
+Error diagnoseIndexError(indexable, index) {
+  if (index is! int) return new ArgumentError.value(index, 'index');
+  int length = indexable.length;
+  // The following returns the same error that would be thrown by calling
+  // [RangeError.checkValidIndex] with no optional parameters provided.
+  if (index < 0 || index >= length) {
+    return new RangeError.index(index, indexable, 'index', null, length);
+  }
+  // The above should always match, but if it does not, use the following.
+  return new RangeError.value(index, 'index');
+}
+
+/// Diagnoses a range error. Returns the ArgumentError or RangeError that
+/// describes the problem.
+@pragma('dart2js:noInline')
+Error diagnoseRangeError(start, end, length) {
+  if (start is! int) {
+    return new ArgumentError.value(start, 'start');
+  }
+  if (start < 0 || start > length) {
+    return new RangeError.range(start, 0, length, 'start');
+  }
+  if (end != null) {
+    if (end is! int) {
+      return new ArgumentError.value(end, 'end');
+    }
+    if (end < start || end > length) {
+      return new RangeError.range(end, start, length, 'end');
+    }
+  }
+  // The above should always match, but if it does not, use the following.
+  return new ArgumentError.value(end, 'end');
+}
+
+stringLastIndexOfUnchecked(receiver, element, start) =>
+    JS('int', r'#.lastIndexOf(#, #)', receiver, element, start);
+
+/// 'factory' for constructing ArgumentError.value to keep the call sites small.
+@pragma('dart2js:noInline')
+ArgumentError argumentErrorValue(object) {
+  return new ArgumentError.value(object);
+}
+
+checkNull(object) {
+  if (object == null) throw argumentErrorValue(object);
+  return object;
+}
+
+@pragma('dart2js:noInline')
+num checkNum(value) {
+  if (value is! num) throw argumentErrorValue(value);
+  return value;
+}
+
+int checkInt(value) {
+  if (value is! int) throw argumentErrorValue(value);
+  return value;
+}
+
+bool checkBool(value) {
+  if (value is! bool) throw argumentErrorValue(value);
+  return value;
+}
+
+String checkString(value) {
+  if (value is! String) throw argumentErrorValue(value);
+  return value;
+}
+
+/// Wrap the given Dart object and record a stack trace.
+///
+/// The code in [unwrapException] deals with getting the original Dart
+/// object out of the wrapper again.
+@pragma('dart2js:noInline')
+wrapException(ex) {
+  if (ex == null) ex = new NullThrownError();
+  var wrapper = JS('', 'new Error()');
+  // [unwrapException] looks for the property 'dartException'.
+  JS('void', '#.dartException = #', wrapper, ex);
+
+  if (JS('bool', '"defineProperty" in Object')) {
+    // Define a JavaScript getter for 'message'. This is to work around V8 bug
+    // (https://code.google.com/p/v8/issues/detail?id=2519).  The default
+    // toString on Error returns the value of 'message' if 'name' is
+    // empty. Setting toString directly doesn't work, see the bug.
+    JS('void', 'Object.defineProperty(#, "message", { get: # })', wrapper,
+        DART_CLOSURE_TO_JS(toStringWrapper));
+    JS('void', '#.name = ""', wrapper);
+  } else {
+    // In the unlikely event the browser doesn't support Object.defineProperty,
+    // hope that it just calls toString.
+    JS('void', '#.toString = #', wrapper, DART_CLOSURE_TO_JS(toStringWrapper));
+  }
+
+  return wrapper;
+}
+
+/// Do not call directly.
+toStringWrapper() {
+  // This method gets installed as toString on a JavaScript object. Due to the
+  // weird scope rules of JavaScript, JS 'this' will refer to that object.
+  return JS('', r'this.dartException').toString();
+}
+
+/// This wraps the exception and does the throw.  It is possible to call this in
+/// a JS expression context, where the throw statement is not allowed.  Helpers
+/// are never inlined, so we don't risk inlining the throw statement into an
+/// expression context.
+throwExpression(ex) {
+  JS('void', 'throw #', wrapException(ex));
+}
+
+throwRuntimeError(message) {
+  throw new RuntimeError(message);
+}
+
+throwUnsupportedError(message) {
+  throw new UnsupportedError(message);
+}
+
+throwAbstractClassInstantiationError(className) {
+  throw new AbstractClassInstantiationError(className);
+}
+
+// This is used in open coded for-in loops on arrays.
+//
+//     checkConcurrentModificationError(a.length == startLength, a)
+//
+// is replaced in codegen by:
+//
+//     a.length == startLength || throwConcurrentModificationError(a)
+//
+// TODO(sra): We would like to annotate this as @pragma('dart2js:noSideEffects') so that loops
+// with no other effects can recognize that the array length does not
+// change. However, in the usual case where the loop does have other effects,
+// that causes the length in the loop condition to be phi(startLength,a.length),
+// which causes confusion in range analysis and the insertion of a bounds check.
+@pragma('dart2js:noInline')
+checkConcurrentModificationError(sameLength, collection) {
+  if (true != sameLength) {
+    throwConcurrentModificationError(collection);
+  }
+}
+
+@pragma('dart2js:noInline')
+throwConcurrentModificationError(collection) {
+  throw new ConcurrentModificationError(collection);
+}
+
+/// Helper class for building patterns recognizing native type errors.
+class TypeErrorDecoder {
+  // Field names are private to help tree-shaking.
+
+  /// A regular expression which matches is matched against an error message.
+  final String _pattern;
+
+  /// The group index of "arguments" in [_pattern], or -1 if _pattern has no
+  /// match for "arguments".
+  final int _arguments;
+
+  /// The group index of "argumentsExpr" in [_pattern], or -1 if _pattern has
+  /// no match for "argumentsExpr".
+  final int _argumentsExpr;
+
+  /// The group index of "expr" in [_pattern], or -1 if _pattern has no match
+  /// for "expr".
+  final int _expr;
+
+  /// The group index of "method" in [_pattern], or -1 if _pattern has no match
+  /// for "method".
+  final int _method;
+
+  /// The group index of "receiver" in [_pattern], or -1 if _pattern has no
+  /// match for "receiver".
+  final int _receiver;
+
+  /// Pattern used to recognize a NoSuchMethodError error (and
+  /// possibly extract the method name).
+  static final TypeErrorDecoder noSuchMethodPattern =
+      extractPattern(provokeCallErrorOn(buildJavaScriptObject()));
+
+  /// Pattern used to recognize an "object not a closure" error (and
+  /// possibly extract the method name).
+  static final TypeErrorDecoder notClosurePattern =
+      extractPattern(provokeCallErrorOn(buildJavaScriptObjectWithNonClosure()));
+
+  /// Pattern used to recognize a NoSuchMethodError on JavaScript null
+  /// call.
+  static final TypeErrorDecoder nullCallPattern =
+      extractPattern(provokeCallErrorOn(JS('', 'null')));
+
+  /// Pattern used to recognize a NoSuchMethodError on JavaScript literal null
+  /// call.
+  static final TypeErrorDecoder nullLiteralCallPattern =
+      extractPattern(provokeCallErrorOnNull());
+
+  /// Pattern used to recognize a NoSuchMethodError on JavaScript
+  /// undefined call.
+  static final TypeErrorDecoder undefinedCallPattern =
+      extractPattern(provokeCallErrorOn(JS('', 'void 0')));
+
+  /// Pattern used to recognize a NoSuchMethodError on JavaScript literal
+  /// undefined call.
+  static final TypeErrorDecoder undefinedLiteralCallPattern =
+      extractPattern(provokeCallErrorOnUndefined());
+
+  /// Pattern used to recognize a NoSuchMethodError on JavaScript null
+  /// property access.
+  static final TypeErrorDecoder nullPropertyPattern =
+      extractPattern(provokePropertyErrorOn(JS('', 'null')));
+
+  /// Pattern used to recognize a NoSuchMethodError on JavaScript literal null
+  /// property access.
+  static final TypeErrorDecoder nullLiteralPropertyPattern =
+      extractPattern(provokePropertyErrorOnNull());
+
+  /// Pattern used to recognize a NoSuchMethodError on JavaScript
+  /// undefined property access.
+  static final TypeErrorDecoder undefinedPropertyPattern =
+      extractPattern(provokePropertyErrorOn(JS('', 'void 0')));
+
+  /// Pattern used to recognize a NoSuchMethodError on JavaScript literal
+  /// undefined property access.
+  static final TypeErrorDecoder undefinedLiteralPropertyPattern =
+      extractPattern(provokePropertyErrorOnUndefined());
+
+  TypeErrorDecoder(this._arguments, this._argumentsExpr, this._expr,
+      this._method, this._receiver, this._pattern);
+
+  /// Returns a JavaScript object literal (map) with at most the
+  /// following keys:
+  ///
+  /// * arguments: The arguments as formatted by the JavaScript
+  ///   engine. No browsers are known to provide this information.
+  ///
+  /// * argumentsExpr: The syntax of the arguments (JavaScript source
+  ///   code). No browsers are known to provide this information.
+  ///
+  /// * expr: The syntax of the receiver expression (JavaScript source
+  ///   code). Firefox provides this information, for example: "$expr$.$method$
+  ///   is not a function".
+  ///
+  /// * method: The name of the called method (mangled name). At least Firefox
+  ///   and Chrome/V8 provides this information, for example, "Object [object
+  ///   Object] has no method '$method$'".
+  ///
+  /// * receiver: The string representation of the receiver. Chrome/V8
+  ///   used to provide this information (by calling user-defined
+  ///   JavaScript toString on receiver), but it has degenerated into
+  ///   "[object Object]" in recent versions.
+  matchTypeError(message) {
+    var match = JS(
+        'JSExtendableArray|Null', 'new RegExp(#).exec(#)', _pattern, message);
+    if (match == null) return null;
+    var result = JS('', 'Object.create(null)');
+    if (_arguments != -1) {
+      JS('', '#.arguments = #[# + 1]', result, match, _arguments);
+    }
+    if (_argumentsExpr != -1) {
+      JS('', '#.argumentsExpr = #[# + 1]', result, match, _argumentsExpr);
+    }
+    if (_expr != -1) {
+      JS('', '#.expr = #[# + 1]', result, match, _expr);
+    }
+    if (_method != -1) {
+      JS('', '#.method = #[# + 1]', result, match, _method);
+    }
+    if (_receiver != -1) {
+      JS('', '#.receiver = #[# + 1]', result, match, _receiver);
+    }
+
+    return result;
+  }
+
+  /// Builds a JavaScript Object with a toString method saying
+  /// r"$receiver$".
+  static buildJavaScriptObject() {
+    return JS('', r'{ toString: function() { return "$receiver$"; } }');
+  }
+
+  /// Builds a JavaScript Object with a toString method saying
+  /// r"$receiver$". The property "$method" is defined, but is not a function.
+  static buildJavaScriptObjectWithNonClosure() {
+    return JS(
+        '',
+        r'{ $method$: null, '
+            r'toString: function() { return "$receiver$"; } }');
+  }
+
+  /// Extract a pattern from a JavaScript TypeError message.
+  ///
+  /// The patterns are extracted by forcing TypeErrors on known
+  /// objects thus forcing known strings into the error message. The
+  /// known strings are then replaced with wildcards which in theory
+  /// makes it possible to recognize the desired information even if
+  /// the error messages are reworded or translated.
+  static extractPattern(String message) {
+    // Some JavaScript implementations (V8 at least) include a
+    // representation of the receiver in the error message, however,
+    // this representation is not always [: receiver.toString() :],
+    // sometimes it is [: Object.prototype.toString(receiver) :], and
+    // sometimes it is an implementation specific method (but that
+    // doesn't seem to happen for object literals). So sometimes we
+    // get the text "[object Object]". The shortest way to get that
+    // string is using "String({})".
+    // See: http://code.google.com/p/v8/issues/detail?id=2519.
+    message = JS('String', r"#.replace(String({}), '$receiver$')", message);
+
+    // Since we want to create a new regular expression from an unknown string,
+    // we must escape all regular expression syntax.
+    message = quoteStringForRegExp(message);
+
+    // Look for the special pattern \$camelCase\$ (all the $ symbols
+    // have been escaped already), as we will soon be inserting
+    // regular expression syntax that we want interpreted by RegExp.
+    List<String> match =
+        JS('JSExtendableArray|Null', r'#.match(/\\\$[a-zA-Z]+\\\$/g)', message);
+    if (match == null) match = [];
+
+    // Find the positions within the substring matches of the error message
+    // components.  This will help us extract information later, such as the
+    // method name.
+    int arguments = JS('int', '#.indexOf(#)', match, r'\$arguments\$');
+    int argumentsExpr = JS('int', '#.indexOf(#)', match, r'\$argumentsExpr\$');
+    int expr = JS('int', '#.indexOf(#)', match, r'\$expr\$');
+    int method = JS('int', '#.indexOf(#)', match, r'\$method\$');
+    int receiver = JS('int', '#.indexOf(#)', match, r'\$receiver\$');
+
+    // Replace the patterns with a regular expression wildcard.
+    // Note: in a perfect world, one would use "(.*)", but not in
+    // JavaScript, "." does not match newlines.
+    String pattern = JS(
+        'String',
+        r"#.replace(new RegExp('\\\\\\$arguments\\\\\\$', 'g'), "
+            r"'((?:x|[^x])*)')"
+            r".replace(new RegExp('\\\\\\$argumentsExpr\\\\\\$', 'g'),  "
+            r"'((?:x|[^x])*)')"
+            r".replace(new RegExp('\\\\\\$expr\\\\\\$', 'g'),  '((?:x|[^x])*)')"
+            r".replace(new RegExp('\\\\\\$method\\\\\\$', 'g'),  '((?:x|[^x])*)')"
+            r".replace(new RegExp('\\\\\\$receiver\\\\\\$', 'g'),  "
+            r"'((?:x|[^x])*)')",
+        message);
+
+    return new TypeErrorDecoder(
+        arguments, argumentsExpr, expr, method, receiver, pattern);
+  }
+
+  /// Provokes a TypeError and returns its message.
+  ///
+  /// The error is provoked so all known variable content can be recognized and
+  /// a pattern can be inferred.
+  static String provokeCallErrorOn(expression) {
+    // This function is carefully created to maximize the possibility
+    // of decoding the TypeError message and turning it into a general
+    // pattern.
+    //
+    // The idea is to inject something known into something unknown.  The
+    // unknown entity is the error message that the browser provides with a
+    // TypeError.  It is a human readable message, possibly localized in a
+    // language no dart2js engineer understand.  We assume that $name$ would
+    // never naturally occur in a human readable error message, yet it is easy
+    // to decode.
+    //
+    // For example, evaluate this in V8 version 3.13.7.6:
+    //
+    // var $expr$ = null; $expr$.$method$()
+    //
+    // The VM throws an instance of TypeError whose message property contains
+    // "Cannot call method '$method$' of null".  We can then reasonably assume
+    // that if the string contains $method$, that's where the method name will
+    // be in general.  Call this automatically reverse engineering the error
+    // format string in V8.
+    //
+    // So the error message from V8 is turned into this regular expression:
+    //
+    // "Cannot call method '(.*)' of null"
+    //
+    // Similarly, if we evaluate:
+    //
+    // var $expr$ = {toString: function() { return '$receiver$'; }};
+    // $expr$.$method$()
+    //
+    // We get this message: "Object $receiver$ has no method '$method$'"
+    //
+    // Which is turned into this regular expression:
+    //
+    // "Object (.*) has no method '(.*)'"
+    //
+    // Firefox/jsshell is slightly different, it tries to include the source
+    // code that caused the exception, so we get this message: "$expr$.$method$
+    // is not a function" which is turned into this regular expression:
+    //
+    // "(.*)\\.(.*) is not a function"
+
+    var function = JS('', r"""function($expr$) {
+  var $argumentsExpr$ = '$arguments$';
+  try {
+    $expr$.$method$($argumentsExpr$);
+  } catch (e) {
+    return e.message;
+  }
+}""");
+    return JS('String', '(#)(#)', function, expression);
+  }
+
+  /// Similar to [provokeCallErrorOn], but provokes an error directly on
+  /// literal "null" expression.
+  static String provokeCallErrorOnNull() {
+    // See [provokeCallErrorOn] for a detailed explanation.
+    var function = JS('', r"""function() {
+  var $argumentsExpr$ = '$arguments$';
+  try {
+    null.$method$($argumentsExpr$);
+  } catch (e) {
+    return e.message;
+  }
+}""");
+    return JS('String', '(#)()', function);
+  }
+
+  /// Similar to [provokeCallErrorOnNull], but provokes an error directly on
+  /// (void 0), that is, "undefined".
+  static String provokeCallErrorOnUndefined() {
+    // See [provokeCallErrorOn] for a detailed explanation.
+    var function = JS('', r"""function() {
+  var $argumentsExpr$ = '$arguments$';
+  try {
+    (void 0).$method$($argumentsExpr$);
+  } catch (e) {
+    return e.message;
+  }
+}""");
+    return JS('String', '(#)()', function);
+  }
+
+  /// Similar to [provokeCallErrorOn], but provokes a property access
+  /// error.
+  static String provokePropertyErrorOn(expression) {
+    // See [provokeCallErrorOn] for a detailed explanation.
+    var function = JS('', r"""function($expr$) {
+  try {
+    $expr$.$method$;
+  } catch (e) {
+    return e.message;
+  }
+}""");
+    return JS('String', '(#)(#)', function, expression);
+  }
+
+  /// Similar to [provokePropertyErrorOn], but provokes an property access
+  /// error directly on literal "null" expression.
+  static String provokePropertyErrorOnNull() {
+    // See [provokeCallErrorOn] for a detailed explanation.
+    var function = JS('', r"""function() {
+  try {
+    null.$method$;
+  } catch (e) {
+    return e.message;
+  }
+}""");
+    return JS('String', '(#)()', function);
+  }
+
+  /// Similar to [provokePropertyErrorOnNull], but provokes an property access
+  /// error directly on (void 0), that is, "undefined".
+  static String provokePropertyErrorOnUndefined() {
+    // See [provokeCallErrorOn] for a detailed explanation.
+    var function = JS('', r"""function() {
+  try {
+    (void 0).$method$;
+  } catch (e) {
+    return e.message;
+  }
+}""");
+    return JS('String', '(#)()', function);
+  }
+}
+
+class NullError extends Error implements NoSuchMethodError {
+  final String _message;
+  final String _method;
+
+  NullError(this._message, match)
+      : _method = match == null ? null : JS('', '#.method', match);
+
+  String toString() {
+    if (_method == null) return 'NoSuchMethodError: $_message';
+    return "NoSuchMethodError: method not found: '$_method' on null";
+  }
+}
+
+class JsNoSuchMethodError extends Error implements NoSuchMethodError {
+  final String _message;
+  final String _method;
+  final String _receiver;
+
+  JsNoSuchMethodError(this._message, match)
+      : _method = match == null ? null : JS('String|Null', '#.method', match),
+        _receiver =
+            match == null ? null : JS('String|Null', '#.receiver', match);
+
+  String toString() {
+    if (_method == null) return 'NoSuchMethodError: $_message';
+    if (_receiver == null) {
+      return "NoSuchMethodError: method not found: '$_method' ($_message)";
+    }
+    return "NoSuchMethodError: "
+        "method not found: '$_method' on '$_receiver' ($_message)";
+  }
+}
+
+class UnknownJsTypeError extends Error {
+  final String _message;
+
+  UnknownJsTypeError(this._message);
+
+  String toString() => _message.isEmpty ? 'Error' : 'Error: $_message';
+}
+
+/// A wrapper around an exception, much like the one created by [wrapException]
+/// but with a pre-given stack-trace.
+class ExceptionAndStackTrace {
+  dynamic dartException;
+  StackTrace stackTrace;
+
+  ExceptionAndStackTrace(this.dartException, this.stackTrace);
+}
+
+/// Called from catch blocks in generated code to extract the Dart
+/// exception from the thrown value. The thrown value may have been
+/// created by [wrapException] or it may be a 'native' JS exception.
+///
+/// Some native exceptions are mapped to new Dart instances, others are
+/// returned unmodified.
+unwrapException(ex) {
+  /// If error implements Error, save [ex] in [error.$thrownJsError].
+  /// Otherwise, do nothing. Later, the stack trace can then be extracted from
+  /// [ex].
+  saveStackTrace(error) {
+    if (error is Error) {
+      var thrownStackTrace = JS('', r'#.$thrownJsError', error);
+      if (thrownStackTrace == null) {
+        JS('void', r'#.$thrownJsError = #', error, ex);
+      }
+    }
+    return error;
+  }
+
+  // Note that we are checking if the object has the property. If it
+  // has, it could be set to null if the thrown value is null.
+  if (ex == null) return null;
+  if (ex is ExceptionAndStackTrace) {
+    return saveStackTrace(ex.dartException);
+  }
+  if (JS('bool', 'typeof # !== "object"', ex)) return ex;
+
+  if (JS('bool', r'"dartException" in #', ex)) {
+    return saveStackTrace(JS('', r'#.dartException', ex));
+  } else if (!JS('bool', r'"message" in #', ex)) {
+    return ex;
+  }
+
+  // Grab hold of the exception message. This field is available on
+  // all supported browsers.
+  var message = JS('var', r'#.message', ex);
+
+  // Internet Explorer has an error number.  This is the most reliable way to
+  // detect specific errors, so check for this first.
+  if (JS('bool', '"number" in #', ex) &&
+      JS('bool', 'typeof #.number == "number"', ex)) {
+    int number = JS('int', '#.number', ex);
+
+    // From http://msdn.microsoft.com/en-us/library/ie/hc53e755(v=vs.94).aspx
+    // "number" is a 32-bit word. The error code is the low 16 bits, and the
+    // facility code is the upper 16 bits.
+    var ieErrorCode = number & 0xffff;
+    var ieFacilityNumber = (number >> 16) & 0x1fff;
+
+    // http://msdn.microsoft.com/en-us/library/aa264975(v=vs.60).aspx
+    // http://msdn.microsoft.com/en-us/library/ie/1dk3k160(v=vs.94).aspx
+    if (ieFacilityNumber == 10) {
+      switch (ieErrorCode) {
+        case 438:
+          return saveStackTrace(
+              new JsNoSuchMethodError('$message (Error $ieErrorCode)', null));
+        case 445:
+        case 5007:
+          return saveStackTrace(
+              new NullError('$message (Error $ieErrorCode)', null));
+      }
+    }
+  }
+
+  if (JS('bool', r'# instanceof TypeError', ex)) {
+    var match;
+    // Using JS to give type hints to the compiler to help tree-shaking.
+    // TODO(ahe): That should be unnecessary due to type inference.
+    var nsme = TypeErrorDecoder.noSuchMethodPattern;
+    var notClosure = TypeErrorDecoder.notClosurePattern;
+    var nullCall = TypeErrorDecoder.nullCallPattern;
+    var nullLiteralCall = TypeErrorDecoder.nullLiteralCallPattern;
+    var undefCall = TypeErrorDecoder.undefinedCallPattern;
+    var undefLiteralCall = TypeErrorDecoder.undefinedLiteralCallPattern;
+    var nullProperty = TypeErrorDecoder.nullPropertyPattern;
+    var nullLiteralProperty = TypeErrorDecoder.nullLiteralPropertyPattern;
+    var undefProperty = TypeErrorDecoder.undefinedPropertyPattern;
+    var undefLiteralProperty = TypeErrorDecoder.undefinedLiteralPropertyPattern;
+    if ((match = nsme.matchTypeError(message)) != null) {
+      return saveStackTrace(new JsNoSuchMethodError(message, match));
+    } else if ((match = notClosure.matchTypeError(message)) != null) {
+      // notClosure may match "({c:null}).c()" or "({c:1}).c()", so we
+      // cannot tell if this an attempt to invoke call on null or a
+      // non-function object.
+      // But we do know the method name is "call".
+      JS('', '#.method = "call"', match);
+      return saveStackTrace(new JsNoSuchMethodError(message, match));
+    } else if ((match = nullCall.matchTypeError(message)) != null ||
+        (match = nullLiteralCall.matchTypeError(message)) != null ||
+        (match = undefCall.matchTypeError(message)) != null ||
+        (match = undefLiteralCall.matchTypeError(message)) != null ||
+        (match = nullProperty.matchTypeError(message)) != null ||
+        (match = nullLiteralCall.matchTypeError(message)) != null ||
+        (match = undefProperty.matchTypeError(message)) != null ||
+        (match = undefLiteralProperty.matchTypeError(message)) != null) {
+      return saveStackTrace(new NullError(message, match));
+    }
+
+    // If we cannot determine what kind of error this is, we fall back
+    // to reporting this as a generic error. It's probably better than
+    // nothing.
+    return saveStackTrace(
+        new UnknownJsTypeError(message is String ? message : ''));
+  }
+
+  if (JS('bool', r'# instanceof RangeError', ex)) {
+    if (message is String && contains(message, 'call stack')) {
+      return new StackOverflowError();
+    }
+
+    // In general, a RangeError is thrown when trying to pass a number as an
+    // argument to a function that does not allow a range that includes that
+    // number. Translate to a Dart ArgumentError with the same message.
+    // TODO(sra): Translate to RangeError.
+    message = tryStringifyException(ex);
+    if (message is String) {
+      message = JS('String', r'#.replace(/^RangeError:\s*/, "")', message);
+    }
+    return saveStackTrace(new ArgumentError(message));
+  }
+
+  // Check for the Firefox specific stack overflow signal.
+  if (JS(
+      'bool',
+      r'typeof InternalError == "function" && # instanceof InternalError',
+      ex)) {
+    if (message is String && message == 'too much recursion') {
+      return new StackOverflowError();
+    }
+  }
+
+  // Just return the exception. We should not wrap it because in case
+  // the exception comes from the DOM, it is a JavaScript
+  // object backed by a native Dart class.
+  return ex;
+}
+
+String tryStringifyException(ex) {
+  // Since this function is called from [unwrapException] which is called from
+  // code injected into a catch-clause, use JavaScript try-catch to avoid a
+  // potential loop if stringifying crashes.
+  return JS(
+      'String|Null',
+      r'''
+    (function(ex) {
+      try {
+        return String(ex);
+      } catch (e) {}
+      return null;
+    })(#)
+    ''',
+      ex);
+}
+
+/// Called by generated code to fetch the stack trace from an
+/// exception. Should never return null.
+StackTrace getTraceFromException(exception) {
+  if (exception is ExceptionAndStackTrace) {
+    return exception.stackTrace;
+  }
+  if (exception == null) return new _StackTrace(exception);
+  _StackTrace trace = JS('_StackTrace|Null', r'#.$cachedTrace', exception);
+  if (trace != null) return trace;
+  trace = new _StackTrace(exception);
+  return JS('_StackTrace', r'#.$cachedTrace = #', exception, trace);
+}
+
+class _StackTrace implements StackTrace {
+  var _exception;
+  String _trace;
+  _StackTrace(this._exception);
+
+  String toString() {
+    if (_trace != null) return JS('String', '#', _trace);
+
+    String trace;
+    if (JS('bool', '# !== null', _exception) &&
+        JS('bool', 'typeof # === "object"', _exception)) {
+      trace = JS('String|Null', r'#.stack', _exception);
+    }
+    return _trace = (trace == null) ? '' : trace;
+  }
+}
+
+int objectHashCode(var object) {
+  if (object == null || JS('bool', "typeof # != 'object'", object)) {
+    return object.hashCode;
+  } else {
+    return Primitives.objectHashCode(object);
+  }
+}
+
+/// Called by generated code to build a map literal. [keyValuePairs] is
+/// a list of key, value, key, value, ..., etc.
+fillLiteralMap(keyValuePairs, Map result) {
+  // TODO(johnniwinther): Use JSArray to optimize this code instead of calling
+  // [getLength] and [getIndex].
+  int index = 0;
+  int length = getLength(keyValuePairs);
+  while (index < length) {
+    var key = getIndex(keyValuePairs, index++);
+    var value = getIndex(keyValuePairs, index++);
+    result[key] = value;
+  }
+  return result;
+}
+
+/// Called by generated code to build a set literal.
+fillLiteralSet(values, Set result) {
+  // TODO(johnniwinther): Use JSArray to optimize this code instead of calling
+  // [getLength] and [getIndex].
+  int length = getLength(values);
+  for (int index = 0; index < length; index++) {
+    result.add(getIndex(values, index));
+  }
+  return result;
+}
+
+invokeClosure(Function closure, int numberOfArguments, var arg1, var arg2,
+    var arg3, var arg4) {
+  switch (numberOfArguments) {
+    case 0:
+      return closure();
+    case 1:
+      return closure(arg1);
+    case 2:
+      return closure(arg1, arg2);
+    case 3:
+      return closure(arg1, arg2, arg3);
+    case 4:
+      return closure(arg1, arg2, arg3, arg4);
+  }
+  throw new Exception('Unsupported number of arguments for wrapped closure');
+}
+
+/// Called by generated code to convert a Dart closure to a JS
+/// closure when the Dart closure is passed to the DOM.
+convertDartClosureToJS(closure, int arity) {
+  if (closure == null) return null;
+  var function = JS('var', r'#.$identity', closure);
+  if (JS('bool', r'!!#', function)) return function;
+
+  function = JS(
+      'var',
+      r'''
+        (function(closure, arity, invoke) {
+          return function(a1, a2, a3, a4) {
+            return invoke(closure, arity, a1, a2, a3, a4);
+          };
+        })(#,#,#)''',
+      closure,
+      arity,
+      DART_CLOSURE_TO_JS(invokeClosure));
+
+  JS('void', r'#.$identity = #', closure, function);
+  return function;
+}
+
+/// Superclass for Dart closures.
+///
+/// All static, tear-off, function declaration and function expression closures
+/// extend this class, but classes that implement Function via a `call` method
+/// do not.
+abstract class Closure implements Function {
+  // TODO(ahe): These constants must be in sync with
+  // reflection_data_parser.dart.
+  static const FUNCTION_INDEX = 0;
+  static const NAME_INDEX = 1;
+  static const CALL_NAME_INDEX = 2;
+  static const REQUIRED_PARAMETER_INDEX = 3;
+  static const OPTIONAL_PARAMETER_INDEX = 4;
+  static const DEFAULT_ARGUMENTS_INDEX = 5;
+
+  /// Global counter to prevent reusing function code objects.
+  ///
+  /// V8 will share the underlying function code objects when the same string is
+  /// passed to "new Function".  Shared function code objects can lead to
+  /// sub-optimal performance due to polymorphism, and can be prevented by
+  /// ensuring the strings are different, for example, by generating a local
+  /// variable with a name dependent on [functionCounter].
+  static int functionCounter = 0;
+
+  Closure();
+
+  /// Creates a new closure class for use by implicit getters associated with a
+  /// method.
+  ///
+  /// In other words, creates a tear-off closure.
+  ///
+  /// Called from [closureFromTearOff] as well as from reflection when tearing
+  /// of a method via `getField`.
+  ///
+  /// This method assumes that [functions] was created by the JavaScript
+  /// function `addStubs` in `reflection_data_parser.dart`. That is, a list of
+  /// JavaScript function objects with properties `$stubName` and `$callName`.
+  ///
+  /// Further assumes that [reflectionInfo] is the end of the array created by
+  /// [dart2js.js_emitter.ContainerBuilder.addMemberMethod] starting with
+  /// required parameter count or, in case of the new emitter, the runtime
+  /// representation of the function's type.
+  ///
+  /// Caution: this function may be called when building constants.
+  /// TODO(ahe): Don't call this function when building constants.
+  static fromTearOff(
+    receiver,
+    List functions,
+    int applyTrampolineIndex,
+    var reflectionInfo,
+    bool isStatic,
+    bool isIntercepted,
+    String propertyName,
+  ) {
+    JS_EFFECT(() {
+      // The functions are called here to model the calls from JS forms below.
+      // The types in the JS forms in the arguments are propagated in type
+      // inference.
+      var aBoundClosure = JS('BoundClosure', '0');
+      var aString = JS('String', '0');
+      BoundClosure.receiverOf(aBoundClosure);
+      BoundClosure.selfOf(aBoundClosure);
+      BoundClosure.evalRecipeIntercepted(aBoundClosure, aString);
+      BoundClosure.evalRecipe(aBoundClosure, aString);
+      getType(JS('int', '0'));
+    });
+    // TODO(ahe): All the place below using \$ should be rewritten to go
+    // through the namer.
+    var function = JS('', '#[#]', functions, 0);
+    String name = JS('String|Null', '#.\$stubName', function);
+    String callName = JS('String|Null', '#[#]', function,
+        JS_GET_NAME(JsGetName.CALL_NAME_PROPERTY));
+
+    // This variable holds either an index into the types-table, or a function
+    // that can compute a function-rti. (The latter is necessary if the type
+    // is dependent on generic arguments).
+    var functionType = reflectionInfo;
+
+    // function tmp() {};
+    // tmp.prototype = BC.prototype;
+    // var proto = new tmp;
+    // for each computed prototype property:
+    //   proto[property] = ...;
+    // proto._init = BC;
+    // var dynClosureConstructor =
+    //     new Function('self', 'target', 'receiver', 'name',
+    //                  'this._init(self, target, receiver, name)');
+    // proto.constructor = dynClosureConstructor;
+    // dynClosureConstructor.prototype = proto;
+    // return dynClosureConstructor;
+
+    // We need to create a new subclass of TearOffClosure, one of StaticClosure
+    // or BoundClosure.  For this, we need to create an object whose prototype
+    // is the prototype is either StaticClosure.prototype or
+    // BoundClosure.prototype, respectively in pseudo JavaScript code. The
+    // simplest way to access the JavaScript construction function of a Dart
+    // class is to create an instance and access its constructor property.
+    // Creating an instance ensures that any lazy class initialization has taken
+    // place. The newly created instance could in theory be used directly as the
+    // prototype, but it might include additional fields that we don't need.  So
+    // we only use the new instance to access the constructor property and use
+    // Object.create to create the desired prototype.
+    //
+    // TODO(sra): Perhaps cache the prototype to avoid the allocation.
+    var prototype = isStatic
+        ? JS('StaticClosure', 'Object.create(#.constructor.prototype)',
+            new StaticClosure())
+        : JS('BoundClosure', 'Object.create(#.constructor.prototype)',
+            new BoundClosure(null, null, null, null));
+
+    JS('', '#.\$initialize = #', prototype, JS('', '#.constructor', prototype));
+
+    // The constructor functions have names to prevent the JavaScript
+    // implementation from inventing a name that might have special meaning
+    // (e.g. clashing with minified 'Object' or 'Interceptor').
+    var constructor = isStatic
+        ? JS('', 'function static_tear_off(){this.\$initialize()}')
+        : isCsp
+            ? JS('', 'function tear_off(a,b,c,d) {this.\$initialize(a,b,c,d)}')
+            : JS(
+                '',
+                'new Function("a,b,c,d" + #,'
+                    ' "this.\$initialize(a,b,c,d" + # + ")")',
+                functionCounter,
+                functionCounter++);
+
+    // It is necessary to set the constructor property, otherwise it will be
+    // "Object".
+    JS('', '#.constructor = #', prototype, constructor);
+
+    JS('', '#.prototype = #', constructor, prototype);
+
+    // Create a closure and "monkey" patch it with call stubs.
+    var trampoline = function;
+    if (!isStatic) {
+      trampoline = forwardCallTo(receiver, function, isIntercepted);
+      JS('', '#.\$reflectionInfo = #', trampoline, reflectionInfo);
+    } else {
+      JS('', '#[#] = #', prototype, STATIC_FUNCTION_NAME_PROPERTY_NAME,
+          propertyName);
+    }
+
+    var signatureFunction = JS_GET_FLAG('USE_NEW_RTI')
+        ? _computeSignatureFunctionNewRti(functionType, isStatic, isIntercepted)
+        : _computeSignatureFunctionLegacy(
+            functionType, isStatic, isIntercepted);
+
+    JS('', '#[#] = #', prototype, JS_GET_NAME(JsGetName.SIGNATURE_NAME),
+        signatureFunction);
+    var applyTrampoline = trampoline;
+    JS('', '#[#] = #', prototype, callName, trampoline);
+    for (int i = 1; i < functions.length; i++) {
+      var stub = functions[i];
+      var stubCallName = JS('String|Null', '#[#]', stub,
+          JS_GET_NAME(JsGetName.CALL_NAME_PROPERTY));
+      if (stubCallName != null) {
+        stub = isStatic ? stub : forwardCallTo(receiver, stub, isIntercepted);
+        JS('', '#[#] = #', prototype, stubCallName, stub);
+      }
+      if (i == applyTrampolineIndex) {
+        applyTrampoline = stub;
+        JS('', '#.\$reflectionInfo = #', applyTrampoline, reflectionInfo);
+      }
+    }
+
+    JS('', '#[#] = #', prototype, JS_GET_NAME(JsGetName.CALL_CATCH_ALL),
+        applyTrampoline);
+    String reqArgProperty = JS_GET_NAME(JsGetName.REQUIRED_PARAMETER_PROPERTY);
+    String defValProperty = JS_GET_NAME(JsGetName.DEFAULT_VALUES_PROPERTY);
+    JS('', '#.# = #.#', prototype, reqArgProperty, function, reqArgProperty);
+    JS('', '#.# = #.#', prototype, defValProperty, function, defValProperty);
+
+    return constructor;
+  }
+
+  static _computeSignatureFunctionLegacy(
+      Object functionType, bool isStatic, bool isIntercepted) {
+    if (JS('bool', 'typeof # == "number"', functionType)) {
+      // We cannot call [getType] here, since the types-metadata might not be
+      // set yet. This is, because fromTearOff might be called for constants
+      // when the program isn't completely set up yet.
+      //
+      // Note that we cannot just textually inline the call
+      // `getType(functionType)` since we cannot guarantee that the (then)
+      // captured variable `functionType` isn't reused.
+      return JS(
+          '',
+          '''(function(getType, t) {
+                    return function(){ return getType(t); };
+                })(#, #)''',
+          RAW_DART_FUNCTION_REF(getType),
+          functionType);
+    }
+    if (JS('bool', 'typeof # == "function"', functionType)) {
+      if (isStatic) {
+        return functionType;
+      } else {
+        var getReceiver = isIntercepted
+            ? RAW_DART_FUNCTION_REF(BoundClosure.receiverOf)
+            : RAW_DART_FUNCTION_REF(BoundClosure.selfOf);
+        return JS(
+            '',
+            'function(f,r){'
+                'return function(){'
+                'return f.apply({\$receiver:r(this)},arguments)'
+                '}'
+                '}(#,#)',
+            functionType,
+            getReceiver);
+      }
+    }
+    throw 'Error in functionType of tearoff';
+  }
+
+  static _computeSignatureFunctionNewRti(
+      Object functionType, bool isStatic, bool isIntercepted) {
+    if (JS('bool', 'typeof # == "number"', functionType)) {
+      // Index into types table.
+      //
+      // We cannot call [getTypeFromTypesTable] here, since the types-metadata
+      // might not be set yet. This is, because fromTearOff might be called for
+      // constants when the program isn't completely set up yet. We also want to
+      // avoid creating lots of types at startup.
+      return JS(
+          '',
+          '''(function(getType, t) {
+                 return function(){ return getType(t); };
+             })(#, #)''',
+          RAW_DART_FUNCTION_REF(newRti.getTypeFromTypesTable),
+          functionType);
+    }
+    if (JS('bool', 'typeof # == "string"', functionType)) {
+      // A recipe to evaluate against the instance type.
+      if (isStatic) {
+        throw 'TODO: Recipe for static tearoff.';
+      }
+      var typeEvalMethod = isIntercepted
+          ? RAW_DART_FUNCTION_REF(BoundClosure.evalRecipeIntercepted)
+          : RAW_DART_FUNCTION_REF(BoundClosure.evalRecipe);
+      return JS(
+          '',
+          '    function(recipe, evalOnReceiver) {'
+              '  return function() {'
+              '    return evalOnReceiver(this, recipe);'
+              '  };'
+              '}(#,#)',
+          functionType,
+          typeEvalMethod);
+    }
+    throw 'Error in functionType of tearoff';
+  }
+
+  static cspForwardCall(
+      int arity, bool isSuperCall, String stubName, function) {
+    var getSelf = RAW_DART_FUNCTION_REF(BoundClosure.selfOf);
+    // Handle intercepted stub-names with the default slow case.
+    if (isSuperCall) arity = -1;
+    switch (arity) {
+      case 0:
+        return JS(
+            '',
+            'function(n,S){'
+                'return function(){'
+                'return S(this)[n]()'
+                '}'
+                '}(#,#)',
+            stubName,
+            getSelf);
+      case 1:
+        return JS(
+            '',
+            'function(n,S){'
+                'return function(a){'
+                'return S(this)[n](a)'
+                '}'
+                '}(#,#)',
+            stubName,
+            getSelf);
+      case 2:
+        return JS(
+            '',
+            'function(n,S){'
+                'return function(a,b){'
+                'return S(this)[n](a,b)'
+                '}'
+                '}(#,#)',
+            stubName,
+            getSelf);
+      case 3:
+        return JS(
+            '',
+            'function(n,S){'
+                'return function(a,b,c){'
+                'return S(this)[n](a,b,c)'
+                '}'
+                '}(#,#)',
+            stubName,
+            getSelf);
+      case 4:
+        return JS(
+            '',
+            'function(n,S){'
+                'return function(a,b,c,d){'
+                'return S(this)[n](a,b,c,d)'
+                '}'
+                '}(#,#)',
+            stubName,
+            getSelf);
+      case 5:
+        return JS(
+            '',
+            'function(n,S){'
+                'return function(a,b,c,d,e){'
+                'return S(this)[n](a,b,c,d,e)'
+                '}'
+                '}(#,#)',
+            stubName,
+            getSelf);
+      default:
+        return JS(
+            '',
+            'function(f,s){'
+                'return function(){'
+                'return f.apply(s(this),arguments)'
+                '}'
+                '}(#,#)',
+            function,
+            getSelf);
+    }
+  }
+
+  static bool get isCsp => JS_GET_FLAG('USE_CONTENT_SECURITY_POLICY');
+
+  static forwardCallTo(receiver, function, bool isIntercepted) {
+    if (isIntercepted) return forwardInterceptedCallTo(receiver, function);
+    String stubName = JS('String|Null', '#.\$stubName', function);
+    int arity = JS('int', '#.length', function);
+    var lookedUpFunction = JS('', '#[#]', receiver, stubName);
+    // The receiver[stubName] may not be equal to the function if we try to
+    // forward to a super-method. Especially when we create a bound closure
+    // of a super-call we need to make sure that we don't forward back to the
+    // dynamically looked up function.
+    bool isSuperCall = !identical(function, lookedUpFunction);
+
+    if (isCsp || isSuperCall || arity >= 27) {
+      return cspForwardCall(arity, isSuperCall, stubName, function);
+    }
+
+    if (arity == 0) {
+      // Incorporate functionCounter into a local.
+      String selfName = 'self${functionCounter++}';
+      return JS(
+          '',
+          '(new Function(#))()',
+          'return function(){'
+              'var $selfName = this.${BoundClosure.selfFieldName()};'
+              'return $selfName.$stubName();'
+              '}');
+    }
+    assert(1 <= arity && arity < 27);
+    String arguments = JS('String',
+        '"abcdefghijklmnopqrstuvwxyz".split("").splice(0,#).join(",")', arity);
+    arguments += '${functionCounter++}';
+    return JS(
+        '',
+        '(new Function(#))()',
+        'return function($arguments){'
+            'return this.${BoundClosure.selfFieldName()}.$stubName($arguments);'
+            '}');
+  }
+
+  static cspForwardInterceptedCall(
+      int arity, bool isSuperCall, String name, function) {
+    var getSelf = RAW_DART_FUNCTION_REF(BoundClosure.selfOf);
+    var getReceiver = RAW_DART_FUNCTION_REF(BoundClosure.receiverOf);
+    // Handle intercepted stub-names with the default slow case.
+    if (isSuperCall) arity = -1;
+    switch (arity) {
+      case 0:
+        // Intercepted functions always takes at least one argument (the
+        // receiver).
+        throw new RuntimeError('Intercepted function with no arguments.');
+      case 1:
+        return JS(
+            '',
+            'function(n,s,r){'
+                'return function(){'
+                'return s(this)[n](r(this))'
+                '}'
+                '}(#,#,#)',
+            name,
+            getSelf,
+            getReceiver);
+      case 2:
+        return JS(
+            '',
+            'function(n,s,r){'
+                'return function(a){'
+                'return s(this)[n](r(this),a)'
+                '}'
+                '}(#,#,#)',
+            name,
+            getSelf,
+            getReceiver);
+      case 3:
+        return JS(
+            '',
+            'function(n,s,r){'
+                'return function(a,b){'
+                'return s(this)[n](r(this),a,b)'
+                '}'
+                '}(#,#,#)',
+            name,
+            getSelf,
+            getReceiver);
+      case 4:
+        return JS(
+            '',
+            'function(n,s,r){'
+                'return function(a,b,c){'
+                'return s(this)[n](r(this),a,b,c)'
+                '}'
+                '}(#,#,#)',
+            name,
+            getSelf,
+            getReceiver);
+      case 5:
+        return JS(
+            '',
+            'function(n,s,r){'
+                'return function(a,b,c,d){'
+                'return s(this)[n](r(this),a,b,c,d)'
+                '}'
+                '}(#,#,#)',
+            name,
+            getSelf,
+            getReceiver);
+      case 6:
+        return JS(
+            '',
+            'function(n,s,r){'
+                'return function(a,b,c,d,e){'
+                'return s(this)[n](r(this),a,b,c,d,e)'
+                '}'
+                '}(#,#,#)',
+            name,
+            getSelf,
+            getReceiver);
+      default:
+        return JS(
+            '',
+            'function(f,s,r,a){'
+                'return function(){'
+                'a=[r(this)];'
+                'Array.prototype.push.apply(a,arguments);'
+                'return f.apply(s(this),a)'
+                '}'
+                '}(#,#,#)',
+            function,
+            getSelf,
+            getReceiver);
+    }
+  }
+
+  static forwardInterceptedCallTo(receiver, function) {
+    String selfField = BoundClosure.selfFieldName();
+    String receiverField = BoundClosure.receiverFieldName();
+    String stubName = JS('String|Null', '#.\$stubName', function);
+    int arity = JS('int', '#.length', function);
+    bool isCsp = JS_GET_FLAG('USE_CONTENT_SECURITY_POLICY');
+    var lookedUpFunction = JS('', '#[#]', receiver, stubName);
+    // The receiver[stubName] may not be equal to the function if we try to
+    // forward to a super-method. Especially when we create a bound closure
+    // of a super-call we need to make sure that we don't forward back to the
+    // dynamically looked up function.
+    bool isSuperCall = !identical(function, lookedUpFunction);
+
+    if (isCsp || isSuperCall || arity >= 28) {
+      return cspForwardInterceptedCall(arity, isSuperCall, stubName, function);
+    }
+    if (arity == 1) {
+      return JS(
+          '',
+          '(new Function(#))()',
+          'return function(){'
+              'return this.$selfField.$stubName(this.$receiverField);'
+              '${functionCounter++}'
+              '}');
+    }
+    assert(1 < arity && arity < 28);
+    String arguments = JS(
+        'String',
+        '"abcdefghijklmnopqrstuvwxyz".split("").splice(0,#).join(",")',
+        arity - 1);
+    return JS(
+        '',
+        '(new Function(#))()',
+        'return function($arguments){'
+            'return this.$selfField.$stubName(this.$receiverField, $arguments);'
+            '${functionCounter++}'
+            '}');
+  }
+
+  // The backend adds a special getter of the form
+  //
+  // Closure get call => this;
+  //
+  // to allow tearing off a closure from itself. We do this magically in the
+  // backend rather than simply adding it here, as we do not want this getter
+  // to be visible to resolution and the generation of extra stubs.
+
+  String toString() {
+    String name;
+    if (JS_GET_FLAG('USE_NEW_RTI')) {
+      var constructor = JS('', '#.constructor', this);
+      name =
+          constructor == null ? null : JS('String|Null', '#.name', constructor);
+      if (name == null) name = 'unknown';
+    } else {
+      name = Primitives.objectTypeName(this);
+      // Mirrors puts a space in front of some names, so remove it.
+      name = JS('String', '#.trim()', name);
+    }
+    return "Closure '$name'";
+  }
+}
+
+/// Called from implicit method getter (aka tear-off).
+closureFromTearOff(receiver, functions, applyTrampolineIndex, reflectionInfo,
+    isStatic, isIntercepted, name) {
+  return Closure.fromTearOff(
+      receiver,
+      JS('JSArray', '#', functions),
+      JS('int|Null', '#', applyTrampolineIndex),
+      reflectionInfo,
+      JS('bool', '!!#', isStatic),
+      JS('bool', '!!#', isIntercepted),
+      JS('String', '#', name));
+}
+
+/// Represents an implicit closure of a function.
+abstract class TearOffClosure extends Closure {}
+
+class StaticClosure extends TearOffClosure {
+  String toString() {
+    String name =
+        JS('String|Null', '#[#]', this, STATIC_FUNCTION_NAME_PROPERTY_NAME);
+    if (name == null) return 'Closure of unknown static method';
+    return "Closure '${unminifyOrTag(name)}'";
+  }
+}
+
+/// Represents a 'tear-off' or property extraction closure of an instance
+/// method, that is an instance method bound to a specific receiver (instance).
+class BoundClosure extends TearOffClosure {
+  /// The receiver or interceptor.
+  // TODO(ahe): This could just be the interceptor, we always know if
+  // we need the interceptor when generating the call method.
+  final _self;
+
+  /// The method.
+  final _target;
+
+  /// The receiver. Null if [_self] is not an interceptor.
+  final _receiver;
+
+  /// The name of the function. Only used by the mirror system.
+  final String _name;
+
+  BoundClosure(this._self, this._target, this._receiver, this._name);
+
+  bool operator ==(other) {
+    if (identical(this, other)) return true;
+    if (other is! BoundClosure) return false;
+    return JS('bool', '# === #', _self, other._self) &&
+        JS('bool', '# === #', _target, other._target) &&
+        JS('bool', '# === #', _receiver, other._receiver);
+  }
+
+  int get hashCode {
+    int receiverHashCode;
+    if (_receiver == null) {
+      // A bound closure on a regular Dart object, just use the
+      // identity hash code.
+      receiverHashCode = Primitives.objectHashCode(_self);
+    } else if (JS('String', 'typeof #', _receiver) != 'object') {
+      // A bound closure on a primitive JavaScript type. We
+      // use the hashCode method we define for those primitive types.
+      receiverHashCode = _receiver.hashCode;
+    } else {
+      // A bound closure on an intercepted native class, just use the
+      // identity hash code.
+      receiverHashCode = Primitives.objectHashCode(_receiver);
+    }
+    return receiverHashCode ^ Primitives.objectHashCode(_target);
+  }
+
+  toString() {
+    var receiver = _receiver == null ? _self : _receiver;
+    // TODO(sra): When minified, mark [_name] with a tag,
+    // e.g. 'minified-property:' so that it can be unminified.
+    return "Closure '$_name' of "
+        "${Primitives.objectToHumanReadableString(receiver)}";
+  }
+
+  static evalRecipe(BoundClosure closure, String recipe) {
+    return newRti.evalInInstance(closure._self, recipe);
+  }
+
+  static evalRecipeIntercepted(BoundClosure closure, String recipe) {
+    return newRti.evalInInstance(closure._receiver, recipe);
+  }
+
+  @pragma('dart2js:noInline')
+  static selfOf(BoundClosure closure) => closure._self;
+
+  static targetOf(BoundClosure closure) => closure._target;
+
+  @pragma('dart2js:noInline')
+  static receiverOf(BoundClosure closure) => closure._receiver;
+
+  static nameOf(BoundClosure closure) => closure._name;
+
+  static String selfFieldNameCache;
+
+  static String selfFieldName() {
+    if (selfFieldNameCache == null) {
+      selfFieldNameCache = computeFieldNamed('self');
+    }
+    return selfFieldNameCache;
+  }
+
+  static String receiverFieldNameCache;
+
+  static String receiverFieldName() {
+    if (receiverFieldNameCache == null) {
+      receiverFieldNameCache = computeFieldNamed('receiver');
+    }
+    return receiverFieldNameCache;
+  }
+
+  @pragma('dart2js:noInline')
+  @pragma('dart2js:noSideEffects')
+  static String computeFieldNamed(String fieldName) {
+    var template = new BoundClosure('self', 'target', 'receiver', 'name');
+    var names = JSArray.markFixedList(
+        JS('', 'Object.getOwnPropertyNames(#)', template));
+    for (int i = 0; i < names.length; i++) {
+      var name = names[i];
+      if (JS('bool', '#[#] === #', template, name, fieldName)) {
+        return JS('String', '#', name);
+      }
+    }
+  }
+}
+
+bool jsHasOwnProperty(var jsObject, String property) {
+  return JS('bool', r'#.hasOwnProperty(#)', jsObject, property);
+}
+
+jsPropertyAccess(var jsObject, String property) {
+  return JS('var', r'#[#]', jsObject, property);
+}
+
+/// Called at the end of unaborted switch cases to get the singleton
+/// FallThroughError exception that will be thrown.
+getFallThroughError() => new FallThroughErrorImplementation();
+
+/// A metadata annotation describing the types instantiated by a native element.
+///
+/// The annotation is valid on a native method and a field of a native class.
+///
+/// By default, a field of a native class is seen as an instantiation point for
+/// all native classes that are a subtype of the field's type, and a native
+/// method is seen as an instantiation point fo all native classes that are a
+/// subtype of the method's return type, or the argument types of the declared
+/// type of the method's callback parameter.
+///
+/// An @[Creates] annotation overrides the default set of instantiated types.
+/// If one or more @[Creates] annotations are present, the type of the native
+/// element is ignored, and the union of @[Creates] annotations is used instead.
+/// The names in the strings are resolved and the program will fail to compile
+/// with dart2js if they do not name types.
+///
+/// The argument to [Creates] is a string.  The string is parsed as the names of
+/// one or more types, separated by vertical bars `|`.  There are some special
+/// names:
+///
+/// * `=Object`. This means 'exactly Object', which is a plain JavaScript object
+///   with properties and none of the subtypes of Object.
+///
+/// Example: we may know that a method always returns a specific implementation:
+///
+///     @Creates('_NodeList')
+///     List<Node> getElementsByTagName(String tag) native;
+///
+/// Useful trick: A method can be marked as not instantiating any native classes
+/// with the annotation `@Creates('Null')`.  This is useful for fields on native
+/// classes that are used only in Dart code.
+///
+///     @Creates('Null')
+///     var _cachedFoo;
+class Creates {
+  final String types;
+  const Creates(this.types);
+}
+
+/// A metadata annotation describing the types returned or yielded by a native
+/// element.
+///
+/// The annotation is valid on a native method and a field of a native class.
+///
+/// By default, a native method or field is seen as returning or yielding all
+/// subtypes if the method return type or field type.  This annotation allows a
+/// more precise set of types to be specified.
+///
+/// See [Creates] for the syntax of the argument.
+///
+/// Example: IndexedDB keys are numbers, strings and JavaScript Arrays of keys.
+///
+///     @Returns('String|num|JSExtendableArray')
+///     dynamic key;
+///
+///     // Equivalent:
+///     @Returns('String') @Returns('num') @Returns('JSExtendableArray')
+///     dynamic key;
+class Returns {
+  final String types;
+  const Returns(this.types);
+}
+
+/// A metadata annotation placed on native methods and fields of native classes
+/// to specify the JavaScript name.
+///
+/// This example declares a Dart field + getter + setter called `$dom_title`
+/// that corresponds to the JavaScript property `title`.
+///
+///     class Document native "*Foo" {
+///       @JSName('title')
+///       String $dom_title;
+///     }
+class JSName {
+  final String name;
+  const JSName(this.name);
+}
+
+/// The following methods are called by the runtime to implement checked mode
+/// and casts. We specialize each primitive type (eg int, bool), and use the
+/// compiler's convention to do is-checks on regular objects.
+boolConversionCheck(value) {
+  // The value from kernel should always be true, false, or null.
+  if (value == null) assertThrow('boolean expression must not be null');
+  return value;
+}
+
+stringTypeCheck(value) {
+  if (value == null) return value;
+  if (value is String) return value;
+  throw new TypeErrorImplementation(value, 'String');
+}
+
+stringTypeCast(value) {
+  if (value is String || value == null) return value;
+  throw new CastErrorImplementation(value, 'String');
+}
+
+doubleTypeCheck(value) {
+  if (value == null) return value;
+  if (value is double) return value;
+  throw new TypeErrorImplementation(value, 'double');
+}
+
+doubleTypeCast(value) {
+  if (value is double || value == null) return value;
+  throw new CastErrorImplementation(value, 'double');
+}
+
+numTypeCheck(value) {
+  if (value == null) return value;
+  if (value is num) return value;
+  throw new TypeErrorImplementation(value, 'num');
+}
+
+numTypeCast(value) {
+  if (value is num || value == null) return value;
+  throw new CastErrorImplementation(value, 'num');
+}
+
+boolTypeCheck(value) {
+  if (value == null) return value;
+  if (value is bool) return value;
+  throw new TypeErrorImplementation(value, 'bool');
+}
+
+boolTypeCast(value) {
+  if (value is bool || value == null) return value;
+  throw new CastErrorImplementation(value, 'bool');
+}
+
+intTypeCheck(value) {
+  if (value == null) return value;
+  if (value is int) return value;
+  throw new TypeErrorImplementation(value, 'int');
+}
+
+intTypeCast(value) {
+  if (value is int || value == null) return value;
+  throw new CastErrorImplementation(value, 'int');
+}
+
+void propertyTypeError(value, property) {
+  String name = isCheckPropertyToJsConstructorName(property);
+  throw new TypeErrorImplementation(value, unminifyOrTag(name));
+}
+
+void propertyTypeCastError(value, property) {
+  // Cuts the property name to the class name.
+  String name = isCheckPropertyToJsConstructorName(property);
+  throw new CastErrorImplementation(value, unminifyOrTag(name));
+}
+
+/// For types that are not supertypes of native (eg DOM) types,
+/// we emit a simple property check to check that an object implements
+/// that type.
+propertyTypeCheck(value, property) {
+  if (value == null) return value;
+  if (JS('bool', '!!#[#]', value, property)) return value;
+  propertyTypeError(value, property);
+}
+
+/// For types that are not supertypes of native (eg DOM) types,
+/// we emit a simple property check to check that an object implements
+/// that type.
+propertyTypeCast(value, property) {
+  if (value == null || JS('bool', '!!#[#]', value, property)) return value;
+  propertyTypeCastError(value, property);
+}
+
+/// For types that are supertypes of native (eg DOM) types, we use the
+/// interceptor for the class because we cannot add a JS property to the
+/// prototype at load time.
+interceptedTypeCheck(value, property) {
+  if (value == null) return value;
+  if ((JS('bool', 'typeof # === "object"', value) ||
+          JS('bool', 'typeof # === "function"', value)) &&
+      JS('bool', '#[#]', getInterceptor(value), property)) {
+    return value;
+  }
+  propertyTypeError(value, property);
+}
+
+/// For types that are supertypes of native (eg DOM) types, we use the
+/// interceptor for the class because we cannot add a JS property to the
+/// prototype at load time.
+interceptedTypeCast(value, property) {
+  if (value == null ||
+      ((JS('bool', 'typeof # === "object"', value) ||
+              JS('bool', 'typeof # === "function"', value)) &&
+          JS('bool', '#[#]', getInterceptor(value), property))) {
+    return value;
+  }
+  propertyTypeCastError(value, property);
+}
+
+/// Specialization of the type check for num and String and their
+/// supertype since [value] can be a JS primitive.
+numberOrStringSuperTypeCheck(value, property) {
+  if (value == null) return value;
+  if (value is String) return value;
+  if (value is num) return value;
+  if (JS('bool', '!!#[#]', value, property)) return value;
+  propertyTypeError(value, property);
+}
+
+numberOrStringSuperTypeCast(value, property) {
+  if (value is String) return value;
+  if (value is num) return value;
+  return propertyTypeCast(value, property);
+}
+
+numberOrStringSuperNativeTypeCheck(value, property) {
+  if (value == null) return value;
+  if (value is String) return value;
+  if (value is num) return value;
+  if (JS('bool', '#[#]', getInterceptor(value), property)) return value;
+  propertyTypeError(value, property);
+}
+
+numberOrStringSuperNativeTypeCast(value, property) {
+  if (value == null) return value;
+  if (value is String) return value;
+  if (value is num) return value;
+  if (JS('bool', '#[#]', getInterceptor(value), property)) return value;
+  propertyTypeCastError(value, property);
+}
+
+/// Specialization of the type check for String and its supertype
+/// since [value] can be a JS primitive.
+stringSuperTypeCheck(value, property) {
+  if (value == null) return value;
+  if (value is String) return value;
+  if (JS('bool', '!!#[#]', value, property)) return value;
+  propertyTypeError(value, property);
+}
+
+stringSuperTypeCast(value, property) {
+  if (value is String) return value;
+  return propertyTypeCast(value, property);
+}
+
+stringSuperNativeTypeCheck(value, property) {
+  if (value == null) return value;
+  if (value is String) return value;
+  if (JS('bool', '#[#]', getInterceptor(value), property)) return value;
+  propertyTypeError(value, property);
+}
+
+stringSuperNativeTypeCast(value, property) {
+  if (value is String || value == null) return value;
+  if (JS('bool', '#[#]', getInterceptor(value), property)) return value;
+  propertyTypeCastError(value, property);
+}
+
+/// Specialization of the type check for List and its supertypes,
+/// since [value] can be a JS array.
+listTypeCheck(value) {
+  if (value == null) return value;
+  if (value is List) return value;
+  throw new TypeErrorImplementation(value, 'List<dynamic>');
+}
+
+listTypeCast(value) {
+  if (value is List || value == null) return value;
+  throw new CastErrorImplementation(value, 'List<dynamic>');
+}
+
+listSuperTypeCheck(value, property) {
+  if (value == null) return value;
+  if (value is List) return value;
+  if (JS('bool', '!!#[#]', value, property)) return value;
+  propertyTypeError(value, property);
+}
+
+listSuperTypeCast(value, property) {
+  if (value is List) return value;
+  return propertyTypeCast(value, property);
+}
+
+listSuperNativeTypeCheck(value, property) {
+  if (value == null) return value;
+  if (value is List) return value;
+  if (JS('bool', '#[#]', getInterceptor(value), property)) return value;
+  propertyTypeError(value, property);
+}
+
+listSuperNativeTypeCast(value, property) {
+  if (value is List || value == null) return value;
+  if (JS('bool', '#[#]', getInterceptor(value), property)) return value;
+  propertyTypeCastError(value, property);
+}
+
+extractFunctionTypeObjectFrom(o) {
+  var interceptor = getInterceptor(o);
+  return extractFunctionTypeObjectFromInternal(interceptor);
+}
+
+extractFunctionTypeObjectFromInternal(o) {
+  var signatureName = JS_GET_NAME(JsGetName.SIGNATURE_NAME);
+  if (JS('bool', '# in #', signatureName, o)) {
+    var signature = JS('', '#[#]', o, signatureName);
+    if (JS('bool', 'typeof # == "number"', signature)) {
+      return getType(signature);
+    } else {
+      return JS('', '#[#]()', o, signatureName);
+    }
+  }
+  return null;
+}
+
+functionTypeTest(value, functionTypeRti) {
+  if (value == null) return false;
+  if (JS('bool', 'typeof # == "function"', value)) {
+    // JavaScript functions do not have an attached type, but for convenient
+    // JS-interop, we pretend they can be any function type.
+    // TODO(sra): Tighten this up to disallow matching function types with
+    // features inaccessible from JavaScript, i.e.  optional named parameters
+    // and type parameters functions.
+    // TODO(sra): If the JavaScript function was the output of `dart:js`'s
+    // `allowInterop` then we have access to the wrapped function.
+    return true;
+  }
+  var functionTypeObject = extractFunctionTypeObjectFrom(value);
+  if (functionTypeObject == null) return false;
+  return isFunctionSubtype(functionTypeObject, functionTypeRti);
+}
+
+// Declared as 'var' to avoid assignment checks.
+var _inTypeAssertion = false;
+
+functionTypeCheck(value, functionTypeRti) {
+  if (value == null) return value;
+
+  // The function type test code contains type assertions for function
+  // types. This leads to unbounded recursion, so disable the type checking of
+  // function types while checking function types.
+
+  if (true == _inTypeAssertion) return value;
+
+  _inTypeAssertion = true;
+  try {
+    if (functionTypeTest(value, functionTypeRti)) return value;
+    var self = runtimeTypeToString(functionTypeRti);
+    throw new TypeErrorImplementation(value, self);
+  } finally {
+    _inTypeAssertion = false;
+  }
+}
+
+functionTypeCast(value, functionTypeRti) {
+  if (value == null) return value;
+  if (functionTypeTest(value, functionTypeRti)) return value;
+
+  var self = runtimeTypeToString(functionTypeRti);
+  throw new CastErrorImplementation(value, self);
+}
+
+futureOrTest(o, futureOrRti) => checkSubtypeOfRuntimeType(o, futureOrRti);
+
+futureOrCheck(o, futureOrRti) => assertSubtypeOfRuntimeType(o, futureOrRti);
+
+futureOrCast(o, futureOrRti) => subtypeOfRuntimeTypeCast(o, futureOrRti);
+
+@pragma('dart2js:noInline')
+void checkDeferredIsLoaded(String loadId, String uri) {
+  if (!_loadedLibraries.contains(loadId)) {
+    throw new DeferredNotLoadedError(uri);
+  }
+}
+
+/// Special interface recognized by the compiler and implemented by DOM
+/// objects that support integer indexing. This interface is not
+/// visible to anyone, and is only injected into special libraries.
+abstract class JavaScriptIndexingBehavior<E> extends JSMutableIndexable<E> {}
+
+// TODO(lrn): These exceptions should be implemented in core.
+// When they are, remove the 'Implementation' here.
+
+/// Thrown by type assertions that fail.
+class TypeErrorImplementation extends Error implements TypeError {
+  final String message;
+
+  /// Normal type error caused by a failed subtype test.
+  TypeErrorImplementation(Object value, String type)
+      : message = "TypeError: ${Error.safeToString(value)}: type "
+            "'${_typeDescription(value)}' is not a subtype of type '$type'";
+
+  TypeErrorImplementation.fromMessage(String this.message);
+
+  String toString() => message;
+}
+
+/// Thrown by the 'as' operator if the cast isn't valid.
+class CastErrorImplementation extends Error implements CastError {
+  // TODO(lrn): Rename to CastError (and move implementation into core).
+  final String message;
+
+  /// Normal cast error caused by a failed type cast.
+  CastErrorImplementation(Object value, Object type)
+      : message = "CastError: ${Error.safeToString(value)}: type "
+            "'${_typeDescription(value)}' is not a subtype of type '$type'";
+
+  String toString() => message;
+}
+
+String _typeDescription(value) {
+  if (value is Closure) {
+    var functionTypeObject = extractFunctionTypeObjectFrom(value);
+    if (functionTypeObject != null) {
+      return runtimeTypeToString(functionTypeObject);
+    }
+    return 'Closure';
+  }
+  return Primitives.objectTypeName(value);
+}
+
+class FallThroughErrorImplementation extends FallThroughError {
+  FallThroughErrorImplementation();
+  String toString() => 'Switch case fall-through.';
+}
+
+/// Helper function for implementing asserts. The compiler treats this
+/// specially.
+///
+/// Returns the negation of the condition. That is: `true` if the assert should
+/// fail.
+bool assertTest(condition) {
+  // Do bool success check first, it is common and faster than 'is Function'.
+  if (true == condition) return false;
+  if (condition is bool) return !condition;
+  throw new TypeErrorImplementation(condition, 'bool');
+}
+
+/// Helper function for implementing asserts with messages.
+/// The compiler treats this specially.
+void assertThrow(Object message) {
+  throw new _AssertionError(message);
+}
+
+/// Helper function for implementing asserts without messages.
+/// The compiler treats this specially.
+@pragma('dart2js:noInline')
+void assertHelper(condition) {
+  if (assertTest(condition)) throw new AssertionError();
+}
+
+/// Called by generated code when a method that must be statically
+/// resolved cannot be found.
+void throwNoSuchMethod(obj, name, arguments, expectedArgumentNames) {
+  Symbol memberName = new _symbol_dev.Symbol.unvalidated(name);
+  throw new NoSuchMethodError(obj, memberName, arguments,
+      new Map<Symbol, dynamic>(), expectedArgumentNames);
+}
+
+/// Called by generated code when a static field's initializer references the
+/// field that is currently being initialized.
+void throwCyclicInit(String staticName) {
+  throw new CyclicInitializationError(staticName);
+}
+
+/// Error thrown when a runtime error occurs.
+class RuntimeError extends Error {
+  final message;
+  RuntimeError(this.message);
+  String toString() => 'RuntimeError: $message';
+}
+
+class DeferredNotLoadedError extends Error implements NoSuchMethodError {
+  String libraryName;
+
+  DeferredNotLoadedError(this.libraryName);
+
+  String toString() {
+    return 'Deferred library $libraryName was not loaded.';
+  }
+}
+
+// TODO(ahe): Remove this class and call noSuchMethod instead.
+class UnimplementedNoSuchMethodError extends Error
+    implements NoSuchMethodError {
+  final String _message;
+
+  UnimplementedNoSuchMethodError(this._message);
+
+  String toString() => 'Unsupported operation: $_message';
+}
+
+/// Creates a random number with 64 bits of randomness.
+///
+/// This will be truncated to the 53 bits available in a double.
+int random64() {
+  // TODO(lrn): Use a secure random source.
+  int int32a = JS('int', '(Math.random() * 0x100000000) >>> 0');
+  int int32b = JS('int', '(Math.random() * 0x100000000) >>> 0');
+  return int32a + int32b * 0x100000000;
+}
+
+String jsonEncodeNative(String string) {
+  return JS('String', 'JSON.stringify(#)', string);
+}
+
+/// Returns a property name for placing data on JavaScript objects shared
+/// between DOM isolates.  This happens when multiple programs are loaded in the
+/// same JavaScript context (i.e. page).  The name is based on [name] but with
+/// an additional part that is unique for each isolate.
+///
+/// The form of the name is '___dart_$name_$id'.
+String getIsolateAffinityTag(String name) {
+  var isolateTagGetter = JS_EMBEDDED_GLOBAL('', GET_ISOLATE_TAG);
+  return JS('String', '#(#)', isolateTagGetter, name);
+}
+
+typedef Future<Null> LoadLibraryFunctionType();
+
+LoadLibraryFunctionType _loadLibraryWrapper(String loadId) {
+  return () => loadDeferredLibrary(loadId);
+}
+
+final Map<String, Future<Null>> _loadingLibraries = <String, Future<Null>>{};
+final Set<String> _loadedLibraries = new Set<String>();
+
+/// Events used to diagnose failures from deferred loading requests.
+final List<String> _eventLog = <String>[];
+
+typedef void DeferredLoadCallback();
+
+// Function that will be called every time a new deferred import is loaded.
+DeferredLoadCallback deferredLoadHook;
+
+Future<Null> loadDeferredLibrary(String loadId) {
+  // For each loadId there is a list of parts to load. The parts are represented
+  // by an index. There are two arrays, one that maps the index into a Uri and
+  // another that maps the index to a hash.
+  var partsMap = JS_EMBEDDED_GLOBAL('', DEFERRED_LIBRARY_PARTS);
+  List indexes = JS('JSExtendableArray|Null', '#[#]', partsMap, loadId);
+  if (indexes == null) return new Future.value(null);
+  List<String> uris = <String>[];
+  List<String> hashes = <String>[];
+  List index2uri = JS_EMBEDDED_GLOBAL('JSArray', DEFERRED_PART_URIS);
+  List index2hash = JS_EMBEDDED_GLOBAL('JSArray', DEFERRED_PART_HASHES);
+  for (int i = 0; i < indexes.length; i++) {
+    int index = JS('int', '#[#]', indexes, i);
+    uris.add(JS('String', '#[#]', index2uri, index));
+    hashes.add(JS('String', '#[#]', index2hash, index));
+  }
+
+  int total = hashes.length;
+  assert(total == uris.length);
+  List<bool> waitingForLoad = new List.filled(total, true);
+  int nextHunkToInitialize = 0;
+  var isHunkLoaded = JS_EMBEDDED_GLOBAL('', IS_HUNK_LOADED);
+  var isHunkInitialized = JS_EMBEDDED_GLOBAL('', IS_HUNK_INITIALIZED);
+  var initializer = JS_EMBEDDED_GLOBAL('', INITIALIZE_LOADED_HUNK);
+
+  void initializeSomeLoadedHunks() {
+    for (int i = nextHunkToInitialize; i < total; ++i) {
+      // A hunk is initialized only if all the preceeding hunks have been
+      // initialized.
+      if (waitingForLoad[i]) return;
+      nextHunkToInitialize++;
+
+      // It is possible for a hash to be repeated. This happens when two
+      // different parts both end up empty. Checking in the loop rather than
+      // pre-filtering prevents duplicate hashes leading to duplicated
+      // initializations.
+      // TODO(29572): Merge small parts.
+      // TODO(29635): Remove duplicate parts from tables and output files.
+      var uri = uris[i];
+      var hash = hashes[i];
+      if (JS('bool', '#(#)', isHunkInitialized, hash)) {
+        _eventLog.add(' - already initialized: $uri ($hash)');
+        continue;
+      }
+      // On strange scenarios, e.g. if js encounters parse errors, we might get
+      // an "success" callback on the script load but the hunk will be null.
+      if (JS('bool', '#(#)', isHunkLoaded, hash)) {
+        _eventLog.add(' - initialize: $uri ($hash)');
+        JS('void', '#(#)', initializer, hash);
+      } else {
+        _eventLog.add(' - missing hunk: $uri ($hash)');
+        throw new DeferredLoadException("Loading ${uris[i]} failed: "
+            "the code with hash '${hash}' was not loaded.\n"
+            "event log:\n${_eventLog.join("\n")}\n");
+      }
+    }
+  }
+
+  Future loadAndInitialize(int i) {
+    if (JS('bool', '#(#)', isHunkLoaded, hashes[i])) {
+      waitingForLoad[i] = false;
+      return new Future.value();
+    }
+    return _loadHunk(uris[i]).then((_) {
+      waitingForLoad[i] = false;
+      initializeSomeLoadedHunks();
+    });
+  }
+
+  return Future.wait(new List.generate(total, loadAndInitialize)).then((_) {
+    initializeSomeLoadedHunks();
+    // At this point all hunks have been loaded, so there should be no pending
+    // initializations to do.
+    assert(nextHunkToInitialize == total);
+    bool updated = _loadedLibraries.add(loadId);
+    if (updated && deferredLoadHook != null) {
+      deferredLoadHook();
+    }
+  });
+}
+
+/// The `nonce` value on the current script used for strict-CSP, if any.
+String _cspNonce = _computeCspNonce();
+
+String _computeCspNonce() {
+  var currentScript = JS_EMBEDDED_GLOBAL('', CURRENT_SCRIPT);
+  if (currentScript == null) return null;
+  String nonce = JS('String|Null', '#.nonce', currentScript);
+  return (nonce != null && nonce != '')
+      ? nonce
+      : JS('String|Null', '#.getAttribute("nonce")', currentScript);
+}
+
+/// The 'crossOrigin' value on the current script used for CORS, if any.
+String _crossOrigin = _computeCrossOrigin();
+
+String _computeCrossOrigin() {
+  var currentScript = JS_EMBEDDED_GLOBAL('', CURRENT_SCRIPT);
+  if (currentScript == null) return null;
+  return JS('String|Null', '#.crossOrigin', currentScript);
+}
+
+/// Returns true if we are currently in a worker context.
+bool _isWorker() {
+  requiresPreamble();
+  return JS('', '!self.window && !!self.postMessage');
+}
+
+/// The src url for the script tag that loaded this code.
+String thisScript = _computeThisScript();
+
+/// The src url for the script tag that loaded this function.
+///
+/// Used to create JavaScript workers and load deferred libraries.
+String _computeThisScript() {
+  var currentScript = JS_EMBEDDED_GLOBAL('', CURRENT_SCRIPT);
+  if (currentScript != null) {
+    return JS('String', 'String(#.src)', currentScript);
+  }
+  // A worker has no script tag - so get an url from a stack-trace.
+  if (_isWorker()) return _computeThisScriptFromTrace();
+  // An isolate that doesn't support workers, but doesn't have a
+  // currentScript either. This is most likely a Chrome extension.
+  return null;
+}
+
+String _computeThisScriptFromTrace() {
+  var stack = JS('String|Null', 'new Error().stack');
+  if (stack == null) {
+    // According to Internet Explorer documentation, the stack
+    // property is not set until the exception is thrown. The stack
+    // property was not provided until IE10.
+    stack = JS(
+        'String|Null',
+        '(function() {'
+            'try { throw new Error() } catch(e) { return e.stack }'
+            '})()');
+    if (stack == null) throw new UnsupportedError('No stack trace');
+  }
+  var pattern, matches;
+
+  // This pattern matches V8, Chrome, and Internet Explorer stack
+  // traces that look like this:
+  // Error
+  //     at methodName (URI:LINE:COLUMN)
+  pattern = JS('', r'new RegExp("^ *at [^(]*\\((.*):[0-9]*:[0-9]*\\)$", "m")');
+
+  matches = JS('JSExtendableArray|Null', '#.match(#)', stack, pattern);
+  if (matches != null) return JS('String', '#[1]', matches);
+
+  // This pattern matches Firefox stack traces that look like this:
+  // methodName@URI:LINE
+  pattern = JS('', r'new RegExp("^[^@]*@(.*):[0-9]*$", "m")');
+
+  matches = JS('JSExtendableArray|Null', '#.match(#)', stack, pattern);
+  if (matches != null) return JS('String', '#[1]', matches);
+
+  throw new UnsupportedError('Cannot extract URI from "$stack"');
+}
+
+Future<Null> _loadHunk(String hunkName) {
+  Future<Null> future = _loadingLibraries[hunkName];
+  _eventLog.add(' - _loadHunk: $hunkName');
+  if (future != null) {
+    _eventLog.add('reuse: $hunkName');
+    return future.then((_) => null);
+  }
+
+  String uri = thisScript;
+
+  int index = uri.lastIndexOf('/');
+  uri = '${uri.substring(0, index + 1)}$hunkName';
+  _eventLog.add(' - download: $hunkName from $uri');
+
+  var deferredLibraryLoader = JS('', 'self.dartDeferredLibraryLoader');
+  Completer<Null> completer = new Completer<Null>();
+
+  void success() {
+    _eventLog.add(' - download success: $hunkName');
+    completer.complete(null);
+  }
+
+  void failure(error, String context, StackTrace stackTrace) {
+    _eventLog.add(' - download failed: $hunkName (context: $context)');
+    _loadingLibraries[hunkName] = null;
+    stackTrace ??= StackTrace.current;
+    completer.completeError(
+        new DeferredLoadException('Loading $uri failed: $error\n'
+            'event log:\n${_eventLog.join("\n")}\n'),
+        stackTrace);
+  }
+
+  var jsSuccess = convertDartClosureToJS(success, 0);
+  var jsFailure = convertDartClosureToJS((error) {
+    failure(unwrapException(error), 'js-failure-wrapper',
+        getTraceFromException(error));
+  }, 1);
+
+  if (JS('bool', 'typeof # === "function"', deferredLibraryLoader)) {
+    try {
+      JS('void', '#(#, #, #)', deferredLibraryLoader, uri, jsSuccess,
+          jsFailure);
+    } catch (error, stackTrace) {
+      failure(error, "invoking dartDeferredLibraryLoader hook", stackTrace);
+    }
+  } else if (_isWorker()) {
+    // We are in a web worker. Load the code with an XMLHttpRequest.
+    int index = uri.lastIndexOf('/');
+    uri = '${uri.substring(0, index + 1)}$hunkName';
+    var xhr = JS('var', 'new XMLHttpRequest()');
+    JS('void', '#.open("GET", #)', xhr, uri);
+    JS(
+        'void',
+        '#.addEventListener("load", #, false)',
+        xhr,
+        convertDartClosureToJS((event) {
+          int status = JS('int', '#.status', xhr);
+          if (status != 200) {
+            failure('Request status: $status', 'worker xhr', null);
+          }
+          String code = JS('String', '#.responseText', xhr);
+          try {
+            // Create a new function to avoid getting access to current function
+            // context.
+            JS('void', '(new Function(#))()', code);
+            success();
+          } catch (error, stackTrace) {
+            failure(error, 'evaluating the code in worker xhr', stackTrace);
+          }
+        }, 1));
+
+    JS('void', '#.addEventListener("error", #, false)', xhr, (e) {
+      failure(e, 'xhr error handler', null);
+    });
+    JS('void', '#.addEventListener("abort", #, false)', xhr, (e) {
+      failure(e, 'xhr abort handler', null);
+    });
+    JS('void', '#.send()', xhr);
+  } else {
+    // We are in a dom-context.
+    // Inject a script tag.
+    var script = JS('', 'document.createElement("script")');
+    JS('', '#.type = "text/javascript"', script);
+    JS('', '#.src = #', script, uri);
+    if (_cspNonce != null && _cspNonce != '') {
+      JS('', '#.nonce = #', script, _cspNonce);
+      JS('', '#.setAttribute("nonce", #)', script, _cspNonce);
+    }
+    if (_crossOrigin != null && _crossOrigin != '') {
+      JS('', '#.crossOrigin = #', script, _crossOrigin);
+    }
+    JS('', '#.addEventListener("load", #, false)', script, jsSuccess);
+    JS('', '#.addEventListener("error", #, false)', script, jsFailure);
+    JS('', 'document.body.appendChild(#)', script);
+  }
+  _loadingLibraries[hunkName] = completer.future;
+  return completer.future;
+}
+
+class MainError extends Error implements NoSuchMethodError {
+  final String _message;
+
+  MainError(this._message);
+
+  String toString() => 'NoSuchMethodError: $_message';
+}
+
+void missingMain() {
+  throw new MainError("No top-level function named 'main'.");
+}
+
+void badMain() {
+  throw new MainError("'main' is not a function.");
+}
+
+void mainHasTooManyParameters() {
+  throw new MainError("'main' expects too many parameters.");
+}
+
+class _AssertionError extends AssertionError {
+  _AssertionError(Object message) : super(message);
+
+  String toString() => "Assertion failed: " + Error.safeToString(message);
+}
+
+// [_UnreachableError] is a separate class because we always resolve
+// [assertUnreachable] and want to reduce the impact of resolving possibly
+// unneeded code.
+class _UnreachableError extends AssertionError {
+  _UnreachableError();
+  String toString() => 'Assertion failed: Reached dead code';
+}
+
+@pragma('dart2js:noInline')
+void assertUnreachable() {
+  throw new _UnreachableError();
+}
+
+// Hook to register new global object if necessary.
+// This is currently a no-op in dart2js.
+void registerGlobalObject(object) {}
+
+// Hook to register new browser classes.
+// This is currently a no-op in dart2js.
+void applyExtension(name, nativeObject) {}
diff --git a/sdk_nnbd/lib/_internal/js_runtime/lib/js_names.dart b/sdk_nnbd/lib/_internal/js_runtime/lib/js_names.dart
new file mode 100644
index 0000000..cb4aa0e
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_runtime/lib/js_names.dart
@@ -0,0 +1,167 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library dart._js_names;
+
+import 'dart:_js_embedded_names'
+    show JsGetName, MANGLED_GLOBAL_NAMES, MANGLED_NAMES;
+
+import 'dart:_foreign_helper' show JS, JS_EMBEDDED_GLOBAL, JS_GET_NAME;
+
+import 'dart:_js_helper' show JsCache, NoInline;
+
+import 'dart:_interceptors' show JSArray;
+
+/// No-op method that is called to inform the compiler that unmangled named
+/// must be preserved.
+preserveNames() {}
+
+/// A map from mangled names to "reflective" names, that is, unmangled names
+/// with some additional information, such as, number of required arguments.
+/// This map is for mangled names used as instance members.
+final _LazyMangledNamesMap mangledNames = new _LazyMangledInstanceNamesMap(
+    JS_EMBEDDED_GLOBAL('=Object', MANGLED_NAMES));
+
+/// A map from "reflective" names to mangled names (the reverse of
+/// [mangledNames]).
+final _LazyReflectiveNamesMap reflectiveNames = new _LazyReflectiveNamesMap(
+    JS_EMBEDDED_GLOBAL('=Object', MANGLED_NAMES), true);
+
+/// A map from mangled names to "reflective" names (see [mangledNames]).  This
+/// map is for globals, that is, static and top-level members.
+final _LazyMangledNamesMap mangledGlobalNames = new _LazyMangledNamesMap(
+    JS_EMBEDDED_GLOBAL('=Object', MANGLED_GLOBAL_NAMES));
+
+/// A map from "reflective" names to mangled names (the reverse of
+/// [mangledGlobalNames]).
+final _LazyReflectiveNamesMap reflectiveGlobalNames =
+    new _LazyReflectiveNamesMap(
+        JS_EMBEDDED_GLOBAL('=Object', MANGLED_GLOBAL_NAMES), false);
+
+/// Implements a mapping from mangled names to their reflective counterparts.
+/// The propertiy names of [_jsMangledNames] are the mangled names, and the
+/// values are the "reflective" names.
+class _LazyMangledNamesMap {
+  /// [_jsMangledNames] is a JavaScript object literal.
+  var _jsMangledNames;
+
+  _LazyMangledNamesMap(this._jsMangledNames);
+
+  String operator [](String key) {
+    var result = JS('var', '#[#]', _jsMangledNames, key);
+    // Filter out all non-string values to protect against polution from
+    // ancillary fields in [_jsMangledNames].
+    bool filter = JS('bool', 'typeof # !== "string"', result);
+    // To ensure that the inferrer sees that result is a String, we explicitly
+    // give it a better type here.
+    return filter ? null : JS('String', '#', result);
+  }
+}
+
+/// Extends [_LazyMangledNamesMap] with additional support for adding mappings
+/// from mangled setter names to their reflective counterpart by rewriting a
+/// corresponding entry for a getter name, if it exists.
+class _LazyMangledInstanceNamesMap extends _LazyMangledNamesMap {
+  _LazyMangledInstanceNamesMap(_jsMangledNames) : super(_jsMangledNames);
+
+  String operator [](String key) {
+    String result = super[key];
+    String setterPrefix = JS_GET_NAME(JsGetName.SETTER_PREFIX);
+    if (result == null && key.startsWith(setterPrefix)) {
+      String getterPrefix = JS_GET_NAME(JsGetName.GETTER_PREFIX);
+      int setterPrefixLength = setterPrefix.length;
+
+      // Generate the setter name from the getter name.
+      key = '$getterPrefix${key.substring(setterPrefixLength)}';
+      result = super[key];
+      return (result != null) ? "${result}=" : null;
+    }
+    return result;
+  }
+}
+
+/// Implements the inverse of [_LazyMangledNamesMap]. As it would be too
+/// expensive to search the mangled names map for a value that corresponds to
+/// the lookup key on each invocation, we compute the full mapping in demand
+/// and cache it. The cache is invalidated when the underlying [_jsMangledNames]
+/// object changes its length. This condition is sufficient as the name mapping
+/// can only grow over time.
+/// When [_isInstance] is true, we also apply the inverse of the setter/getter
+/// name conversion implemented by [_LazyMangledInstanceNamesMap].
+class _LazyReflectiveNamesMap {
+  /// [_jsMangledNames] is a JavaScript object literal.
+  final _jsMangledNames;
+  final bool _isInstance;
+  int _cacheLength = 0;
+  Map<String, String> _cache;
+
+  _LazyReflectiveNamesMap(this._jsMangledNames, this._isInstance);
+
+  Map<String, String> _updateReflectiveNames() {
+    preserveNames();
+    Map<String, String> result = <String, String>{};
+    List keys = JS('List', 'Object.keys(#)', _jsMangledNames);
+    for (String key in keys) {
+      var reflectiveName = JS('var', '#[#]', _jsMangledNames, key);
+      // Filter out all non-string values to protect against polution from
+      // ancillary fields in [_jsMangledNames].
+      bool filter = JS('bool', 'typeof # !== "string"', reflectiveName);
+      if (filter) continue;
+      result[reflectiveName] = JS('String', '#', key);
+
+      String getterPrefix = JS_GET_NAME(JsGetName.GETTER_PREFIX);
+      if (_isInstance && key.startsWith(getterPrefix)) {
+        int getterPrefixLength = getterPrefix.length;
+        String setterPrefix = JS_GET_NAME(JsGetName.SETTER_PREFIX);
+        result['$reflectiveName='] =
+            '$setterPrefix${key.substring(getterPrefixLength)}';
+      }
+    }
+    return result;
+  }
+
+  int get _jsMangledNamesLength =>
+      JS('int', 'Object.keys(#).length', _jsMangledNames);
+
+  String operator [](String key) {
+    if (_cache == null || _jsMangledNamesLength != _cacheLength) {
+      _cache = _updateReflectiveNames();
+      _cacheLength = _jsMangledNamesLength;
+    }
+    return _cache[key];
+  }
+}
+
+@pragma('dart2js:noInline')
+List extractKeys(victim) {
+  var result = JS('', '# ? Object.keys(#) : []', victim, victim);
+  return new JSArray.markFixed(result);
+}
+
+/// Returns the (global) unmangled version of [name].
+///
+/// Normally, you should use [mangledGlobalNames] directly, but this method
+/// doesn't tell the compiler to preserve names. So this method only returns a
+/// non-null value if some other component has made the compiler preserve names.
+///
+/// This is used, for example, to return unmangled names from TypeImpl.toString
+/// *if* names are being preserved for other reasons (use of dart:mirrors, for
+/// example).
+String unmangleGlobalNameIfPreservedAnyways(String name) {
+  var names = JS_EMBEDDED_GLOBAL('', MANGLED_GLOBAL_NAMES);
+  return JS('String|Null', '#', JsCache.fetch(names, name));
+}
+
+String unmangleAllIdentifiersIfPreservedAnyways(String str) {
+  return JS(
+      'String',
+      r'''
+        (function(str, names) {
+          return str.replace(
+              /[^<,> ]+/g,
+              function(m) { return names[m] || m; });
+        })(#, #)''',
+      str,
+      JS_EMBEDDED_GLOBAL('', MANGLED_GLOBAL_NAMES));
+}
diff --git a/sdk_nnbd/lib/_internal/js_runtime/lib/js_number.dart b/sdk_nnbd/lib/_internal/js_runtime/lib/js_number.dart
new file mode 100644
index 0000000..918c1ba
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_runtime/lib/js_number.dart
@@ -0,0 +1,707 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of _interceptors;
+
+/// The super interceptor class for [JSInt] and [JSDouble]. The compiler
+/// recognizes this class as an interceptor, and changes references to
+/// [:this:] to actually use the receiver of the method, which is
+/// generated as an extra argument added to each member.
+///
+/// Note that none of the methods here delegate to a method defined on JSInt or
+/// JSDouble.  This is exploited in [tryComputeConstantInterceptor].
+class JSNumber extends Interceptor implements double {
+  const JSNumber();
+
+  int compareTo(num b) {
+    if (b is! num) throw argumentErrorValue(b);
+    if (this < b) {
+      return -1;
+    } else if (this > b) {
+      return 1;
+    } else if (this == b) {
+      if (this == 0) {
+        bool bIsNegative = b.isNegative;
+        if (isNegative == bIsNegative) return 0;
+        if (isNegative) return -1;
+        return 1;
+      }
+      return 0;
+    } else if (isNaN) {
+      if (b.isNaN) {
+        return 0;
+      }
+      return 1;
+    } else {
+      return -1;
+    }
+  }
+
+  bool get isNegative => (this == 0) ? (1 / this) < 0 : this < 0;
+
+  bool get isNaN => JS(
+      'returns:bool;effects:none;depends:none;throws:never;gvn:true',
+      r'isNaN(#)',
+      this);
+
+  bool get isInfinite {
+    return JS('bool', r'# == (1/0)', this) || JS('bool', r'# == (-1/0)', this);
+  }
+
+  bool get isFinite => JS(
+      'returns:bool;effects:none;depends:none;throws:never;gvn:true',
+      r'isFinite(#)',
+      this);
+
+  JSNumber remainder(num b) {
+    if (b is! num) throw argumentErrorValue(b);
+    return JS('num', r'# % #', this, b);
+  }
+
+  // Use invoke_dynamic_specializer instead of inlining.
+  @pragma('dart2js:noInline')
+  JSNumber abs() => JS(
+      'returns:num;effects:none;depends:none;throws:never;gvn:true',
+      r'Math.abs(#)',
+      this);
+
+  JSNumber get sign => this > 0 ? 1 : this < 0 ? -1 : this;
+
+  static const int _MIN_INT32 = -0x80000000;
+  static const int _MAX_INT32 = 0x7FFFFFFF;
+
+  int toInt() {
+    if (this >= _MIN_INT32 && this <= _MAX_INT32) {
+      // 0 and -0.0 handled here.
+      return JS('int', '# | 0', this);
+    }
+    if (JS('bool', r'isFinite(#)', this)) {
+      return JS('int', r'# + 0', truncateToDouble()); // Converts -0.0 to +0.0.
+    }
+    // [this] is either NaN, Infinity or -Infinity.
+    throw new UnsupportedError(JS('String', '"" + # + ".toInt()"', this));
+  }
+
+  int truncate() => toInt();
+
+  int ceil() {
+    if (this >= 0) {
+      if (this <= _MAX_INT32) {
+        int truncated = JS('int', '# | 0', this); // converts -0.0 to 0.
+        return this == truncated ? truncated : truncated + 1;
+      }
+    } else {
+      if (this >= _MIN_INT32) {
+        return JS('int', '# | 0', this);
+      }
+    }
+    var d = JS('num', 'Math.ceil(#)', this);
+    if (JS('bool', r'isFinite(#)', d)) {
+      return JS('int', r'#', d);
+    }
+    // [this] is either NaN, Infinity or -Infinity.
+    throw new UnsupportedError(JS('String', '"" + # + ".ceil()"', this));
+  }
+
+  int floor() {
+    if (this >= 0) {
+      if (this <= _MAX_INT32) {
+        return JS('int', '# | 0', this);
+      }
+    } else {
+      if (this >= _MIN_INT32) {
+        int truncated = JS('int', '# | 0', this);
+        return this == truncated ? truncated : truncated - 1;
+      }
+    }
+    var d = JS('num', 'Math.floor(#)', this);
+    if (JS('bool', r'isFinite(#)', d)) {
+      return JS('int', r'#', d);
+    }
+    // [this] is either NaN, Infinity or -Infinity.
+    throw new UnsupportedError(JS('String', '"" + # + ".floor()"', this));
+  }
+
+  int round() {
+    if (this > 0) {
+      // This path excludes the special cases -0.0, NaN and -Infinity, leaving
+      // only +Infinity, for which a direct test is faster than [isFinite].
+      if (JS('bool', r'# !== (1/0)', this)) {
+        return JS('int', r'Math.round(#)', this);
+      }
+    } else if (JS('bool', '# > (-1/0)', this)) {
+      // This test excludes NaN and -Infinity, leaving only -0.0.
+      //
+      // Subtraction from zero rather than negation forces -0.0 to 0.0 so code
+      // inside Math.round and code to handle result never sees -0.0, which on
+      // some JavaScript VMs can be a slow path.
+      return JS('int', r'0 - Math.round(0 - #)', this);
+    }
+    // [this] is either NaN, Infinity or -Infinity.
+    throw new UnsupportedError(JS('String', '"" + # + ".round()"', this));
+  }
+
+  double ceilToDouble() => JS('num', r'Math.ceil(#)', this);
+
+  double floorToDouble() => JS('num', r'Math.floor(#)', this);
+
+  double roundToDouble() {
+    if (this < 0) {
+      return JS('num', r'-Math.round(-#)', this);
+    } else {
+      return JS('num', r'Math.round(#)', this);
+    }
+  }
+
+  double truncateToDouble() => this < 0 ? ceilToDouble() : floorToDouble();
+
+  num clamp(lowerLimit, upperLimit) {
+    if (lowerLimit is! num) throw argumentErrorValue(lowerLimit);
+    if (upperLimit is! num) throw argumentErrorValue(upperLimit);
+    if (lowerLimit.compareTo(upperLimit) > 0) {
+      throw argumentErrorValue(lowerLimit);
+    }
+    if (this.compareTo(lowerLimit) < 0) return lowerLimit;
+    if (this.compareTo(upperLimit) > 0) return upperLimit;
+    return this;
+  }
+
+  // The return type is intentionally omitted to avoid type checker warnings
+  // from assigning JSNumber to double.
+  toDouble() => this;
+
+  String toStringAsFixed(int fractionDigits) {
+    checkInt(fractionDigits);
+    if (fractionDigits < 0 || fractionDigits > 20) {
+      throw new RangeError.range(fractionDigits, 0, 20, 'fractionDigits');
+    }
+    String result = JS('String', r'#.toFixed(#)', this, fractionDigits);
+    if (this == 0 && isNegative) return '-$result';
+    return result;
+  }
+
+  String toStringAsExponential([int fractionDigits]) {
+    String result;
+    if (fractionDigits != null) {
+      checkInt(fractionDigits);
+      if (fractionDigits < 0 || fractionDigits > 20) {
+        throw new RangeError.range(fractionDigits, 0, 20, 'fractionDigits');
+      }
+      result = JS('String', r'#.toExponential(#)', this, fractionDigits);
+    } else {
+      result = JS('String', r'#.toExponential()', this);
+    }
+    if (this == 0 && isNegative) return '-$result';
+    return result;
+  }
+
+  String toStringAsPrecision(int precision) {
+    checkInt(precision);
+    if (precision < 1 || precision > 21) {
+      throw new RangeError.range(precision, 1, 21, 'precision');
+    }
+    String result = JS('String', r'#.toPrecision(#)', this, precision);
+    if (this == 0 && isNegative) return '-$result';
+    return result;
+  }
+
+  String toRadixString(int radix) {
+    checkInt(radix);
+    if (radix < 2 || radix > 36) {
+      throw new RangeError.range(radix, 2, 36, 'radix');
+    }
+    String result = JS('String', r'#.toString(#)', this, radix);
+    const int rightParenCode = 0x29;
+    if (result.codeUnitAt(result.length - 1) != rightParenCode) {
+      return result;
+    }
+    return _handleIEtoString(result);
+  }
+
+  static String _handleIEtoString(String result) {
+    // Result is probably IE's untraditional format for large numbers,
+    // e.g., "8.0000000000008(e+15)" for 0x8000000000000800.toString(16).
+    var match = JS('JSArray|Null',
+        r'/^([\da-z]+)(?:\.([\da-z]+))?\(e\+(\d+)\)$/.exec(#)', result);
+    if (match == null) {
+      // Then we don't know how to handle it at all.
+      throw new UnsupportedError('Unexpected toString result: $result');
+    }
+    result = JS('String', '#', match[1]);
+    int exponent = JS('int', '+#', match[3]);
+    if (match[2] != null) {
+      result = JS('String', '# + #', result, match[2]);
+      exponent -= JS('int', '#.length', match[2]);
+    }
+    return result + '0' * exponent;
+  }
+
+  // Note: if you change this, also change the function [S].
+  String toString() {
+    if (this == 0 && JS('bool', '(1 / #) < 0', this)) {
+      return '-0.0';
+    } else {
+      return JS('String', r'"" + (#)', this);
+    }
+  }
+
+  int get hashCode {
+    int intValue = JS('int', '# | 0', this);
+    // Fast exit for integers in signed 32-bit range. Masking converts -0.0 to 0
+    // and ensures that result fits in JavaScript engine's Smi range.
+    if (this == intValue) return 0x1FFFFFFF & intValue;
+
+    // We would like to access the exponent and mantissa as integers but there
+    // are no JavaScript operations that do this, so use log2-floor-pow-divide
+    // to extract the values.
+    num absolute = JS('num', 'Math.abs(#)', this);
+    num lnAbsolute = JS('num', 'Math.log(#)', absolute);
+    num log2 = lnAbsolute / ln2;
+    // Floor via '# | 0' converts NaN to zero so the final result is not NaN.
+    int floorLog2 = JS('int', '# | 0', log2);
+    num factor = JS('num', 'Math.pow(2, #)', floorLog2);
+    num scaled = absolute < 1 ? absolute / factor : factor / absolute;
+    // [scaled] is in the range [0.5, 1].
+
+    // Multiply and truncate to pick up all the mantissa bits. Multiplying by
+    // 0x20000000000000 (which has 53 zero bits) converts the mantissa into an
+    // integer. There are interesting subsets where all the bit variance is in
+    // the most significant bits of the mantissa (e.g. 0.5, 0.625, 0.75), so we
+    // need to mix in the most significant bits. We do this by scaling with a
+    // constant that has many bits set to use the multiplier to mix in bits from
+    // all over the mantissa into low positions.
+    num rescaled1 = scaled * 0x20000000000000;
+    num rescaled2 = scaled * 0x0C95A6C285A6C9;
+    int d1 = JS('int', '# | 0', rescaled1);
+    int d2 = JS('int', '# | 0', rescaled2);
+    // Mix in exponent to distinguish e.g. 1.25 from 2.5.
+    int d3 = floorLog2;
+    int h = 0x1FFFFFFF & ((d1 + d2) * (601 * 997) + d3 * (1259));
+    return h;
+  }
+
+  JSNumber operator -() => JS('num', r'-#', this);
+
+  JSNumber operator +(num other) {
+    if (other is! num) throw argumentErrorValue(other);
+    return JS('num', '# + #', this, other);
+  }
+
+  JSNumber operator -(num other) {
+    if (other is! num) throw argumentErrorValue(other);
+    return JS('num', '# - #', this, other);
+  }
+
+  double operator /(num other) {
+    if (other is! num) throw argumentErrorValue(other);
+    return JS('num', '# / #', this, other);
+  }
+
+  JSNumber operator *(num other) {
+    if (other is! num) throw argumentErrorValue(other);
+    return JS('num', '# * #', this, other);
+  }
+
+  JSNumber operator %(num other) {
+    if (other is! num) throw argumentErrorValue(other);
+    // Euclidean Modulo.
+    num result = JS('num', r'# % #', this, other);
+    if (result == 0) return JS('num', '0'); // Make sure we don't return -0.0.
+    if (result > 0) return result;
+    if (JS('num', '#', other) < 0) {
+      return result - JS('num', '#', other);
+    } else {
+      return result + JS('num', '#', other);
+    }
+  }
+
+  bool _isInt32(value) => JS('bool', '(# | 0) === #', value, value);
+
+  int operator ~/(num other) {
+    if (other is! num) throw argumentErrorValue(other);
+    if (false) _tdivFast(other); // Ensure resolution.
+    if (_isInt32(this)) {
+      if (other >= 1 || other < -1) {
+        return JS('int', r'(# / #) | 0', this, other);
+      }
+    }
+    return _tdivSlow(other);
+  }
+
+  int _tdivFast(num other) {
+    // [other] is known to be a number outside the range [-1, 1).
+    return _isInt32(this)
+        ? JS('int', r'(# / #) | 0', this, other)
+        : _tdivSlow(other);
+  }
+
+  int _tdivSlow(num other) {
+    var quotient = JS('num', r'# / #', this, other);
+    if (quotient >= _MIN_INT32 && quotient <= _MAX_INT32) {
+      // This path includes -0.0 and +0.0.
+      return JS('int', '# | 0', quotient);
+    }
+    if (quotient > 0) {
+      // This path excludes the special cases -0.0, NaN and -Infinity, leaving
+      // only +Infinity, for which a direct test is faster than [isFinite].
+      if (JS('bool', r'# !== (1/0)', quotient)) {
+        return JS('int', r'Math.floor(#)', quotient);
+      }
+    } else if (JS('bool', '# > (-1/0)', quotient)) {
+      // This test excludes NaN and -Infinity.
+      return JS('int', r'Math.ceil(#)', quotient);
+    }
+
+    // [quotient] is either NaN, Infinity or -Infinity.
+    throw new UnsupportedError(
+        'Result of truncating division is $quotient: $this ~/ $other');
+  }
+
+  // TODO(ngeoffray): Move the bit operations below to [JSInt] and
+  // make them take an int. Because this will make operations slower,
+  // we define these methods on number for now but we need to decide
+  // the grain at which we do the type checks.
+
+  num operator <<(num other) {
+    if (other is! num) throw argumentErrorValue(other);
+    if (JS('num', '#', other) < 0) throw argumentErrorValue(other);
+    return _shlPositive(other);
+  }
+
+  num _shlPositive(num other) {
+    // JavaScript only looks at the last 5 bits of the shift-amount. Shifting
+    // by 33 is hence equivalent to a shift by 1.
+    return JS('bool', r'# > 31', other)
+        ? 0
+        : JS('JSUInt32', r'(# << #) >>> 0', this, other);
+  }
+
+  num operator >>(num other) {
+    if (false) _shrReceiverPositive(other);
+    if (other is! num) throw argumentErrorValue(other);
+    if (JS('num', '#', other) < 0) throw argumentErrorValue(other);
+    return _shrOtherPositive(other);
+  }
+
+  num _shrOtherPositive(num other) {
+    return JS('num', '#', this) > 0
+        ? _shrBothPositive(other)
+        // For negative numbers we just clamp the shift-by amount.
+        // `this` could be negative but not have its 31st bit set.
+        // The ">>" would then shift in 0s instead of 1s. Therefore
+        // we cannot simply return 0xFFFFFFFF.
+        : JS('JSUInt32', r'(# >> #) >>> 0', this, other > 31 ? 31 : other);
+  }
+
+  num _shrReceiverPositive(num other) {
+    if (JS('num', '#', other) < 0) throw argumentErrorValue(other);
+    return _shrBothPositive(other);
+  }
+
+  num _shrBothPositive(num other) {
+    return JS('bool', r'# > 31', other)
+        // JavaScript only looks at the last 5 bits of the shift-amount. In JS
+        // shifting by 33 is hence equivalent to a shift by 1. Shortcut the
+        // computation when that happens.
+        ? 0
+        // Given that `this` is positive we must not use '>>'. Otherwise a
+        // number that has the 31st bit set would be treated as negative and
+        // shift in ones.
+        : JS('JSUInt32', r'# >>> #', this, other);
+  }
+
+  num operator &(num other) {
+    if (other is! num) throw argumentErrorValue(other);
+    return JS('JSUInt32', r'(# & #) >>> 0', this, other);
+  }
+
+  num operator |(num other) {
+    if (other is! num) throw argumentErrorValue(other);
+    return JS('JSUInt32', r'(# | #) >>> 0', this, other);
+  }
+
+  num operator ^(num other) {
+    if (other is! num) throw argumentErrorValue(other);
+    return JS('JSUInt32', r'(# ^ #) >>> 0', this, other);
+  }
+
+  bool operator <(num other) {
+    if (other is! num) throw argumentErrorValue(other);
+    return JS('bool', '# < #', this, other);
+  }
+
+  bool operator >(num other) {
+    if (other is! num) throw argumentErrorValue(other);
+    return JS('bool', '# > #', this, other);
+  }
+
+  bool operator <=(num other) {
+    if (other is! num) throw argumentErrorValue(other);
+    return JS('bool', '# <= #', this, other);
+  }
+
+  bool operator >=(num other) {
+    if (other is! num) throw argumentErrorValue(other);
+    return JS('bool', '# >= #', this, other);
+  }
+
+  Type get runtimeType => num;
+}
+
+/// The interceptor class for [int]s.
+///
+/// This class implements double (indirectly through JSNumber) since in
+/// JavaScript all numbers are doubles, so while we want to treat `2.0` as an
+/// integer for some operations, its interceptor should answer `true` to `is
+/// double`.
+class JSInt extends JSNumber implements int {
+  const JSInt();
+
+  @override
+  // Use invoke_dynamic_specializer instead of inlining.
+  @pragma('dart2js:noInline')
+  JSInt abs() => JS(
+      'returns:int;effects:none;depends:none;throws:never;gvn:true',
+      r'Math.abs(#)',
+      this);
+
+  @override
+  JSInt get sign => this > 0 ? 1 : this < 0 ? -1 : this;
+
+  @override
+  JSInt operator -() => JS('int', r'-#', this);
+
+  bool get isEven => (this & 1) == 0;
+
+  bool get isOdd => (this & 1) == 1;
+
+  int toUnsigned(int width) {
+    return this & ((1 << width) - 1);
+  }
+
+  int toSigned(int width) {
+    int signMask = 1 << (width - 1);
+    return (this & (signMask - 1)) - (this & signMask);
+  }
+
+  int get bitLength {
+    JSInt nonneg = this < 0 ? -this - 1 : this;
+    int wordBits = 32;
+    while (nonneg >= 0x100000000) {
+      nonneg = nonneg ~/ 0x100000000;
+      wordBits += 32;
+    }
+    return wordBits - _clz32(nonneg);
+  }
+
+  static int _clz32(int uint32) {
+    // TODO(sra): Use `Math.clz32(uint32)` (not available on IE11).
+    return 32 - _bitCount(_spread(uint32));
+  }
+
+  // Returns pow(this, e) % m.
+  int modPow(int e, int m) {
+    if (e is! int) {
+      throw ArgumentError.value(e, 'exponent', 'not an integer');
+    }
+    if (m is! int) {
+      throw ArgumentError.value(m, 'modulus', 'not an integer');
+    }
+    if (e < 0) throw RangeError.range(e, 0, null, 'exponent');
+    if (m <= 0) throw RangeError.range(m, 1, null, 'modulus');
+    if (e == 0) return 1;
+
+    const int maxPreciseInteger = 9007199254740991;
+
+    // Reject inputs that are outside the range of integer values that can be
+    // represented precisely as a Number (double).
+    if (this < -maxPreciseInteger || this > maxPreciseInteger) {
+      throw RangeError.range(
+          this, -maxPreciseInteger, maxPreciseInteger, 'receiver');
+    }
+    if (e > maxPreciseInteger) {
+      throw RangeError.range(e, 0, maxPreciseInteger, 'exponent');
+    }
+    if (m > maxPreciseInteger) {
+      throw RangeError.range(e, 1, maxPreciseInteger, 'modulus');
+    }
+
+    // This is floor(sqrt(maxPreciseInteger)).
+    const int maxValueThatCanBeSquaredWithoutTruncation = 94906265;
+    if (m > maxValueThatCanBeSquaredWithoutTruncation) {
+      // Use BigInt version to avoid truncation in multiplications below. The
+      // 'maxPreciseInteger' check on [m] ensures that toInt() does not round.
+      return BigInt.from(this).modPow(BigInt.from(e), BigInt.from(m)).toInt();
+    }
+
+    int b = this;
+    if (b < 0 || b > m) {
+      b %= m;
+    }
+    int r = 1;
+    while (e > 0) {
+      if (e.isOdd) {
+        r = (r * b) % m;
+      }
+      e ~/= 2;
+      b = (b * b) % m;
+    }
+    return r;
+  }
+
+  // If inv is false, returns gcd(x, y).
+  // If inv is true and gcd(x, y) = 1, returns d, so that c*x + d*y = 1.
+  // If inv is true and gcd(x, y) != 1, throws Exception("Not coprime").
+  static int _binaryGcd(int x, int y, bool inv) {
+    int s = 1;
+    if (!inv) {
+      while (x.isEven && y.isEven) {
+        x ~/= 2;
+        y ~/= 2;
+        s *= 2;
+      }
+      if (y.isOdd) {
+        var t = x;
+        x = y;
+        y = t;
+      }
+    }
+    final bool ac = x.isEven;
+    int u = x;
+    int v = y;
+    int a = 1, b = 0, c = 0, d = 1;
+    do {
+      while (u.isEven) {
+        u ~/= 2;
+        if (ac) {
+          if (!a.isEven || !b.isEven) {
+            a += y;
+            b -= x;
+          }
+          a ~/= 2;
+        } else if (!b.isEven) {
+          b -= x;
+        }
+        b ~/= 2;
+      }
+      while (v.isEven) {
+        v ~/= 2;
+        if (ac) {
+          if (!c.isEven || !d.isEven) {
+            c += y;
+            d -= x;
+          }
+          c ~/= 2;
+        } else if (!d.isEven) {
+          d -= x;
+        }
+        d ~/= 2;
+      }
+      if (u >= v) {
+        u -= v;
+        if (ac) a -= c;
+        b -= d;
+      } else {
+        v -= u;
+        if (ac) c -= a;
+        d -= b;
+      }
+    } while (u != 0);
+    if (!inv) return s * v;
+    if (v != 1) throw new Exception('Not coprime');
+    if (d < 0) {
+      d += x;
+      if (d < 0) d += x;
+    } else if (d > x) {
+      d -= x;
+      if (d > x) d -= x;
+    }
+    return d;
+  }
+
+  // Returns 1/this % m, with m > 0.
+  int modInverse(int m) {
+    if (m is! int) {
+      throw new ArgumentError.value(m, 'modulus', 'not an integer');
+    }
+    if (m <= 0) throw new RangeError.range(m, 1, null, 'modulus');
+    if (m == 1) return 0;
+    int t = this;
+    if ((t < 0) || (t >= m)) t %= m;
+    if (t == 1) return 1;
+    if ((t == 0) || (t.isEven && m.isEven)) {
+      throw new Exception('Not coprime');
+    }
+    return _binaryGcd(m, t, true);
+  }
+
+  // Returns gcd of abs(this) and abs(other).
+  int gcd(int other) {
+    if (other is! int) {
+      throw new ArgumentError.value(other, 'other', 'not an integer');
+    }
+    int x = this.abs();
+    int y = other.abs();
+    if (x == 0) return y;
+    if (y == 0) return x;
+    if ((x == 1) || (y == 1)) return 1;
+    return _binaryGcd(x, y, false);
+  }
+
+  // Assumes i is <= 32-bit and unsigned.
+  static int _bitCount(int i) {
+    // See "Hacker's Delight", section 5-1, "Counting 1-Bits".
+
+    // The basic strategy is to use "divide and conquer" to
+    // add pairs (then quads, etc.) of bits together to obtain
+    // sub-counts.
+    //
+    // A straightforward approach would look like:
+    //
+    // i = (i & 0x55555555) + ((i >>  1) & 0x55555555);
+    // i = (i & 0x33333333) + ((i >>  2) & 0x33333333);
+    // i = (i & 0x0F0F0F0F) + ((i >>  4) & 0x0F0F0F0F);
+    // i = (i & 0x00FF00FF) + ((i >>  8) & 0x00FF00FF);
+    // i = (i & 0x0000FFFF) + ((i >> 16) & 0x0000FFFF);
+    //
+    // The code below removes unnecessary &'s and uses a
+    // trick to remove one instruction in the first line.
+
+    i = _shru(i, 0) - (_shru(i, 1) & 0x55555555);
+    i = (i & 0x33333333) + (_shru(i, 2) & 0x33333333);
+    i = 0x0F0F0F0F & (i + _shru(i, 4));
+    i += _shru(i, 8);
+    i += _shru(i, 16);
+    return (i & 0x0000003F);
+  }
+
+  static int _shru(int value, int shift) => JS('int', '# >>> #', value, shift);
+  static int _shrs(int value, int shift) => JS('int', '# >> #', value, shift);
+  static int _ors(int a, int b) => JS('int', '# | #', a, b);
+
+  // Assumes i is <= 32-bit
+  static int _spread(int i) {
+    i = _ors(i, _shrs(i, 1));
+    i = _ors(i, _shrs(i, 2));
+    i = _ors(i, _shrs(i, 4));
+    i = _ors(i, _shrs(i, 8));
+    i = _shru(_ors(i, _shrs(i, 16)), 0);
+    return i;
+  }
+
+  Type get runtimeType => int;
+
+  int operator ~() => JS('JSUInt32', r'(~#) >>> 0', this);
+}
+
+class JSDouble extends JSNumber implements double {
+  const JSDouble();
+  Type get runtimeType => double;
+}
+
+class JSPositiveInt extends JSInt {}
+
+class JSUInt32 extends JSPositiveInt {}
+
+class JSUInt31 extends JSUInt32 {}
diff --git a/sdk_nnbd/lib/_internal/js_runtime/lib/js_primitives.dart b/sdk_nnbd/lib/_internal/js_runtime/lib/js_primitives.dart
new file mode 100644
index 0000000..97577a0
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_runtime/lib/js_primitives.dart
@@ -0,0 +1,47 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// dart2js "primitives", that is, features that cannot be implemented without
+/// access to JavaScript features.
+library dart2js._js_primitives;
+
+import 'dart:_foreign_helper' show JS;
+
+/// This is the low-level method that is used to implement [print].  It is
+/// possible to override this function from JavaScript by defining a function in
+/// JavaScript called "dartPrint".
+///
+/// Notice that it is also possible to intercept calls to [print] from within a
+/// Dart program using zones. This means that there is no guarantee that a call
+/// to print ends in this method.
+void printString(String string) {
+  if (JS('bool', r'typeof dartPrint == "function"')) {
+    // Support overriding print from JavaScript.
+    JS('void', r'dartPrint(#)', string);
+    return;
+  }
+
+  // Inside browser or nodejs.
+  if (JS('bool', r'typeof console == "object"') &&
+      JS('bool', r'typeof console.log != "undefined"')) {
+    JS('void', r'console.log(#)', string);
+    return;
+  }
+
+  // Don't throw inside IE, the console is only defined if dev tools is open.
+  if (JS('bool', r'typeof window == "object"')) {
+    return;
+  }
+
+  // Running in d8, the V8 developer shell, or in Firefox' js-shell.
+  if (JS('bool', r'typeof print == "function"')) {
+    JS('void', r'print(#)', string);
+    return;
+  }
+
+  // This is somewhat nasty, but we don't want to drag in a bunch of
+  // dependencies to handle a situation that cannot happen. So we
+  // avoid using Dart [:throw:] and Dart [toString].
+  JS('void', 'throw "Unable to print message: " + String(#)', string);
+}
diff --git a/sdk_nnbd/lib/_internal/js_runtime/lib/js_rti.dart b/sdk_nnbd/lib/_internal/js_runtime/lib/js_rti.dart
new file mode 100644
index 0000000..fd82931
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_runtime/lib/js_rti.dart
@@ -0,0 +1,1125 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// This part contains helpers for supporting runtime type information.
+///
+/// The helper use a mixture of Dart and JavaScript objects. To indicate which
+/// is used where we adopt the scheme of using explicit type annotation for Dart
+/// objects and 'var' or omitted return type for JavaScript objects.
+///
+/// Since bool, int, and String values are represented by the same JavaScript
+/// primitives, type annotations are used for these types in all cases.
+///
+/// Several methods use a common JavaScript encoding of runtime type
+/// information.  This encoding is referred to as the type representation which
+/// is one of these:
+///  1) a JavaScript constructor for a class C: the represented type is the raw
+///     type C.
+///  2) a JavaScript array: the first entry is of type 1 and contains the
+///     subtyping flags and the substitution of the type and the rest of the
+///     array are the type arguments.
+///  3) `null`: the dynamic type.
+///  4) a JavaScript object representing the function type. For instance, it has
+///     the form {ret: rti, args: [rti], opt: [rti], named: {name: rti}} for a
+///     function with a return type, regular, optional and named arguments.
+///     Generic function types have a 'bounds' property.
+///
+/// To check subtype relations between generic classes we use a JavaScript
+/// expression that describes the necessary substitution for type arguments.
+/// Such a substitution expression can be:
+///  1) `null`, if no substituted check is necessary, because the
+///     type variables are the same or there are no type variables in the class
+///     that is checked for.
+///  2) A list expression describing the type arguments to be used in the
+///     subtype check, if the type arguments to be used in the check do not
+///     depend on the type arguments of the object.
+///  3) A function mapping the type variables of the object to be checked to a
+///     list expression. The function may also return null, which is equivalent
+///     to an array containing only null values.
+
+part of _js_helper;
+
+/// Called from generated code.
+Type createRuntimeType(rti) {
+  return new TypeImpl(rti);
+}
+
+class TypeImpl implements Type {
+  final dynamic _rti;
+  String __typeName;
+  String _unmangledName;
+  int _hashCode;
+
+  TypeImpl(this._rti);
+
+  String get _typeName => __typeName ??= runtimeTypeToString(_rti);
+
+  String toString() => _typeName;
+
+  // TODO(ahe): This is a poor hashCode as it collides with its name.
+  int get hashCode => _hashCode ??= _typeName.hashCode;
+
+  @pragma('dart2js:noInline')
+  bool operator ==(other) {
+    return (other is TypeImpl) && _typeName == other._typeName;
+  }
+}
+
+/// Represents a type variable.
+///
+/// This class holds the information needed when reflecting on generic classes
+/// and their members.
+class TypeVariable {
+  final Type owner;
+  final String name;
+  final int bound;
+
+  const TypeVariable(this.owner, this.name, this.bound);
+}
+
+getMangledTypeName(Type t) {
+  TypeImpl type = t;
+  return type._typeName;
+}
+
+/// Sets the runtime type information on [target]. [rti] is a type
+/// representation of type 4 or 5, that is, either a JavaScript array or `null`.
+///
+/// Called from generated code.
+///
+/// This is used only for marking JavaScript Arrays (JSArray) with the element
+/// type.
+// Don't inline.  Let the JS engine inline this.  The call expression is much
+// more compact that the inlined expansion.
+@pragma('dart2js:noInline')
+Object setRuntimeTypeInfo(Object target, var rti) {
+  assert(rti == null || isJsArray(rti));
+  String rtiName = JS_GET_NAME(JsGetName.RTI_NAME);
+  JS('var', r'#[#] = #', target, rtiName, rti);
+  return target;
+}
+
+/// Returns the runtime type information of [target]. The returned value is a
+/// list of type representations for the type arguments.
+///
+/// Called from generated code.
+getRuntimeTypeInfo(Object target) {
+  if (target == null) return null;
+  String rtiName = JS_GET_NAME(JsGetName.RTI_NAME);
+  return JS('var', r'#[#]', target, rtiName);
+}
+
+/// Returns the type arguments of [object] as an instance of [substitutionName].
+getRuntimeTypeArguments(interceptor, object, substitutionName) {
+  var substitution = getField(interceptor,
+      '${JS_GET_NAME(JsGetName.OPERATOR_AS_PREFIX)}$substitutionName');
+  return substitute(substitution, getRuntimeTypeInfo(object));
+}
+
+/// Returns the [index]th type argument of [target] as an instance of
+/// [substitutionName].
+///
+/// Called from generated code.
+@pragma('dart2js:noThrows')
+@pragma('dart2js:noSideEffects')
+@pragma('dart2js:noInline')
+getRuntimeTypeArgumentIntercepted(
+    interceptor, Object target, String substitutionName, int index) {
+  var arguments =
+      getRuntimeTypeArguments(interceptor, target, substitutionName);
+  return arguments == null ? null : getIndex(arguments, index);
+}
+
+/// Returns the [index]th type argument of [target] as an instance of
+/// [substitutionName].
+///
+/// Called from generated code.
+@pragma('dart2js:noThrows')
+@pragma('dart2js:noSideEffects')
+@pragma('dart2js:noInline')
+getRuntimeTypeArgument(Object target, String substitutionName, int index) {
+  var arguments = getRuntimeTypeArguments(target, target, substitutionName);
+  return arguments == null ? null : getIndex(arguments, index);
+}
+
+/// Returns the [index]th type argument of [target].
+///
+/// Called from generated code.
+@pragma('dart2js:noThrows')
+@pragma('dart2js:noSideEffects')
+@pragma('dart2js:noInline')
+getTypeArgumentByIndex(Object target, int index) {
+  var rti = getRuntimeTypeInfo(target);
+  return rti == null ? null : getIndex(rti, index);
+}
+
+/// Retrieves the class name from type information stored on the constructor
+/// of [object].
+String getClassName(var object) {
+  return rawRtiToJsConstructorName(getRawRuntimeType(getInterceptor(object)));
+}
+
+String _getRuntimeTypeAsString(var rti, List<String> genericContext) {
+  assert(isJsArray(rti));
+  String className = unminifyOrTag(rawRtiToJsConstructorName(getIndex(rti, 0)));
+  return '$className${_joinArguments(rti, 1, genericContext)}';
+}
+
+/// Returns a human-readable representation of the type representation [rti].
+///
+/// Called from generated code.
+@pragma('dart2js:noInline')
+String runtimeTypeToString(var rti) {
+  return _runtimeTypeToString(rti, null);
+}
+
+String _runtimeTypeToString(var rti, List<String> genericContext) {
+  if (isDartDynamicTypeRti(rti)) {
+    return 'dynamic';
+  }
+  if (isDartVoidTypeRti(rti)) {
+    return 'void';
+  }
+  if (isJsArray(rti)) {
+    // A list representing a type with arguments.
+    return _getRuntimeTypeAsString(rti, genericContext);
+  }
+  if (isJsFunction(rti)) {
+    // A reference to the constructor.
+    return unminifyOrTag(rawRtiToJsConstructorName(rti));
+  }
+  if (isDartJsInteropTypeArgumentRti(rti)) {
+    return 'dynamic';
+  }
+  if (isGenericFunctionTypeParameter(rti)) {
+    int index = rti;
+    if (genericContext == null || index < 0 || index >= genericContext.length) {
+      return 'unexpected-generic-index:${index}';
+    }
+    return '${genericContext[genericContext.length - index - 1]}';
+  }
+  if (isDartFunctionType(rti)) {
+    // TODO(sra): If there is a typedef tag, use the typedef name.
+    return _functionRtiToString(rti, genericContext);
+  }
+  if (isDartFutureOrType(rti)) {
+    var typeArgument = getFutureOrArgument(rti);
+    return 'FutureOr<${_runtimeTypeToString(typeArgument, genericContext)}>';
+  }
+  // We should not get here.
+  return 'unknown-reified-type';
+}
+
+// Returns a formatted String version of a function type.
+//
+// [genericContext] is list of the names of generic type parameters for generic
+// function types. The de Bruijn indexing scheme references the type variables
+// from the inner scope out. The parameters for each scope are pushed in
+// reverse, e.g.  `<P,Q>(<R,S,T>(R))` creates the list `[Q,P,T,S,R]`. This
+// allows the de Bruijn index to simply index backwards from the end of
+// [genericContext], e.g. in the outer scope index `0` is P and `1` is Q, and in
+// the inner scope index `0` is R, `3` is P, and `4` is Q.
+//
+// [genericContext] is initially `null`.
+String _functionRtiToString(var rti, List<String> genericContext) {
+  String typeParameters = '';
+  int outerContextLength;
+
+  String boundsTag = JS_GET_NAME(JsGetName.FUNCTION_TYPE_GENERIC_BOUNDS_TAG);
+  if (hasField(rti, boundsTag)) {
+    List boundsRti = JS('JSFixedArray', '#[#]', rti, boundsTag);
+    if (genericContext == null) {
+      genericContext = <String>[];
+    } else {
+      outerContextLength = genericContext.length;
+    }
+    int offset = genericContext.length;
+    for (int i = boundsRti.length; i > 0; i--) {
+      genericContext.add('T${offset + i}');
+    }
+    // All variables are in scope in the bounds.
+    String typeSep = '';
+    typeParameters = '<';
+    for (int i = 0; i < boundsRti.length; i++) {
+      typeParameters += typeSep;
+      typeParameters += genericContext[genericContext.length - i - 1];
+      typeSep = ', ';
+      var boundRti = boundsRti[i];
+      if (isInterestingBound(boundRti)) {
+        typeParameters +=
+            ' extends ' + _runtimeTypeToString(boundRti, genericContext);
+      }
+    }
+    typeParameters += '>';
+  }
+
+  String returnTypeText;
+  String voidTag = JS_GET_NAME(JsGetName.FUNCTION_TYPE_VOID_RETURN_TAG);
+  if (JS('bool', '!!#[#]', rti, voidTag)) {
+    returnTypeText = 'void';
+  } else {
+    String returnTypeTag = JS_GET_NAME(JsGetName.FUNCTION_TYPE_RETURN_TYPE_TAG);
+    var returnRti = JS('', '#[#]', rti, returnTypeTag);
+    returnTypeText = _runtimeTypeToString(returnRti, genericContext);
+  }
+
+  String argumentsText = '';
+  String sep = '';
+
+  String requiredParamsTag =
+      JS_GET_NAME(JsGetName.FUNCTION_TYPE_REQUIRED_PARAMETERS_TAG);
+  if (hasField(rti, requiredParamsTag)) {
+    List arguments = JS('JSFixedArray', '#[#]', rti, requiredParamsTag);
+    for (var argument in arguments) {
+      argumentsText += sep;
+      argumentsText += _runtimeTypeToString(argument, genericContext);
+      sep = ', ';
+    }
+  }
+
+  String optionalParamsTag =
+      JS_GET_NAME(JsGetName.FUNCTION_TYPE_OPTIONAL_PARAMETERS_TAG);
+  bool hasOptionalArguments = JS('bool', '# in #', optionalParamsTag, rti);
+  if (hasOptionalArguments) {
+    List optionalArguments = JS('JSFixedArray', '#[#]', rti, optionalParamsTag);
+    argumentsText += '$sep[';
+    sep = '';
+    for (var argument in optionalArguments) {
+      argumentsText += sep;
+      argumentsText += _runtimeTypeToString(argument, genericContext);
+      sep = ', ';
+    }
+    argumentsText += ']';
+  }
+
+  String namedParamsTag =
+      JS_GET_NAME(JsGetName.FUNCTION_TYPE_NAMED_PARAMETERS_TAG);
+  bool hasNamedArguments = JS('bool', '# in #', namedParamsTag, rti);
+  if (hasNamedArguments) {
+    var namedArguments = JS('', '#[#]', rti, namedParamsTag);
+    argumentsText += '$sep{';
+    sep = '';
+    for (String name in extractKeys(namedArguments)) {
+      argumentsText += sep;
+      argumentsText += _runtimeTypeToString(
+          JS('', '#[#]', namedArguments, name), genericContext);
+      argumentsText += ' $name';
+      sep = ', ';
+    }
+    argumentsText += '}';
+  }
+
+  if (outerContextLength != null) {
+    // Pop all of the generic type parameters.
+    JS('', '#.length = #', genericContext, outerContextLength);
+  }
+
+  // TODO(sra): Below is the same format as the VM. Change to:
+  //
+  //     return '${returnTypeText} Function${typeParameters}(${argumentsText})';
+  //
+  return '${typeParameters}(${argumentsText}) => ${returnTypeText}';
+}
+
+/// Creates a comma-separated string of human-readable representations of the
+/// type representations in the JavaScript array [types] starting at index
+/// [startIndex].
+String joinArguments(var types, int startIndex) {
+  return _joinArguments(types, startIndex, null);
+}
+
+String _joinArguments(var types, int startIndex, List<String> genericContext) {
+  if (types == null) return '';
+  assert(isJsArray(types));
+  var separator = '';
+  bool allDynamic = true;
+  StringBuffer buffer = new StringBuffer('');
+  for (int index = startIndex; index < getLength(types); index++) {
+    buffer.write(separator);
+    separator = ', ';
+    var argument = getIndex(types, index);
+    if (argument != null) {
+      allDynamic = false;
+    }
+    buffer.write(_runtimeTypeToString(argument, genericContext));
+  }
+  return '<$buffer>';
+}
+
+/// Returns a human-readable representation of the type of [object].
+///
+/// In minified mode does *not* use unminified identifiers (even when present).
+String getRuntimeTypeString(var object) {
+  if (object is Closure) {
+    // This excludes classes that implement Function via a `call` method, but
+    // includes classes generated to represent closures in closure conversion.
+    var functionRti = extractFunctionTypeObjectFrom(object);
+    if (functionRti != null) {
+      return runtimeTypeToString(functionRti);
+    }
+  }
+  String className = getClassName(object);
+  if (object == null) return className;
+  String rtiName = JS_GET_NAME(JsGetName.RTI_NAME);
+  var rti = JS('var', r'#[#]', object, rtiName);
+  return "$className${joinArguments(rti, 0)}";
+}
+
+/// Returns the full type of [o] in the runtime type representation.
+getRti(o) {
+  if (o is Closure) {
+    // This excludes classes that implement Function via a `call` method, but
+    // includes classes generated to represent closures in closure conversion.
+    var functionRti = extractFunctionTypeObjectFrom(o);
+    if (functionRti != null) return functionRti;
+  }
+  var interceptor = getInterceptor(o);
+  var type = getRawRuntimeType(interceptor);
+  if (o == null) return type;
+  if (JS('bool', 'typeof # != "object"', o)) return type;
+  var rti = getRuntimeTypeInfo(o);
+  if (rti != null) {
+    // If the type has type variables (that is, `rti != null`), make a copy of
+    // the type arguments and insert [o] in the first position to create a
+    // compound type representation.
+    rti = JS('JSExtendableArray', '#.slice()', rti); // Make a copy.
+    JS('', '#.splice(0, 0, #)', rti, type); // Insert type at position 0.
+    type = rti;
+  }
+  return type;
+}
+
+Type getRuntimeType(var object) {
+  if (JS_GET_FLAG('USE_NEW_RTI')) return newRti.getRuntimeType(object);
+  return new TypeImpl(getRti(object));
+}
+
+/// Applies the [substitution] on the [arguments].
+///
+/// See the comment in the beginning of this file for a description of the
+/// possible values for [substitution].
+substitute(var substitution, var arguments) {
+  if (substitution == null) return arguments;
+  assert(isJsFunction(substitution));
+  assert(arguments == null || isJsArray(arguments));
+  substitution = invoke(substitution, arguments);
+  if (substitution == null) return null;
+  if (isJsArray(substitution)) {
+    // Substitutions are generated too late to mark Array as used, so use a
+    // tautological JS 'cast' to mark Array as used. This is needed only in
+    // some tiny tests where the substition is the only thing that creates an
+    // Array.
+    return JS('JSArray', '#', substitution);
+  }
+  if (isJsFunction(substitution)) {
+    // TODO(johnniwinther): Check if this is still needed.
+    return invoke(substitution, arguments);
+  }
+  return arguments;
+}
+
+/// Perform a type check with arguments on the Dart object [object].
+///
+/// Parameters:
+/// - [isField]: the name of the flag/function to check if the object
+///   is of the correct class.
+/// - [checks]: the (JavaScript) list of type representations for the
+///   arguments to check against.
+/// - [asField]: the name of the function that transforms the type
+///   arguments of [objects] to an instance of the class that we check
+///   against.
+bool checkSubtype(Object object, String isField, List checks, String asField) {
+  if (object == null) return false;
+  var arguments = getRuntimeTypeInfo(object);
+  // Interceptor is needed for JSArray and native classes.
+  // TODO(sra): It could be a more specialized interceptor since [object] is not
+  // `null` or a primitive.
+  var interceptor = getInterceptor(object);
+  var isSubclass = getField(interceptor, isField);
+  // When we read the field and it is not there, [isSubclass] will be `null`.
+  if (isSubclass == null) return false;
+  // Should the asField function be passed the receiver?
+  var substitution = getField(interceptor, asField);
+  return checkArguments(substitution, arguments, null, checks, null);
+}
+
+/// Returns the field's type name.
+///
+/// In minified mode, uses the unminified names if available.
+String computeTypeName(String isField, List arguments) {
+  // Extract the class name from the is field and append the textual
+  // representation of the type arguments.
+  return Primitives.formatType(
+      unminifyOrTag(isCheckPropertyToJsConstructorName(isField)), arguments);
+}
+
+/// Called from generated code.
+Object subtypeCast(Object object, String isField, List checks, String asField) {
+  if (object == null) return object;
+  if (checkSubtype(object, isField, checks, asField)) return object;
+  String typeName = computeTypeName(isField, checks);
+  throw new CastErrorImplementation(object, typeName);
+}
+
+/// Called from generated code.
+Object assertSubtype(
+    Object object, String isField, List checks, String asField) {
+  if (object == null) return object;
+  if (checkSubtype(object, isField, checks, asField)) return object;
+  String typeName = computeTypeName(isField, checks);
+  throw new TypeErrorImplementation(object, typeName);
+}
+
+/// Checks that the type represented by [subtype] is a subtype of [supertype].
+/// If not a type error is thrown using [prefix], [infix], [suffix] and the
+/// runtime types [subtype] and [supertype] to generate the error message.
+///
+/// Called from generated code.
+assertIsSubtype(
+    var subtype, var supertype, String prefix, String infix, String suffix) {
+  if (!isSubtype(subtype, supertype)) {
+    String message = "TypeError: "
+        "$prefix${runtimeTypeToString(subtype)}$infix"
+        "${runtimeTypeToString(supertype)}$suffix";
+    throwTypeError(message);
+  }
+}
+
+throwTypeError(message) {
+  throw new TypeErrorImplementation.fromMessage(message);
+}
+
+bool checkArguments(
+    var substitution, var arguments, var sEnv, var checks, var tEnv) {
+  return areSubtypes(substitute(substitution, arguments), sEnv, checks, tEnv);
+}
+
+/// Checks whether the types of [s] are all subtypes of the types of [t].
+///
+/// [s] and [t] are either `null` or JavaScript arrays of type representations,
+/// A `null` argument is interpreted as the arguments of a raw type, that is a
+/// list of `dynamic`. If [s] and [t] are JavaScript arrays they must be of the
+/// same length.
+///
+/// See the comment in the beginning of this file for a description of type
+/// representations.
+
+bool areSubtypes(var s, var sEnv, var t, var tEnv) {
+  // `null` means a raw type.
+  if (t == null) return true;
+  if (s == null) {
+    int len = getLength(t);
+    for (int i = 0; i < len; i++) {
+      if (!_isSubtype(null, null, getIndex(t, i), tEnv)) {
+        return false;
+      }
+    }
+    return true;
+  }
+
+  assert(isJsArray(s));
+  assert(isJsArray(t));
+  assert(getLength(s) == getLength(t));
+
+  int len = getLength(s);
+  for (int i = 0; i < len; i++) {
+    if (!_isSubtype(getIndex(s, i), sEnv, getIndex(t, i), tEnv)) {
+      return false;
+    }
+  }
+  return true;
+}
+
+/// Computes the signature by applying the type arguments of [context] as an
+/// instance of [contextName] to the signature function [signature].
+computeSignature(var signature, var context, var contextName) {
+  var interceptor = getInterceptor(context);
+  var typeArguments =
+      getRuntimeTypeArguments(interceptor, context, contextName);
+  return invokeOn(signature, context, typeArguments);
+}
+
+/// Returns `true` if the runtime type representation [type] is a top type.
+/// That is, either `dynamic`, `void` or `Object`.
+@pragma('dart2js:tryInline')
+bool isTopType(var type) {
+  return isDartDynamicTypeRti(type) ||
+      isDartVoidTypeRti(type) ||
+      isDartObjectTypeRti(type) ||
+      isDartJsInteropTypeArgumentRti(type);
+}
+
+/// Returns `true` if the runtime type representation [type] is a supertype of
+/// [Null].
+@pragma('dart2js:tryInline')
+bool isSupertypeOfNull(var type) {
+  return isSupertypeOfNullBase(type) || isSupertypeOfNullRecursive(type);
+}
+
+/// Returns `true` if the runtime type representation [type] is a simple
+/// supertype of [Null].
+///
+/// This method doesn't handle `FutureOr<Null>`. This is handle by
+/// [isSupertypeOfNullRecursive] because it requires a recursive check.
+@pragma('dart2js:tryInline')
+bool isSupertypeOfNullBase(var type) {
+  return isDartDynamicTypeRti(type) ||
+      isDartObjectTypeRti(type) ||
+      isNullTypeRti(type) ||
+      isDartVoidTypeRti(type) ||
+      isDartJsInteropTypeArgumentRti(type);
+}
+
+/// Returns `true` if the runtime type representation [type] is a `FutureOr`
+/// type that is a supertype of [Null].
+///
+/// This method is recursive to be able to handle both `FutureOr<Null>` and
+/// `FutureOr<FutureOr<Null>>` etc.
+bool isSupertypeOfNullRecursive(var type) {
+  if (isGenericFunctionTypeParameter(type)) {
+    // We need to check for function type variables because `isDartFutureOrType`
+    // doesn't work on numbers.
+    return false;
+  }
+  if (isDartFutureOrType(type)) {
+    var typeArgument = getFutureOrArgument(type);
+    return isSupertypeOfNullBase(type) ||
+        isSupertypeOfNullRecursive(typeArgument);
+  }
+  return false;
+}
+
+/// Returns the type argument of the `FutureOr` runtime type representation
+/// [type].
+///
+/// For instance `num` of `FutureOr<num>`.
+@pragma('dart2js:tryInline')
+Object getFutureOrArgument(var type) {
+  assert(isDartFutureOrType(type));
+  var typeArgumentTag = JS_GET_NAME(JsGetName.FUTURE_OR_TYPE_ARGUMENT_TAG);
+  return hasField(type, typeArgumentTag)
+      ? getField(type, typeArgumentTag)
+      : null;
+}
+
+/// Tests whether the Dart object [o] is a subtype of the runtime type
+/// representation [t].
+///
+/// See the comment in the beginning of this file for a description of type
+/// representations.
+bool checkSubtypeOfRuntimeType(o, t) {
+  if (o == null) return isSupertypeOfNull(t);
+  if (isTopType(t)) return true;
+  if (JS('bool', 'typeof # == "object"', t)) {
+    if (isDartFutureOrType(t)) {
+      // `o is FutureOr<T>` is equivalent to
+      //
+      //     o is T || o is Future<T>
+      //
+      // T might be a function type, requiring extracting the closure's
+      // signature, so do the `o is T` check here and let the `Future` interface
+      // type test fall through to the `isSubtype` check at the end of this
+      // function.
+      var tTypeArgument = getFutureOrArgument(t);
+      if (checkSubtypeOfRuntimeType(o, tTypeArgument)) return true;
+    }
+
+    if (isDartFunctionType(t)) {
+      return functionTypeTest(o, t);
+    }
+  }
+
+  var interceptor = getInterceptor(o);
+  var type = getRawRuntimeType(interceptor);
+  var rti = getRuntimeTypeInfo(o);
+  if (rti != null) {
+    // If the type has type variables (that is, `rti != null`), make a copy of
+    // the type arguments and insert [o] in the first position to create a
+    // compound type representation.
+    rti = JS('JSExtendableArray', '#.slice()', rti); // Make a copy.
+    JS('', '#.splice(0, 0, #)', rti, type); // Insert type at position 0.
+    type = rti;
+  }
+  return isSubtype(type, t);
+}
+
+/// Called from generated code.
+Object subtypeOfRuntimeTypeCast(Object object, var type) {
+  if (object != null && !checkSubtypeOfRuntimeType(object, type)) {
+    throw new CastErrorImplementation(object, runtimeTypeToString(type));
+  }
+  return object;
+}
+
+/// Called from generated code.
+Object assertSubtypeOfRuntimeType(Object object, var type) {
+  if (object != null && !checkSubtypeOfRuntimeType(object, type)) {
+    throw new TypeErrorImplementation(object, runtimeTypeToString(type));
+  }
+  return object;
+}
+
+/// Extracts the type arguments from a type representation. The result is a
+/// JavaScript array or `null`.
+getArguments(var type) {
+  return isJsArray(type) ? JS('var', r'#.slice(1)', type) : null;
+}
+
+/// Checks whether the type represented by the type representation [s] is a
+/// subtype of the type represented by the type representation [t].
+///
+/// See the comment in the beginning of this file for a description of type
+/// representations.
+///
+/// The arguments [s] and [t] must be types, usually represented by the
+/// constructor of the class, or an array (for generic class types).
+bool isSubtype(var s, var t) {
+  return _isSubtype(s, null, t, null);
+}
+
+bool _isSubtype(var s, var sEnv, var t, var tEnv) {
+  // Subtyping is reflexive.
+  if (isIdentical(s, t)) return true;
+
+  // [t] is a top type?
+  if (isTopType(t)) return true;
+
+  if (isDartJsInteropTypeArgumentRti(s)) return true;
+
+  // [s] is a top type?
+  if (isTopType(s)) {
+    if (isGenericFunctionTypeParameter(t)) {
+      // We need to check for function type variables because
+      // `isDartFutureOrType` doesn't work on numbers.
+      return false;
+    }
+    if (isDartFutureOrType(t)) {
+      // [t] is FutureOr<T>. Check [s] <: T.
+      var tTypeArgument = getFutureOrArgument(t);
+      return _isSubtype(s, sEnv, tTypeArgument, tEnv);
+    }
+    return false;
+  }
+
+  // Generic function type parameters must match exactly, which would have
+  // exited earlier. The de Bruijn indexing ensures the representation as a
+  // small number can be used for type comparison.
+  if (isGenericFunctionTypeParameter(s)) {
+    // TODO(sra): Use the bound of the type variable.
+    return false;
+  }
+  if (isGenericFunctionTypeParameter(t)) return false;
+
+  if (isNullType(s)) return true;
+
+  // Get the object describing the class and check for the subtyping flag
+  // constructed from the type of [s].
+  var typeOfS = isJsArray(s) ? getIndex(s, 0) : s;
+
+  if (isDartFutureOrType(t)) {
+    // [t] is FutureOr<T>
+    var tTypeArgument = getFutureOrArgument(t);
+    if (isDartFutureOrType(s)) {
+      // [S] is FutureOr<S>. Check S <: T
+      var sTypeArgument = getFutureOrArgument(s);
+      return _isSubtype(sTypeArgument, sEnv, tTypeArgument, tEnv);
+    } else if (_isSubtype(s, sEnv, tTypeArgument, tEnv)) {
+      // `true` because [s] <: T.
+      return true;
+    } else {
+      // Check [s] <: Future<T>.
+      String futureClass = JS_GET_NAME(JsGetName.FUTURE_CLASS_TYPE_NAME);
+      if (!builtinIsSubtype(typeOfS, futureClass)) {
+        // [s] doesn't implement Future.
+        return false;
+      }
+      var typeOfSPrototype = JS('', '#.prototype', typeOfS);
+      var field = '${JS_GET_NAME(JsGetName.OPERATOR_AS_PREFIX)}${futureClass}';
+      var futureSubstitution = getField(typeOfSPrototype, field);
+      var futureArguments = substitute(futureSubstitution, getArguments(s));
+      var futureArgument =
+          isJsArray(futureArguments) ? getIndex(futureArguments, 0) : null;
+      // [s] implements Future<S>. Check S <: T.
+      return _isSubtype(futureArgument, sEnv, tTypeArgument, tEnv);
+    }
+  }
+
+  if (isDartFunctionType(t)) {
+    return _isFunctionSubtype(s, sEnv, t, tEnv);
+  }
+
+  if (isDartFunctionType(s)) {
+    // Check function types against the `Function` class (`Object` is also a
+    // supertype, but is tested above with other 'top' types.).
+    return isDartFunctionTypeRti(t);
+  }
+
+  // Get the object describing the class and check for the subtyping flag
+  // constructed from the type of [t].
+  var typeOfT = isJsArray(t) ? getIndex(t, 0) : t;
+
+  // Check for a subtyping flag.
+  // Get the necessary substitution of the type arguments, if there is one.
+  var substitution;
+  if (isNotIdentical(typeOfT, typeOfS)) {
+    String typeOfTString = rawRtiToJsConstructorName(typeOfT);
+    if (!builtinIsSubtype(typeOfS, typeOfTString)) {
+      return false;
+    }
+    var typeOfSPrototype = JS('', '#.prototype', typeOfS);
+    var field = '${JS_GET_NAME(JsGetName.OPERATOR_AS_PREFIX)}${typeOfTString}';
+    substitution = getField(typeOfSPrototype, field);
+  }
+  // The class of [s] is a subclass of the class of [t]. If [t] has no
+  // type arguments, it used as a raw type and [s] is a subtype of [t].
+  if (!isJsArray(t)) {
+    return true;
+  }
+  // Recursively check the type arguments.
+  return checkArguments(
+      substitution, getArguments(s), sEnv, getArguments(t), tEnv);
+}
+
+/// Top-level function subtype check when [t] is known to be a function type
+/// rti.
+bool isFunctionSubtype(var s, var t) {
+  return _isFunctionSubtype(s, null, t, null);
+}
+
+bool _isFunctionSubtype(var s, var sEnv, var t, var tEnv) {
+  assert(isDartFunctionType(t));
+  if (!isDartFunctionType(s)) return false;
+  var genericBoundsTag =
+      JS_GET_NAME(JsGetName.FUNCTION_TYPE_GENERIC_BOUNDS_TAG);
+  var voidReturnTag = JS_GET_NAME(JsGetName.FUNCTION_TYPE_VOID_RETURN_TAG);
+  var returnTypeTag = JS_GET_NAME(JsGetName.FUNCTION_TYPE_RETURN_TYPE_TAG);
+
+  // Generic function types must agree on number of type parameters and bounds.
+  if (hasField(s, genericBoundsTag)) {
+    if (hasNoField(t, genericBoundsTag)) return false;
+    var sBounds = getField(s, genericBoundsTag);
+    var tBounds = getField(t, genericBoundsTag);
+    int sGenericParameters = getLength(sBounds);
+    int tGenericParameters = getLength(tBounds);
+    if (sGenericParameters != tGenericParameters) return false;
+    // TODO(sra): Compare bounds, which should be 'equal' trees due to the de
+    // Bruijn numbering of type parameters.
+    // TODO(sra): Extend [sEnv] and [tEnv] with bindings for the [s] and [t]
+    // type parameters to enable checking the bound against non-type-parameter
+    // terms.
+  } else if (hasField(t, genericBoundsTag)) {
+    return false;
+  }
+
+  var sReturnType = getField(s, returnTypeTag);
+  var tReturnType = getField(t, returnTypeTag);
+  if (!_isSubtype(sReturnType, sEnv, tReturnType, tEnv)) return false;
+
+  var requiredParametersTag =
+      JS_GET_NAME(JsGetName.FUNCTION_TYPE_REQUIRED_PARAMETERS_TAG);
+  var sParameterTypes = getField(s, requiredParametersTag);
+  var tParameterTypes = getField(t, requiredParametersTag);
+
+  var optionalParametersTag =
+      JS_GET_NAME(JsGetName.FUNCTION_TYPE_OPTIONAL_PARAMETERS_TAG);
+  var sOptionalParameterTypes = getField(s, optionalParametersTag);
+  var tOptionalParameterTypes = getField(t, optionalParametersTag);
+
+  int sParametersLen = sParameterTypes != null ? getLength(sParameterTypes) : 0;
+  int tParametersLen = tParameterTypes != null ? getLength(tParameterTypes) : 0;
+
+  int sOptionalParametersLen =
+      sOptionalParameterTypes != null ? getLength(sOptionalParameterTypes) : 0;
+  int tOptionalParametersLen =
+      tOptionalParameterTypes != null ? getLength(tOptionalParameterTypes) : 0;
+
+  if (sParametersLen > tParametersLen) {
+    // Too many required parameters in [s].
+    return false;
+  }
+  if (sParametersLen + sOptionalParametersLen <
+      tParametersLen + tOptionalParametersLen) {
+    // Too few required and optional parameters in [s].
+    return false;
+  }
+
+  int pos = 0;
+  // Check all required parameters of [s].
+  for (; pos < sParametersLen; pos++) {
+    if (!_isSubtype(getIndex(tParameterTypes, pos), tEnv,
+        getIndex(sParameterTypes, pos), sEnv)) {
+      return false;
+    }
+  }
+  int sPos = 0;
+  int tPos = pos;
+  // Check the remaining parameters of [t] with the first optional parameters
+  // of [s].
+  for (; tPos < tParametersLen; sPos++, tPos++) {
+    if (!_isSubtype(getIndex(tParameterTypes, tPos), tEnv,
+        getIndex(sOptionalParameterTypes, sPos), sEnv)) {
+      return false;
+    }
+  }
+  tPos = 0;
+  // Check the optional parameters of [t] with the remaining optional
+  // parameters of [s]:
+  for (; tPos < tOptionalParametersLen; sPos++, tPos++) {
+    if (!_isSubtype(getIndex(tOptionalParameterTypes, tPos), tEnv,
+        getIndex(sOptionalParameterTypes, sPos), sEnv)) {
+      return false;
+    }
+  }
+
+  var namedParametersTag =
+      JS_GET_NAME(JsGetName.FUNCTION_TYPE_NAMED_PARAMETERS_TAG);
+  var sNamedParameters = getField(s, namedParametersTag);
+  var tNamedParameters = getField(t, namedParametersTag);
+  if (tNamedParameters == null) return true;
+  if (sNamedParameters == null) return false;
+  return namedParametersSubtypeCheck(
+      sNamedParameters, sEnv, tNamedParameters, tEnv);
+}
+
+bool namedParametersSubtypeCheck(var s, var sEnv, var t, var tEnv) {
+  assert(isJsObject(s));
+  assert(isJsObject(t));
+
+  // Each named parameter in [t] must exist in [s] and be a subtype of the type
+  // in [s].
+  List names = JS('JSFixedArray', 'Object.getOwnPropertyNames(#)', t);
+  for (int i = 0; i < names.length; i++) {
+    var name = names[i];
+    if (JS('bool', '!Object.hasOwnProperty.call(#, #)', s, name)) {
+      return false;
+    }
+    var tType = JS('', '#[#]', t, name);
+    var sType = JS('', '#[#]', s, name);
+    if (!_isSubtype(tType, tEnv, sType, sEnv)) return false;
+  }
+  return true;
+}
+
+/// Returns whether [type] is the representation of a generic function type
+/// parameter. Generic function type parameters are represented de Bruijn
+/// indexes.
+///
+/// This test is only valid if [type] is known _not_ to be the void rti, whose
+/// runtime representation is -1.
+bool isGenericFunctionTypeParameter(var type) {
+  assert(!isDartVoidTypeRti(type));
+  return type is num; // Actually int, but 'is num' is faster.
+}
+
+/// Returns [genericFunctionRti] with type parameters bound to [parameters].
+///
+/// [genericFunctionRti] must be an rti representation with a number of generic
+/// type parameters matching the number of types in [parameters].
+///
+/// Called from generated code.
+@pragma('dart2js:noInline')
+instantiatedGenericFunctionType(genericFunctionRti, parameters) {
+  if (genericFunctionRti == null) return null;
+
+  assert(isDartFunctionType(genericFunctionRti));
+
+  var genericBoundsTag =
+      JS_GET_NAME(JsGetName.FUNCTION_TYPE_GENERIC_BOUNDS_TAG);
+
+  assert(hasField(genericFunctionRti, genericBoundsTag));
+  var bounds = getField(genericFunctionRti, genericBoundsTag);
+
+  // Generic function types must agree on number of type parameters and bounds.
+  int boundLength = getLength(bounds);
+  int parametersLength = getLength(parameters);
+  assert(boundLength == parametersLength);
+
+  var result = JS('', '{#:1}', JS_GET_NAME(JsGetName.FUNCTION_TYPE_TAG));
+  return finishBindInstantiatedFunctionType(
+      genericFunctionRti, result, parameters, 0);
+}
+
+bindInstantiatedFunctionType(rti, parameters, int depth) {
+  var result = JS('', '{#:1}', JS_GET_NAME(JsGetName.FUNCTION_TYPE_TAG));
+
+  var genericBoundsTag =
+      JS_GET_NAME(JsGetName.FUNCTION_TYPE_GENERIC_BOUNDS_TAG);
+  if (hasField(rti, genericBoundsTag)) {
+    var bounds = getField(rti, genericBoundsTag);
+    depth += getLength(bounds);
+    setField(result, genericBoundsTag,
+        bindInstantiatedTypes(bounds, parameters, depth));
+  }
+
+  return finishBindInstantiatedFunctionType(rti, result, parameters, depth);
+}
+
+/// Common code for function types that copies all non-bounds parts of the
+/// function [rti] into [result].
+finishBindInstantiatedFunctionType(rti, result, parameters, int depth) {
+  var voidReturnTag = JS_GET_NAME(JsGetName.FUNCTION_TYPE_VOID_RETURN_TAG);
+  var returnTypeTag = JS_GET_NAME(JsGetName.FUNCTION_TYPE_RETURN_TYPE_TAG);
+
+  if (hasField(rti, voidReturnTag)) {
+    setField(result, voidReturnTag, getField(rti, voidReturnTag));
+  } else if (hasField(rti, returnTypeTag)) {
+    setField(result, returnTypeTag,
+        bindInstantiatedType(getField(rti, returnTypeTag), parameters, depth));
+  }
+
+  var requiredParametersTag =
+      JS_GET_NAME(JsGetName.FUNCTION_TYPE_REQUIRED_PARAMETERS_TAG);
+  if (hasField(rti, requiredParametersTag)) {
+    setField(
+        result,
+        requiredParametersTag,
+        bindInstantiatedTypes(
+            getField(rti, requiredParametersTag), parameters, depth));
+  }
+
+  String optionalParametersTag =
+      JS_GET_NAME(JsGetName.FUNCTION_TYPE_OPTIONAL_PARAMETERS_TAG);
+  if (hasField(rti, optionalParametersTag)) {
+    setField(
+        result,
+        optionalParametersTag,
+        bindInstantiatedTypes(
+            getField(rti, optionalParametersTag), parameters, depth));
+  }
+
+  String namedParametersTag =
+      JS_GET_NAME(JsGetName.FUNCTION_TYPE_NAMED_PARAMETERS_TAG);
+  if (hasField(rti, namedParametersTag)) {
+    var namedParameters = getField(rti, namedParametersTag);
+    var boundNamed = JS('', '{}');
+    var names = JS('JSFixedArray', 'Object.keys(#)', namedParameters);
+    for (var name in names) {
+      setField(
+          boundNamed,
+          name,
+          bindInstantiatedType(
+              getField(namedParameters, name), parameters, depth));
+    }
+    setField(result, namedParametersTag, boundNamed);
+  }
+
+  return result;
+}
+
+/// Copies [rti], substituting generic type parameters from [parameters].
+///
+/// Generic type parameters are de Bruijn indexes counting up through the
+/// generic function type parameters scopes to index into [parameters].
+///
+/// [depth] is the number of subsequent generic function parameters that are in
+/// scope. This is subtracted off the de Bruijn index for the type parameter to
+/// arrive at an potential index into [parameters].
+bindInstantiatedType(rti, parameters, int depth) {
+  if (isDartDynamicTypeRti(rti)) return rti; // dynamic.
+  if (isDartVoidTypeRti(rti)) return rti; // void.
+  // Functions are constructors denoting the class of the constructor.
+  if (isJsFunction(rti)) return rti;
+
+  // de Bruijn type indexes.
+  if (isGenericFunctionTypeParameter(rti)) {
+    if (rti < depth) return rti;
+    return JS('', '#[#]', parameters, rti - depth);
+  }
+  // Other things encoded as numbers.
+  if (rti is num) return rti;
+
+  if (isJsArray(rti)) {
+    // An array is a parameterized class type, e.g. the list of three
+    // constructor functions [Map, String, int] represents `Map<String, int>`.
+    // Since the 'head' of the term and the arguments are encoded in the same
+    // scheme, it is sufficient to walk all the types.
+    return bindInstantiatedTypes(rti, parameters, depth);
+  }
+  if (isDartFunctionType(rti)) {
+    return bindInstantiatedFunctionType(rti, parameters, depth);
+  }
+
+  // Can't include the bad [rti] since it is not a Dart value.
+  throw new ArgumentError('Unknown RTI format in bindInstantiatedType.');
+}
+
+/// Returns a copy of array [rti] with each type bound.
+bindInstantiatedTypes(rti, parameters, int depth) {
+  List array = JS('JSFixedArray', '#.slice()', rti);
+  for (int i = 0; i < array.length; i++) {
+    array[i] = bindInstantiatedType(array[i], parameters, depth);
+  }
+  return array;
+}
+
+/// Calls the JavaScript [function] with the [arguments] with the global scope
+/// as the `this` context.
+invoke(var function, var arguments) => invokeOn(function, null, arguments);
+
+/// Calls the JavaScript [function] with the [arguments] with [receiver] as the
+/// `this` context.
+Object invokeOn(function, receiver, arguments) {
+  assert(isJsFunction(function));
+  assert(arguments == null || isJsArray(arguments));
+  return JS('var', r'#.apply(#, #)', function, receiver, arguments);
+}
+
+/// Calls the property [name] on the JavaScript [object].
+call(var object, String name) => JS('var', r'#[#]()', object, name);
+
+/// Returns the property [name] of the JavaScript object [object].
+getField(var object, String name) => JS('var', r'#[#]', object, name);
+
+/// Returns the property [index] of the JavaScript array [array].
+getIndex(var array, int index) {
+  assert(isJsArray(array));
+  return JS('var', r'#[#]', array, index);
+}
+
+setField(var object, String name, var value) {
+  JS('', '#[#] = #', object, name, value);
+}
+
+setIndex(var array, int index, var value) {
+  JS('', '#[#] = #', array, index, value);
+}
+
+/// Returns the length of the JavaScript array [array].
+int getLength(var array) {
+  assert(isJsArray(array));
+  return JS('int', r'#.length', array);
+}
+
+/// Returns whether [value] is a JavaScript array.
+bool isJsArray(var value) {
+  return value is JSArray;
+}
+
+hasField(var object, var name) => JS('bool', r'# in #', name, object);
+
+hasNoField(var object, var name) => !hasField(object, name);
+
+/// Returns `true` if [o] is a JavaScript function.
+bool isJsFunction(var o) => JS('bool', r'typeof # == "function"', o);
+
+/// Returns `true` if [o] is a JavaScript object.
+bool isJsObject(var o) => JS('bool', r"typeof # == 'object'", o);
+
+/// Returns `true` if the JavaScript values [s] and [t] are identical. We use
+/// this helper instead of [identical] because `identical` needs to merge
+/// `null` and `undefined` (which we can avoid).
+bool isIdentical(var s, var t) => JS('bool', '# === #', s, t);
+
+/// Returns `true` if the JavaScript values [s] and [t] are not identical. We
+/// use this helper instead of [identical] because `identical` needs to merge
+/// `null` and `undefined` (which we can avoid).
+bool isNotIdentical(var s, var t) => JS('bool', '# !== #', s, t);
+
+/// 'Top' bounds are uninteresting: null/undefined and Object.
+bool isInterestingBound(rti) =>
+    rti != null &&
+    isNotIdentical(
+        rti,
+        JS_BUILTIN(
+            'depends:none;effects:none;', JsBuiltin.dartObjectConstructor));
diff --git a/sdk_nnbd/lib/_internal/js_runtime/lib/js_string.dart b/sdk_nnbd/lib/_internal/js_runtime/lib/js_string.dart
new file mode 100644
index 0000000..39370d7
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_runtime/lib/js_string.dart
@@ -0,0 +1,470 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of _interceptors;
+
+/// The interceptor class for [String]. The compiler recognizes this
+/// class as an interceptor, and changes references to [:this:] to
+/// actually use the receiver of the method, which is generated as an extra
+/// argument added to each member.
+class JSString extends Interceptor implements String, JSIndexable {
+  const JSString();
+
+  @pragma('dart2js:noInline')
+  int codeUnitAt(int index) {
+    if (index is! int) throw diagnoseIndexError(this, index);
+    if (index < 0) throw diagnoseIndexError(this, index);
+    return _codeUnitAt(index);
+  }
+
+  int _codeUnitAt(int index) {
+    if (index >= length) throw diagnoseIndexError(this, index);
+    return JS('JSUInt31', r'#.charCodeAt(#)', this, index);
+  }
+
+  Iterable<Match> allMatches(String string, [int start = 0]) {
+    checkString(string);
+    checkInt(start);
+    if (0 > start || start > string.length) {
+      throw new RangeError.range(start, 0, string.length);
+    }
+    return allMatchesInStringUnchecked(this, string, start);
+  }
+
+  Match matchAsPrefix(String string, [int start = 0]) {
+    if (start < 0 || start > string.length) {
+      throw new RangeError.range(start, 0, string.length);
+    }
+    if (start + this.length > string.length) return null;
+    // TODO(lrn): See if this can be optimized.
+    for (int i = 0; i < this.length; i++) {
+      if (string.codeUnitAt(start + i) != this.codeUnitAt(i)) {
+        return null;
+      }
+    }
+    return new StringMatch(start, string, this);
+  }
+
+  String operator +(String other) {
+    if (other is! String) throw new ArgumentError.value(other);
+    return JS('String', r'# + #', this, other);
+  }
+
+  bool endsWith(String other) {
+    checkString(other);
+    int otherLength = other.length;
+    if (otherLength > length) return false;
+    return other == substring(length - otherLength);
+  }
+
+  String replaceAll(Pattern from, String to) {
+    return stringReplaceAllUnchecked(this, from, checkString(to));
+  }
+
+  String replaceAllMapped(Pattern from, String convert(Match match)) {
+    return this.splitMapJoin(from, onMatch: convert);
+  }
+
+  String splitMapJoin(Pattern from,
+      {String onMatch(Match match), String onNonMatch(String nonMatch)}) {
+    return stringReplaceAllFuncUnchecked(this, from, onMatch, onNonMatch);
+  }
+
+  String replaceFirst(Pattern from, String to, [int startIndex = 0]) {
+    checkString(to);
+    checkInt(startIndex);
+    RangeError.checkValueInInterval(startIndex, 0, this.length, "startIndex");
+    return stringReplaceFirstUnchecked(this, from, to, startIndex);
+  }
+
+  String replaceFirstMapped(Pattern from, String replace(Match match),
+      [int startIndex = 0]) {
+    checkNull(replace);
+    checkInt(startIndex);
+    RangeError.checkValueInInterval(startIndex, 0, this.length, "startIndex");
+    return stringReplaceFirstMappedUnchecked(this, from, replace, startIndex);
+  }
+
+  List<String> split(Pattern pattern) {
+    checkNull(pattern);
+    if (pattern is String) {
+      return stringSplitUnchecked(this, pattern);
+    } else if (pattern is JSSyntaxRegExp && regExpCaptureCount(pattern) == 0) {
+      var re = regExpGetNative(pattern);
+      return stringSplitUnchecked(this, re);
+    } else {
+      return _defaultSplit(pattern);
+    }
+  }
+
+  String replaceRange(int start, int end, String replacement) {
+    checkString(replacement);
+    checkInt(start);
+    end = RangeError.checkValidRange(start, end, this.length);
+    checkInt(end);
+    return stringReplaceRangeUnchecked(this, start, end, replacement);
+  }
+
+  List<String> _defaultSplit(Pattern pattern) {
+    List<String> result = <String>[];
+    // End of most recent match. That is, start of next part to add to result.
+    int start = 0;
+    // Length of most recent match.
+    // Set >0, so no match on the empty string causes the result to be [""].
+    int length = 1;
+    for (var match in pattern.allMatches(this)) {
+      int matchStart = match.start;
+      int matchEnd = match.end;
+      length = matchEnd - matchStart;
+      if (length == 0 && start == matchStart) {
+        // An empty match right after another match is ignored.
+        // This includes an empty match at the start of the string.
+        continue;
+      }
+      int end = matchStart;
+      result.add(this.substring(start, end));
+      start = matchEnd;
+    }
+    if (start < this.length || length > 0) {
+      // An empty match at the end of the string does not cause a "" at the end.
+      // A non-empty match ending at the end of the string does add a "".
+      result.add(this.substring(start));
+    }
+    return result;
+  }
+
+  bool startsWith(Pattern pattern, [int index = 0]) {
+    checkInt(index);
+    if (index < 0 || index > this.length) {
+      throw new RangeError.range(index, 0, this.length);
+    }
+    if (pattern is String) {
+      String other = pattern;
+      int otherLength = other.length;
+      int endIndex = index + otherLength;
+      if (endIndex > length) return false;
+      return other == JS('String', r'#.substring(#, #)', this, index, endIndex);
+    }
+    return pattern.matchAsPrefix(this, index) != null;
+  }
+
+  String substring(int startIndex, [int endIndex]) {
+    checkInt(startIndex);
+    if (endIndex == null) endIndex = length;
+    checkInt(endIndex);
+    if (startIndex < 0) throw new RangeError.value(startIndex);
+    if (startIndex > endIndex) throw new RangeError.value(startIndex);
+    if (endIndex > length) throw new RangeError.value(endIndex);
+    return JS('String', r'#.substring(#, #)', this, startIndex, endIndex);
+  }
+
+  String toLowerCase() {
+    return JS('returns:String;effects:none;depends:none;throws:null(1)',
+        r'#.toLowerCase()', this);
+  }
+
+  String toUpperCase() {
+    return JS('returns:String;effects:none;depends:none;throws:null(1)',
+        r'#.toUpperCase()', this);
+  }
+
+  // Characters with Whitespace property (Unicode 6.3).
+  // 0009..000D    ; White_Space # Cc       <control-0009>..<control-000D>
+  // 0020          ; White_Space # Zs       SPACE
+  // 0085          ; White_Space # Cc       <control-0085>
+  // 00A0          ; White_Space # Zs       NO-BREAK SPACE
+  // 1680          ; White_Space # Zs       OGHAM SPACE MARK
+  // 2000..200A    ; White_Space # Zs       EN QUAD..HAIR SPACE
+  // 2028          ; White_Space # Zl       LINE SEPARATOR
+  // 2029          ; White_Space # Zp       PARAGRAPH SEPARATOR
+  // 202F          ; White_Space # Zs       NARROW NO-BREAK SPACE
+  // 205F          ; White_Space # Zs       MEDIUM MATHEMATICAL SPACE
+  // 3000          ; White_Space # Zs       IDEOGRAPHIC SPACE
+  //
+  // BOM: 0xFEFF
+  static bool _isWhitespace(int codeUnit) {
+    // Most codeUnits should be less than 256. Special case with a smaller
+    // switch.
+    if (codeUnit < 256) {
+      switch (codeUnit) {
+        case 0x09:
+        case 0x0A:
+        case 0x0B:
+        case 0x0C:
+        case 0x0D:
+        case 0x20:
+        case 0x85:
+        case 0xA0:
+          return true;
+        default:
+          return false;
+      }
+    }
+    switch (codeUnit) {
+      case 0x1680:
+      case 0x2000:
+      case 0x2001:
+      case 0x2002:
+      case 0x2003:
+      case 0x2004:
+      case 0x2005:
+      case 0x2006:
+      case 0x2007:
+      case 0x2008:
+      case 0x2009:
+      case 0x200A:
+      case 0x2028:
+      case 0x2029:
+      case 0x202F:
+      case 0x205F:
+      case 0x3000:
+      case 0xFEFF:
+        return true;
+      default:
+        return false;
+    }
+  }
+
+  /// Finds the index of the first non-whitespace character, or the
+  /// end of the string. Start looking at position [index].
+  static int _skipLeadingWhitespace(String string, int index) {
+    const int SPACE = 0x20;
+    const int CARRIAGE_RETURN = 0x0D;
+    while (index < string.length) {
+      int codeUnit = string.codeUnitAt(index);
+      if (codeUnit != SPACE &&
+          codeUnit != CARRIAGE_RETURN &&
+          !_isWhitespace(codeUnit)) {
+        break;
+      }
+      index++;
+    }
+    return index;
+  }
+
+  /// Finds the index after the last non-whitespace character, or 0.
+  /// Start looking at position [index - 1].
+  static int _skipTrailingWhitespace(String string, int index) {
+    const int SPACE = 0x20;
+    const int CARRIAGE_RETURN = 0x0D;
+    while (index > 0) {
+      int codeUnit = string.codeUnitAt(index - 1);
+      if (codeUnit != SPACE &&
+          codeUnit != CARRIAGE_RETURN &&
+          !_isWhitespace(codeUnit)) {
+        break;
+      }
+      index--;
+    }
+    return index;
+  }
+
+  // Dart2js can't use JavaScript trim directly,
+  // because JavaScript does not trim
+  // the NEXT LINE (NEL) character (0x85).
+  String trim() {
+    const int NEL = 0x85;
+
+    // Start by doing JS trim. Then check if it leaves a NEL at
+    // either end of the string.
+    String result = JS('String', '#.trim()', this);
+    if (result.length == 0) return result;
+    int firstCode = result.codeUnitAt(0);
+    int startIndex = 0;
+    if (firstCode == NEL) {
+      startIndex = _skipLeadingWhitespace(result, 1);
+      if (startIndex == result.length) return "";
+    }
+
+    int endIndex = result.length;
+    // We know that there is at least one character that is non-whitespace.
+    // Therefore we don't need to verify that endIndex > startIndex.
+    int lastCode = result.codeUnitAt(endIndex - 1);
+    if (lastCode == NEL) {
+      endIndex = _skipTrailingWhitespace(result, endIndex - 1);
+    }
+    if (startIndex == 0 && endIndex == result.length) return result;
+    return JS('String', r'#.substring(#, #)', result, startIndex, endIndex);
+  }
+
+  // Dart2js can't use JavaScript trimLeft directly,
+  // because it is not in ES5, so not every browser implements it,
+  // and because those that do will not trim the NEXT LINE character (0x85).
+  String trimLeft() {
+    const int NEL = 0x85;
+
+    // Start by doing JS trim. Then check if it leaves a NEL at
+    // the beginning of the string.
+    String result;
+    int startIndex = 0;
+    if (JS('bool', 'typeof #.trimLeft != "undefined"', this)) {
+      result = JS('String', '#.trimLeft()', this);
+      if (result.length == 0) return result;
+      int firstCode = result.codeUnitAt(0);
+      if (firstCode == NEL) {
+        startIndex = _skipLeadingWhitespace(result, 1);
+      }
+    } else {
+      result = this;
+      startIndex = _skipLeadingWhitespace(this, 0);
+    }
+    if (startIndex == 0) return result;
+    if (startIndex == result.length) return "";
+    return JS('String', r'#.substring(#)', result, startIndex);
+  }
+
+  // Dart2js can't use JavaScript trimRight directly,
+  // because it is not in ES5 and because JavaScript does not trim
+  // the NEXT LINE character (0x85).
+  String trimRight() {
+    const int NEL = 0x85;
+
+    // Start by doing JS trim. Then check if it leaves a NEL or BOM at
+    // the end of the string.
+    String result;
+    int endIndex;
+    // trimRight is implemented by Firefox and Chrome/Blink,
+    // so use it if it is there.
+    if (JS('bool', 'typeof #.trimRight != "undefined"', this)) {
+      result = JS('String', '#.trimRight()', this);
+      endIndex = result.length;
+      if (endIndex == 0) return result;
+      int lastCode = result.codeUnitAt(endIndex - 1);
+      if (lastCode == NEL) {
+        endIndex = _skipTrailingWhitespace(result, endIndex - 1);
+      }
+    } else {
+      result = this;
+      endIndex = _skipTrailingWhitespace(this, this.length);
+    }
+
+    if (endIndex == result.length) return result;
+    if (endIndex == 0) return "";
+    return JS('String', r'#.substring(#, #)', result, 0, endIndex);
+  }
+
+  String operator *(int times) {
+    if (0 >= times) return ''; // Unnecessary but hoists argument type check.
+    if (times == 1 || this.length == 0) return this;
+    if (times != JS('JSUInt32', '# >>> 0', times)) {
+      // times >= 2^32. We can't create a string that big.
+      throw const OutOfMemoryError();
+    }
+    var result = '';
+    var s = this;
+    while (true) {
+      if (times & 1 == 1) result = s + result;
+      times = JS('JSUInt31', '# >>> 1', times);
+      if (times == 0) break;
+      s += s;
+    }
+    return result;
+  }
+
+  String padLeft(int width, [String padding = ' ']) {
+    int delta = width - this.length;
+    if (delta <= 0) return this;
+    return padding * delta + this;
+  }
+
+  String padRight(int width, [String padding = ' ']) {
+    int delta = width - this.length;
+    if (delta <= 0) return this;
+    return this + padding * delta;
+  }
+
+  List<int> get codeUnits => new CodeUnits(this);
+
+  Runes get runes => new Runes(this);
+
+  int indexOf(Pattern pattern, [int start = 0]) {
+    checkNull(pattern);
+    if (start is! int) throw argumentErrorValue(start);
+    if (start < 0 || start > this.length) {
+      throw new RangeError.range(start, 0, this.length);
+    }
+    if (pattern is String) {
+      return stringIndexOfStringUnchecked(this, pattern, start);
+    }
+    if (pattern is JSSyntaxRegExp) {
+      JSSyntaxRegExp re = pattern;
+      Match match = firstMatchAfter(re, this, start);
+      return (match == null) ? -1 : match.start;
+    }
+    for (int i = start; i <= this.length; i++) {
+      if (pattern.matchAsPrefix(this, i) != null) return i;
+    }
+    return -1;
+  }
+
+  int lastIndexOf(Pattern pattern, [int start]) {
+    checkNull(pattern);
+    if (start == null) {
+      start = length;
+    } else if (start is! int) {
+      throw argumentErrorValue(start);
+    } else if (start < 0 || start > this.length) {
+      throw new RangeError.range(start, 0, this.length);
+    }
+    if (pattern is String) {
+      String other = pattern;
+      if (start + other.length > this.length) {
+        start = this.length - other.length;
+      }
+      return stringLastIndexOfUnchecked(this, other, start);
+    }
+    for (int i = start; i >= 0; i--) {
+      if (pattern.matchAsPrefix(this, i) != null) return i;
+    }
+    return -1;
+  }
+
+  bool contains(Pattern other, [int startIndex = 0]) {
+    checkNull(other);
+    if (startIndex < 0 || startIndex > this.length) {
+      throw new RangeError.range(startIndex, 0, this.length);
+    }
+    return stringContainsUnchecked(this, other, startIndex);
+  }
+
+  bool get isEmpty => length == 0;
+
+  bool get isNotEmpty => !isEmpty;
+
+  int compareTo(String other) {
+    if (other is! String) throw argumentErrorValue(other);
+    return this == other ? 0 : JS('bool', r'# < #', this, other) ? -1 : 1;
+  }
+
+  // Note: if you change this, also change the function [S].
+  String toString() => this;
+
+  /// This is the [Jenkins hash function][1] but using masking to keep
+  /// values in SMI range.
+  ///
+  /// [1]: http://en.wikipedia.org/wiki/Jenkins_hash_function
+  int get hashCode {
+    // TODO(ahe): This method shouldn't have to use JS. Update when our
+    // optimizations are smarter.
+    int hash = 0;
+    for (int i = 0; i < length; i++) {
+      hash = 0x1fffffff & (hash + JS('int', r'#.charCodeAt(#)', this, i));
+      hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10));
+      hash = JS('int', '# ^ (# >> 6)', hash, hash);
+    }
+    hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3));
+    hash = JS('int', '# ^ (# >> 11)', hash, hash);
+    return 0x1fffffff & (hash + ((0x00003fff & hash) << 15));
+  }
+
+  Type get runtimeType => String;
+
+  int get length => JS('int', r'#.length', this);
+
+  String operator [](int index) {
+    if (index is! int) throw diagnoseIndexError(this, index);
+    if (index >= length || index < 0) throw diagnoseIndexError(this, index);
+    return JS('String', '#[#]', this, index);
+  }
+}
diff --git a/sdk_nnbd/lib/_internal/js_runtime/lib/linked_hash_map.dart b/sdk_nnbd/lib/_internal/js_runtime/lib/linked_hash_map.dart
new file mode 100644
index 0000000..42ad0c4
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_runtime/lib/linked_hash_map.dart
@@ -0,0 +1,439 @@
+// Copyright (c) 2014, 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.
+
+// Efficient JavaScript based implementation of a linked hash map used as a
+// backing map for constant maps and the [LinkedHashMap] patch
+
+part of _js_helper;
+
+const _USE_ES6_MAPS = const bool.fromEnvironment("dart2js.use.es6.maps");
+
+class JsLinkedHashMap<K, V> extends MapBase<K, V>
+    implements LinkedHashMap<K, V>, InternalMap {
+  int _length = 0;
+
+  // The hash map contents are divided into three parts: one part for
+  // string keys, one for numeric keys, and one for the rest. String
+  // and numeric keys map directly to their linked cells, but the rest
+  // of the entries are stored in bucket lists of the form:
+  //
+  //    [cell-0, cell-1, ...]
+  //
+  // where all keys in the same bucket share the same hash code.
+  var _strings;
+  var _nums;
+  var _rest;
+
+  // The keys and values are stored in cells that are linked together
+  // to form a double linked list.
+  LinkedHashMapCell _first;
+  LinkedHashMapCell _last;
+
+  // We track the number of modifications done to the key set of the
+  // hash map to be able to throw when the map is modified while being
+  // iterated over.
+  int _modifications = 0;
+
+  static bool get _supportsEs6Maps {
+    return JS('returns:bool;depends:none;effects:none;throws:never;gvn:true',
+        'typeof Map != "undefined"');
+  }
+
+  JsLinkedHashMap();
+
+  /// If ES6 Maps are available returns a linked hash-map backed by an ES6 Map.
+  @pragma('dart2js:tryInline')
+  factory JsLinkedHashMap.es6() {
+    return (_USE_ES6_MAPS && JsLinkedHashMap._supportsEs6Maps)
+        ? new Es6LinkedHashMap<K, V>()
+        : new JsLinkedHashMap<K, V>();
+  }
+
+  int get length => _length;
+  bool get isEmpty => _length == 0;
+  bool get isNotEmpty => !isEmpty;
+
+  Iterable<K> get keys {
+    return new LinkedHashMapKeyIterable<K>(this);
+  }
+
+  Iterable<V> get values {
+    return new MappedIterable<K, V>(keys, (each) => this[each]);
+  }
+
+  bool containsKey(Object key) {
+    if (_isStringKey(key)) {
+      var strings = _strings;
+      if (strings == null) return false;
+      return _containsTableEntry(strings, key);
+    } else if (_isNumericKey(key)) {
+      var nums = _nums;
+      if (nums == null) return false;
+      return _containsTableEntry(nums, key);
+    } else {
+      return internalContainsKey(key);
+    }
+  }
+
+  bool internalContainsKey(Object key) {
+    var rest = _rest;
+    if (rest == null) return false;
+    var bucket = _getBucket(rest, key);
+    return internalFindBucketIndex(bucket, key) >= 0;
+  }
+
+  bool containsValue(Object value) {
+    return keys.any((each) => this[each] == value);
+  }
+
+  void addAll(Map<K, V> other) {
+    other.forEach((K key, V value) {
+      this[key] = value;
+    });
+  }
+
+  V operator [](Object key) {
+    if (_isStringKey(key)) {
+      var strings = _strings;
+      if (strings == null) return null;
+      LinkedHashMapCell cell = _getTableCell(strings, key);
+      return JS('', '#', cell == null ? null : cell.hashMapCellValue);
+    } else if (_isNumericKey(key)) {
+      var nums = _nums;
+      if (nums == null) return null;
+      LinkedHashMapCell cell = _getTableCell(nums, key);
+      return JS('', '#', cell == null ? null : cell.hashMapCellValue);
+    } else {
+      return internalGet(key);
+    }
+  }
+
+  V internalGet(Object key) {
+    var rest = _rest;
+    if (rest == null) return null;
+    var bucket = _getBucket(rest, key);
+    int index = internalFindBucketIndex(bucket, key);
+    if (index < 0) return null;
+    LinkedHashMapCell cell = JS('var', '#[#]', bucket, index);
+    return JS('', '#', cell.hashMapCellValue);
+  }
+
+  void operator []=(K key, V value) {
+    if (_isStringKey(key)) {
+      var strings = _strings;
+      if (strings == null) _strings = strings = _newHashTable();
+      _addHashTableEntry(strings, key, value);
+    } else if (_isNumericKey(key)) {
+      var nums = _nums;
+      if (nums == null) _nums = nums = _newHashTable();
+      _addHashTableEntry(nums, key, value);
+    } else {
+      internalSet(key, value);
+    }
+  }
+
+  void internalSet(K key, V value) {
+    var rest = _rest;
+    if (rest == null) _rest = rest = _newHashTable();
+    var hash = internalComputeHashCode(key);
+    var bucket = _getTableBucket(rest, hash);
+    if (bucket == null) {
+      LinkedHashMapCell cell = _newLinkedCell(key, value);
+      _setTableEntry(rest, hash, JS('var', '[#]', cell));
+    } else {
+      int index = internalFindBucketIndex(bucket, key);
+      if (index >= 0) {
+        LinkedHashMapCell cell = JS('var', '#[#]', bucket, index);
+        cell.hashMapCellValue = value;
+      } else {
+        LinkedHashMapCell cell = _newLinkedCell(key, value);
+        JS('void', '#.push(#)', bucket, cell);
+      }
+    }
+  }
+
+  V putIfAbsent(K key, V ifAbsent()) {
+    if (containsKey(key)) return this[key];
+    V value = ifAbsent();
+    this[key] = value;
+    return value;
+  }
+
+  V remove(Object key) {
+    if (_isStringKey(key)) {
+      return _removeHashTableEntry(_strings, key);
+    } else if (_isNumericKey(key)) {
+      return _removeHashTableEntry(_nums, key);
+    } else {
+      return internalRemove(key);
+    }
+  }
+
+  V internalRemove(Object key) {
+    var rest = _rest;
+    if (rest == null) return null;
+    var hash = internalComputeHashCode(key);
+    var bucket = _getTableBucket(rest, hash);
+    int index = internalFindBucketIndex(bucket, key);
+    if (index < 0) return null;
+    // Use splice to remove the [cell] element at the index and
+    // unlink the cell before returning its value.
+    LinkedHashMapCell cell = JS('var', '#.splice(#, 1)[0]', bucket, index);
+    _unlinkCell(cell);
+    // Remove empty bucket list to avoid memory leak.
+    if (JS('int', '#.length', bucket) == 0) {
+      _deleteTableEntry(rest, hash);
+    }
+    return JS('', '#', cell.hashMapCellValue);
+  }
+
+  void clear() {
+    if (_length > 0) {
+      _strings = _nums = _rest = _first = _last = null;
+      _length = 0;
+      _modified();
+    }
+  }
+
+  void forEach(void action(K key, V value)) {
+    LinkedHashMapCell cell = _first;
+    int modifications = _modifications;
+    while (cell != null) {
+      K key = JS('', '#', cell.hashMapCellKey);
+      V value = JS('', '#', cell.hashMapCellValue);
+      action(key, value);
+      if (modifications != _modifications) {
+        throw new ConcurrentModificationError(this);
+      }
+      cell = cell._next;
+    }
+  }
+
+  void _addHashTableEntry(var table, K key, V value) {
+    LinkedHashMapCell cell = _getTableCell(table, key);
+    if (cell == null) {
+      _setTableEntry(table, key, _newLinkedCell(key, value));
+    } else {
+      cell.hashMapCellValue = value;
+    }
+  }
+
+  V _removeHashTableEntry(var table, Object key) {
+    if (table == null) return null;
+    LinkedHashMapCell cell = _getTableCell(table, key);
+    if (cell == null) return null;
+    _unlinkCell(cell);
+    _deleteTableEntry(table, key);
+    return JS('', '#', cell.hashMapCellValue);
+  }
+
+  void _modified() {
+    // Value cycles after 2^30 modifications so that modification counts are
+    // always unboxed (Smi) values. Modification detection will be missed if you
+    // make exactly some multiple of 2^30 modifications between advances of an
+    // iterator.
+    _modifications = (_modifications + 1) & 0x3ffffff;
+  }
+
+  // Create a new cell and link it in as the last one in the list.
+  LinkedHashMapCell _newLinkedCell(K key, V value) {
+    LinkedHashMapCell cell = new LinkedHashMapCell(key, value);
+    if (_first == null) {
+      _first = _last = cell;
+    } else {
+      LinkedHashMapCell last = _last;
+      cell._previous = last;
+      _last = last._next = cell;
+    }
+    _length++;
+    _modified();
+    return cell;
+  }
+
+  // Unlink the given cell from the linked list of cells.
+  void _unlinkCell(LinkedHashMapCell cell) {
+    LinkedHashMapCell previous = cell._previous;
+    LinkedHashMapCell next = cell._next;
+    if (previous == null) {
+      assert(cell == _first);
+      _first = next;
+    } else {
+      previous._next = next;
+    }
+    if (next == null) {
+      assert(cell == _last);
+      _last = previous;
+    } else {
+      next._previous = previous;
+    }
+    _length--;
+    _modified();
+  }
+
+  static bool _isStringKey(var key) {
+    return key is String;
+  }
+
+  static bool _isNumericKey(var key) {
+    // Only treat unsigned 30-bit integers as numeric keys. This way,
+    // we avoid converting them to strings when we use them as keys in
+    // the JavaScript hash table object.
+    return key is num && JS('bool', '(# & 0x3ffffff) === #', key, key);
+  }
+
+  int internalComputeHashCode(var key) {
+    // We force the hash codes to be unsigned 30-bit integers to avoid
+    // issues with problematic keys like '__proto__'. Another option
+    // would be to throw an exception if the hash code isn't a number.
+    return JS('int', '# & 0x3ffffff', key.hashCode);
+  }
+
+  List<LinkedHashMapCell> _getBucket(var table, var key) {
+    var hash = internalComputeHashCode(key);
+    return _getTableBucket(table, hash);
+  }
+
+  int internalFindBucketIndex(var bucket, var key) {
+    if (bucket == null) return -1;
+    int length = JS('int', '#.length', bucket);
+    for (int i = 0; i < length; i++) {
+      LinkedHashMapCell cell = JS('var', '#[#]', bucket, i);
+      if (cell.hashMapCellKey == key) return i;
+    }
+    return -1;
+  }
+
+  String toString() => MapBase.mapToString(this);
+
+  LinkedHashMapCell _getTableCell(var table, var key) {
+    return JS('var', '#[#]', table, key);
+  }
+
+  List<LinkedHashMapCell> _getTableBucket(var table, var key) {
+    return JS('var', '#[#]', table, key);
+  }
+
+  void _setTableEntry(var table, var key, var value) {
+    assert(value != null);
+    JS('void', '#[#] = #', table, key, value);
+  }
+
+  void _deleteTableEntry(var table, var key) {
+    JS('void', 'delete #[#]', table, key);
+  }
+
+  bool _containsTableEntry(var table, var key) {
+    LinkedHashMapCell cell = _getTableCell(table, key);
+    return cell != null;
+  }
+
+  _newHashTable() {
+    // Create a new JavaScript object to be used as a hash table. Use
+    // Object.create to avoid the properties on Object.prototype
+    // showing up as entries.
+    var table = JS('var', 'Object.create(null)');
+    // Attempt to force the hash table into 'dictionary' mode by
+    // adding a property to it and deleting it again.
+    var temporaryKey = '<non-identifier-key>';
+    _setTableEntry(table, temporaryKey, table);
+    _deleteTableEntry(table, temporaryKey);
+    return table;
+  }
+}
+
+class Es6LinkedHashMap<K, V> extends JsLinkedHashMap<K, V> {
+  @override
+  LinkedHashMapCell _getTableCell(var table, var key) {
+    return JS('var', '#.get(#)', table, key);
+  }
+
+  @override
+  List<LinkedHashMapCell> _getTableBucket(var table, var key) {
+    return JS('var', '#.get(#)', table, key);
+  }
+
+  @override
+  void _setTableEntry(var table, var key, var value) {
+    JS('void', '#.set(#, #)', table, key, value);
+  }
+
+  @override
+  void _deleteTableEntry(var table, var key) {
+    JS('void', '#.delete(#)', table, key);
+  }
+
+  @override
+  bool _containsTableEntry(var table, var key) {
+    return JS('bool', '#.has(#)', table, key);
+  }
+
+  @override
+  _newHashTable() {
+    return JS('var', 'new Map()');
+  }
+}
+
+class LinkedHashMapCell {
+  final dynamic hashMapCellKey;
+  dynamic hashMapCellValue;
+
+  LinkedHashMapCell _next;
+  LinkedHashMapCell _previous;
+
+  LinkedHashMapCell(this.hashMapCellKey, this.hashMapCellValue);
+}
+
+class LinkedHashMapKeyIterable<E> extends EfficientLengthIterable<E> {
+  final dynamic _map;
+  LinkedHashMapKeyIterable(this._map);
+
+  int get length => _map._length;
+  bool get isEmpty => _map._length == 0;
+
+  Iterator<E> get iterator {
+    return new LinkedHashMapKeyIterator<E>(_map, _map._modifications);
+  }
+
+  bool contains(Object element) {
+    return _map.containsKey(element);
+  }
+
+  void forEach(void f(E element)) {
+    LinkedHashMapCell cell = _map._first;
+    int modifications = _map._modifications;
+    while (cell != null) {
+      f(JS('', '#', cell.hashMapCellKey));
+      if (modifications != _map._modifications) {
+        throw new ConcurrentModificationError(_map);
+      }
+      cell = cell._next;
+    }
+  }
+}
+
+class LinkedHashMapKeyIterator<E> implements Iterator<E> {
+  final dynamic _map;
+  final int _modifications;
+  LinkedHashMapCell _cell;
+  E _current;
+
+  LinkedHashMapKeyIterator(this._map, this._modifications) {
+    _cell = _map._first;
+  }
+
+  E get current => _current;
+
+  bool moveNext() {
+    if (_modifications != _map._modifications) {
+      throw new ConcurrentModificationError(_map);
+    } else if (_cell == null) {
+      _current = null;
+      return false;
+    } else {
+      _current = JS('', '#', _cell.hashMapCellKey);
+      _cell = _cell._next;
+      return true;
+    }
+  }
+}
diff --git a/sdk_nnbd/lib/_internal/js_runtime/lib/math_patch.dart b/sdk_nnbd/lib/_internal/js_runtime/lib/math_patch.dart
new file mode 100644
index 0000000..677953e
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_runtime/lib/math_patch.dart
@@ -0,0 +1,329 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Patch file for dart:math library.
+import 'dart:_foreign_helper' show JS;
+import 'dart:_js_helper' show patch, checkNum;
+import 'dart:typed_data' show ByteData;
+
+@patch
+T min<T extends num>(T a, T b) => JS(
+    'returns:num;depends:none;effects:none;gvn:true',
+    r'Math.min(#, #)',
+    checkNum(a),
+    checkNum(b));
+
+@patch
+T max<T extends num>(T a, T b) => JS(
+    'returns:num;depends:none;effects:none;gvn:true',
+    r'Math.max(#, #)',
+    checkNum(a),
+    checkNum(b));
+
+@patch
+double sqrt(num x) => JS('num', r'Math.sqrt(#)', checkNum(x));
+
+@patch
+double sin(num radians) => JS('num', r'Math.sin(#)', checkNum(radians));
+
+@patch
+double cos(num radians) => JS('num', r'Math.cos(#)', checkNum(radians));
+
+@patch
+double tan(num radians) => JS('num', r'Math.tan(#)', checkNum(radians));
+
+@patch
+double acos(num x) => JS('num', r'Math.acos(#)', checkNum(x));
+
+@patch
+double asin(num x) => JS('num', r'Math.asin(#)', checkNum(x));
+
+@patch
+double atan(num x) => JS('num', r'Math.atan(#)', checkNum(x));
+
+@patch
+double atan2(num a, num b) =>
+    JS('num', r'Math.atan2(#, #)', checkNum(a), checkNum(b));
+
+@patch
+double exp(num x) => JS('num', r'Math.exp(#)', checkNum(x));
+
+@patch
+double log(num x) => JS('num', r'Math.log(#)', checkNum(x));
+
+@patch
+num pow(num x, num exponent) {
+  checkNum(x);
+  checkNum(exponent);
+  return JS('num', r'Math.pow(#, #)', x, exponent);
+}
+
+const int _POW2_32 = 0x100000000;
+
+@patch
+class Random {
+  static Random _secureRandom;
+
+  @patch
+  factory Random([int seed]) =>
+      (seed == null) ? const _JSRandom() : new _Random(seed);
+
+  @patch
+  factory Random.secure() => _secureRandom ??= _JSSecureRandom();
+}
+
+class _JSRandom implements Random {
+  // The Dart2JS implementation of Random doesn't use a seed.
+  const _JSRandom();
+
+  int nextInt(int max) {
+    if (max <= 0 || max > _POW2_32) {
+      throw new RangeError('max must be in range 0 < max ≤ 2^32, was $max');
+    }
+    return JS('int', '(Math.random() * #) >>> 0', max);
+  }
+
+  /// Generates a positive random floating point value uniformly distributed on
+  /// the range from 0.0, inclusive, to 1.0, exclusive.
+  double nextDouble() => JS('double', 'Math.random()');
+
+  /// Generates a random boolean value.
+  bool nextBool() => JS('bool', 'Math.random() < 0.5');
+}
+
+class _Random implements Random {
+  // Constants used by the algorithm or masking.
+  static const double _POW2_53_D = 1.0 * (0x20000000000000);
+  static const double _POW2_27_D = 1.0 * (1 << 27);
+  static const int _MASK32 = 0xFFFFFFFF;
+
+  // State comprised of two unsigned 32 bit integers.
+  int _lo = 0;
+  int _hi = 0;
+
+  // Implements:
+  //   uint64_t hash = 0;
+  //   do {
+  //      hash = hash * 1037 ^ mix64((uint64_t)seed);
+  //      seed >>= 64;
+  //   } while (seed != 0 && seed != -1);  // Limits for pos/neg seed.
+  //   if (hash == 0) {
+  //     hash = 0x5A17;
+  //   }
+  //   _lo = hash & _MASK_32;
+  //   _hi = hash >> 32;
+  // and then does four _nextState calls to shuffle bits around.
+  _Random(int seed) {
+    int empty_seed = 0;
+    if (seed < 0) {
+      empty_seed = -1;
+    }
+    do {
+      int low = seed & _MASK32;
+      seed = (seed - low) ~/ _POW2_32;
+      int high = seed & _MASK32;
+      seed = (seed - high) ~/ _POW2_32;
+
+      // Thomas Wang's 64-bit mix function.
+      // http://www.concentric.net/~Ttwang/tech/inthash.htm
+      // via. http://web.archive.org/web/20071223173210/http://www.concentric.net/~Ttwang/tech/inthash.htm
+
+      // key = ~key + (key << 21);
+      int tmplow = low << 21;
+      int tmphigh = (high << 21) | (low >> 11);
+      tmplow = (~low & _MASK32) + tmplow;
+      low = tmplow & _MASK32;
+      high = (~high + tmphigh + ((tmplow - low) ~/ 0x100000000)) & _MASK32;
+      // key = key ^ (key >> 24).
+      tmphigh = high >> 24;
+      tmplow = (low >> 24) | (high << 8);
+      low ^= tmplow;
+      high ^= tmphigh;
+      // key = key * 265
+      tmplow = low * 265;
+      low = tmplow & _MASK32;
+      high = (high * 265 + (tmplow - low) ~/ 0x100000000) & _MASK32;
+      // key = key ^ (key >> 14);
+      tmphigh = high >> 14;
+      tmplow = (low >> 14) | (high << 18);
+      low ^= tmplow;
+      high ^= tmphigh;
+      // key = key * 21
+      tmplow = low * 21;
+      low = tmplow & _MASK32;
+      high = (high * 21 + (tmplow - low) ~/ 0x100000000) & _MASK32;
+      // key = key ^ (key >> 28).
+      tmphigh = high >> 28;
+      tmplow = (low >> 28) | (high << 4);
+      low ^= tmplow;
+      high ^= tmphigh;
+      // key = key + (key << 31);
+      tmplow = low << 31;
+      tmphigh = (high << 31) | (low >> 1);
+      tmplow += low;
+      low = tmplow & _MASK32;
+      high = (high + tmphigh + (tmplow - low) ~/ 0x100000000) & _MASK32;
+      // Mix end.
+
+      // seed = seed * 1037 ^ key;
+      tmplow = _lo * 1037;
+      _lo = tmplow & _MASK32;
+      _hi = (_hi * 1037 + (tmplow - _lo) ~/ 0x100000000) & _MASK32;
+      _lo ^= low;
+      _hi ^= high;
+    } while (seed != empty_seed);
+
+    if (_hi == 0 && _lo == 0) {
+      _lo = 0x5A17;
+    }
+    _nextState();
+    _nextState();
+    _nextState();
+    _nextState();
+  }
+
+  // The algorithm used here is Multiply with Carry (MWC) with a Base b = 2^32.
+  // http://en.wikipedia.org/wiki/Multiply-with-carry
+  // The constant A (0xFFFFDA61) is selected from "Numerical Recipes 3rd
+  // Edition" p.348 B1.
+
+  // Implements:
+  //   var state = (A * _lo + _hi) & _MASK_64;
+  //   _lo = state & _MASK_32;
+  //   _hi = state >> 32;
+  void _nextState() {
+    // Simulate (0xFFFFDA61 * lo + hi) without overflowing 53 bits.
+    int tmpHi = 0xFFFF0000 * _lo; // At most 48 bits of significant result.
+    int tmpHiLo = tmpHi & _MASK32; // Get the lower 32 bits.
+    int tmpHiHi = tmpHi - tmpHiLo; // And just the upper 32 bits.
+    int tmpLo = 0xDA61 * _lo;
+    int tmpLoLo = tmpLo & _MASK32;
+    int tmpLoHi = tmpLo - tmpLoLo;
+
+    int newLo = tmpLoLo + tmpHiLo + _hi;
+    _lo = newLo & _MASK32;
+    int newLoHi = newLo - _lo;
+    _hi = ((tmpLoHi + tmpHiHi + newLoHi) ~/ _POW2_32) & _MASK32;
+    assert(_lo < _POW2_32);
+    assert(_hi < _POW2_32);
+  }
+
+  int nextInt(int max) {
+    if (max <= 0 || max > _POW2_32) {
+      throw new RangeError('max must be in range 0 < max ≤ 2^32, was $max');
+    }
+    if ((max & (max - 1)) == 0) {
+      // Fast case for powers of two.
+      _nextState();
+      return _lo & (max - 1);
+    }
+
+    int rnd32;
+    int result;
+    do {
+      _nextState();
+      rnd32 = _lo;
+      result = rnd32.remainder(max); // % max;
+    } while ((rnd32 - result + max) >= _POW2_32);
+    return result;
+  }
+
+  double nextDouble() {
+    _nextState();
+    int bits26 = _lo & ((1 << 26) - 1);
+    _nextState();
+    int bits27 = _lo & ((1 << 27) - 1);
+    return (bits26 * _POW2_27_D + bits27) / _POW2_53_D;
+  }
+
+  bool nextBool() {
+    _nextState();
+    return (_lo & 1) == 0;
+  }
+}
+
+class _JSSecureRandom implements Random {
+  // Reused buffer with room enough for a double.
+  final _buffer = new ByteData(8);
+
+  _JSSecureRandom() {
+    var crypto = JS('', 'self.crypto');
+    if (crypto != null) {
+      var getRandomValues = JS('', '#.getRandomValues', crypto);
+      if (getRandomValues != null) {
+        return;
+      }
+    }
+    throw new UnsupportedError(
+        'No source of cryptographically secure random numbers available.');
+  }
+
+  /// Fill _buffer from [start] to `start + length` with random bytes.
+  void _getRandomBytes(int start, int length) {
+    JS('void', 'crypto.getRandomValues(#)',
+        _buffer.buffer.asUint8List(start, length));
+  }
+
+  bool nextBool() {
+    _getRandomBytes(0, 1);
+    return _buffer.getUint8(0).isOdd;
+  }
+
+  double nextDouble() {
+    _getRandomBytes(1, 7);
+    // Set top bits 12 of double to 0x3FF which is the exponent for numbers
+    // between 1.0 and 2.0.
+    _buffer.setUint8(0, 0x3F);
+    int highByte = _buffer.getUint8(1);
+    _buffer.setUint8(1, highByte | 0xF0);
+
+    // Buffer now contains double in the range [1.0-2.0)
+    // with 52 bits of entropy (not 53).
+    // To get 53 bits, we extract the 53rd bit from higthByte before
+    // overwriting it, and add that as a least significant bit.
+    // The getFloat64 method is big-endian as default.
+    double result = _buffer.getFloat64(0) - 1.0;
+    if (highByte & 0x10 != 0) {
+      result += 1.1102230246251565e-16; // pow(2,-53).
+    }
+    return result;
+  }
+
+  int nextInt(int max) {
+    if (max <= 0 || max > _POW2_32) {
+      throw new RangeError('max must be in range 0 < max ≤ 2^32, was $max');
+    }
+    int byteCount = 1;
+    if (max > 0xFF) {
+      byteCount++;
+      if (max > 0xFFFF) {
+        byteCount++;
+        if (max > 0xFFFFFF) {
+          byteCount++;
+        }
+      }
+    }
+    _buffer.setUint32(0, 0);
+    int start = 4 - byteCount;
+    int randomLimit = pow(256, byteCount);
+    while (true) {
+      _getRandomBytes(start, byteCount);
+      // The getUint32 method is big-endian as default.
+      int random = _buffer.getUint32(0);
+      if (max & (max - 1) == 0) {
+        // Max is power of 2.
+        return random & (max - 1);
+      }
+      int result = random.remainder(max);
+      // Ensure results have equal probability by rejecting values in the
+      // last range of k*max .. 256**byteCount.
+      // TODO: Consider picking a higher byte count if the last range is a
+      // significant portion of the entire range - a 50% chance of having
+      // to use two more bytes is no worse than always using one more.
+      if (random - result + max < randomLimit) {
+        return result;
+      }
+    }
+  }
+}
diff --git a/sdk_nnbd/lib/_internal/js_runtime/lib/mirrors_patch_cfe.dart b/sdk_nnbd/lib/_internal/js_runtime/lib/mirrors_patch_cfe.dart
new file mode 100644
index 0000000..6f8018a
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_runtime/lib/mirrors_patch_cfe.dart
@@ -0,0 +1,24 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Patch library for dart:mirrors.
+
+import 'dart:_js_helper' show patch;
+import 'dart:mirrors';
+
+const String _message = 'dart:mirrors is no longer supported for web apps';
+
+@patch
+MirrorSystem currentMirrorSystem() => throw new UnsupportedError(_message);
+
+@patch
+InstanceMirror reflect(Object reflectee) =>
+    throw new UnsupportedError(_message);
+
+@patch
+ClassMirror reflectClass(Type key) => throw new UnsupportedError(_message);
+
+@patch
+TypeMirror reflectType(Type key, [List<Type> typeArguments]) =>
+    throw new UnsupportedError(_message);
diff --git a/sdk_nnbd/lib/_internal/js_runtime/lib/native_helper.dart b/sdk_nnbd/lib/_internal/js_runtime/lib/native_helper.dart
new file mode 100644
index 0000000..ccfa26f
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_runtime/lib/native_helper.dart
@@ -0,0 +1,592 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of _js_helper;
+
+// TODO(ngeoffray): stop using this method once our optimizers can
+// change str1.contains(str2) into str1.indexOf(str2) != -1.
+bool contains(String userAgent, String name) {
+  return JS('int', '#.indexOf(#)', userAgent, name) != -1;
+}
+
+int arrayLength(List array) {
+  return JS('int', '#.length', array);
+}
+
+arrayGet(List array, int index) {
+  return JS('var', '#[#]', array, index);
+}
+
+void arraySet(List array, int index, var value) {
+  JS('var', '#[#] = #', array, index, value);
+}
+
+propertyGet(var object, String property) {
+  return JS('var', '#[#]', object, property);
+}
+
+bool callHasOwnProperty(var function, var object, String property) {
+  return JS('bool', '#.call(#, #)', function, object, property);
+}
+
+void propertySet(var object, String property, var value) {
+  JS('var', '#[#] = #', object, property, value);
+}
+
+getPropertyFromPrototype(var object, String name) {
+  return JS('var', 'Object.getPrototypeOf(#)[#]', object, name);
+}
+
+/// Returns a String tag identifying the type of the native object, or `null`.
+/// The tag is not the name of the type, but usually the name of the JavaScript
+/// constructor function.  Initialized by [initHooks].
+Function getTagFunction;
+
+/// If a lookup via [getTagFunction] on an object [object] that has [tag] fails,
+/// this function is called to provide an alternate tag.  This allows us to fail
+/// gracefully if we can make a good guess, for example, when browsers add novel
+/// kinds of HTMLElement that we have never heard of.  Initialized by
+/// [initHooks].
+Function alternateTagFunction;
+
+/// Returns the prototype for the JavaScript constructor named by an input tag.
+/// Returns `null` if there is no such constructor, or if pre-patching of the
+/// constructor is to be avoided.  Initialized by [initHooks].
+Function prototypeForTagFunction;
+
+String toStringForNativeObject(var obj) {
+  // TODO(sra): Is this code dead?
+  // [getTagFunction] might be uninitialized, but in usual usage, toString has
+  // been called via an interceptor and initialized it.
+  String name = getTagFunction == null
+      ? '<Unknown>'
+      : JS('String', '#', getTagFunction(obj));
+  return 'Instance of $name';
+}
+
+int hashCodeForNativeObject(object) => Primitives.objectHashCode(object);
+
+/// Sets a JavaScript property on an object.
+void defineProperty(var obj, String property, var value) {
+  JS(
+      'void',
+      'Object.defineProperty(#, #, '
+          '{value: #, enumerable: false, writable: true, configurable: true})',
+      obj,
+      property,
+      value);
+}
+
+// Is [obj] an instance of a Dart-defined class?
+bool isDartObject(obj) {
+  // Some of the extra parens here are necessary.
+  return JS(
+      'bool',
+      '((#) instanceof (#))',
+      obj,
+      JS_BUILTIN(
+          'depends:none;effects:none;', JsBuiltin.dartObjectConstructor));
+}
+
+/// A JavaScript object mapping tags to the constructors of interceptors.
+/// This is a JavaScript object with no prototype.
+///
+/// Example: 'HTMLImageElement' maps to the ImageElement class constructor.
+get interceptorsByTag => JS_EMBEDDED_GLOBAL('=Object', INTERCEPTORS_BY_TAG);
+
+/// A JavaScript object mapping tags to `true` or `false`.
+///
+/// Example: 'HTMLImageElement' maps to `true` since, as there are no subclasses
+/// of ImageElement, it is a leaf class in the native class hierarchy.
+get leafTags => JS_EMBEDDED_GLOBAL('=Object', LEAF_TAGS);
+
+String findDispatchTagForInterceptorClass(interceptorClassConstructor) {
+  return JS(
+      '', r'#.#', interceptorClassConstructor, NATIVE_SUPERCLASS_TAG_NAME);
+}
+
+/// Cache of dispatch records for instances.  This is a JavaScript object used
+/// as a map.  Keys are instance tags, e.g. "!SomeThing".  The cache permits the
+/// sharing of one dispatch record between multiple instances.
+var dispatchRecordsForInstanceTags;
+
+/// Cache of interceptors indexed by uncacheable tags, e.g. "~SomeThing".
+/// This is a JavaScript object used as a map.
+var interceptorsForUncacheableTags;
+
+lookupInterceptor(String tag) {
+  return propertyGet(interceptorsByTag, tag);
+}
+
+// Dispatch tag marks are optional prefixes for a dispatch tag that direct how
+// the interceptor for the tag may be cached.
+
+/// No caching permitted.
+const UNCACHED_MARK = '~';
+
+/// Dispatch record must be cached per instance
+const INSTANCE_CACHED_MARK = '!';
+
+/// Dispatch record is cached on immediate prototype.
+const LEAF_MARK = '-';
+
+/// Dispatch record is cached on immediate prototype with a prototype
+/// verification to prevent the interceptor being associated with a subclass
+/// before a dispatch record is cached on the subclass.
+const INTERIOR_MARK = '+';
+
+/// A 'discriminator' function is to be used. TBD.
+const DISCRIMINATED_MARK = '*';
+
+/// Returns the interceptor for a native object, or returns `null` if not found.
+///
+/// A dispatch record is cached according to the specification of the dispatch
+/// tag for [obj].
+@pragma('dart2js:noInline')
+lookupAndCacheInterceptor(obj) {
+  assert(!isDartObject(obj));
+  String tag = getTagFunction(obj);
+
+  // Fast path for instance (and uncached) tags because the lookup is repeated
+  // for each instance (or getInterceptor call).
+  var record = propertyGet(dispatchRecordsForInstanceTags, tag);
+  if (record != null) return patchInstance(obj, record);
+  var interceptor = propertyGet(interceptorsForUncacheableTags, tag);
+  if (interceptor != null) return interceptor;
+
+  // This lookup works for derived dispatch tags because we add them all in
+  // [initNativeDispatch].
+  var interceptorClass = lookupInterceptor(tag);
+  if (interceptorClass == null) {
+    tag = alternateTagFunction(obj, tag);
+    if (tag != null) {
+      // Fast path for instance and uncached tags again.
+      record = propertyGet(dispatchRecordsForInstanceTags, tag);
+      if (record != null) return patchInstance(obj, record);
+      interceptor = propertyGet(interceptorsForUncacheableTags, tag);
+      if (interceptor != null) return interceptor;
+
+      interceptorClass = lookupInterceptor(tag);
+    }
+  }
+
+  if (interceptorClass == null) {
+    // This object is not known to Dart.  There could be several reasons for
+    // that, including (but not limited to):
+    //
+    // * A bug in native code (hopefully this is caught during development).
+    // * An unknown DOM object encountered.
+    // * JavaScript code running in an unexpected context.  For example, on
+    //   node.js.
+    return null;
+  }
+
+  interceptor = JS('', '#.prototype', interceptorClass);
+
+  var mark = JS('String|Null', '#[0]', tag);
+
+  if (mark == INSTANCE_CACHED_MARK) {
+    record = makeLeafDispatchRecord(interceptor);
+    propertySet(dispatchRecordsForInstanceTags, tag, record);
+    return patchInstance(obj, record);
+  }
+
+  if (mark == UNCACHED_MARK) {
+    propertySet(interceptorsForUncacheableTags, tag, interceptor);
+    return interceptor;
+  }
+
+  if (mark == LEAF_MARK) {
+    return patchProto(obj, makeLeafDispatchRecord(interceptor));
+  }
+
+  if (mark == INTERIOR_MARK) {
+    return patchInteriorProto(obj, interceptor);
+  }
+
+  if (mark == DISCRIMINATED_MARK) {
+    // TODO(sra): Use discriminator of tag.
+    throw new UnimplementedError(tag);
+  }
+
+  // [tag] was not explicitly an interior or leaf tag, so
+  var isLeaf = JS('bool', '(#[#]) === true', leafTags, tag);
+  if (isLeaf) {
+    return patchProto(obj, makeLeafDispatchRecord(interceptor));
+  } else {
+    return patchInteriorProto(obj, interceptor);
+  }
+}
+
+patchInstance(obj, record) {
+  setDispatchProperty(obj, record);
+  return dispatchRecordInterceptor(record);
+}
+
+patchProto(obj, record) {
+  setDispatchProperty(JS('', 'Object.getPrototypeOf(#)', obj), record);
+  return dispatchRecordInterceptor(record);
+}
+
+patchInteriorProto(obj, interceptor) {
+  var proto = JS('', 'Object.getPrototypeOf(#)', obj);
+  var record = makeDispatchRecord(interceptor, proto, null, null);
+  setDispatchProperty(proto, record);
+  return interceptor;
+}
+
+makeLeafDispatchRecord(interceptor) {
+  var fieldName = JS_GET_NAME(JsGetName.IS_INDEXABLE_FIELD_NAME);
+  bool indexability = JS('bool', r'!!#[#]', interceptor, fieldName);
+  return makeDispatchRecord(interceptor, false, null, indexability);
+}
+
+makeDefaultDispatchRecord(tag, interceptorClass, proto) {
+  var interceptor = JS('', '#.prototype', interceptorClass);
+  var isLeaf = JS('bool', '(#[#]) === true', leafTags, tag);
+  if (isLeaf) {
+    return makeLeafDispatchRecord(interceptor);
+  } else {
+    return makeDispatchRecord(interceptor, proto, null, null);
+  }
+}
+
+/// [proto] should have no shadowing prototypes that are not also assigned a
+/// dispatch rescord.
+setNativeSubclassDispatchRecord(proto, interceptor) {
+  setDispatchProperty(proto, makeLeafDispatchRecord(interceptor));
+}
+
+String constructorNameFallback(object) {
+  return JS('String', '#(#)', _constructorNameFallback, object);
+}
+
+var initNativeDispatchFlag; // null or true
+
+@pragma('dart2js:noInline')
+void initNativeDispatch() {
+  if (true == initNativeDispatchFlag) return;
+  initNativeDispatchFlag = true;
+  initNativeDispatchContinue();
+}
+
+@pragma('dart2js:noInline')
+void initNativeDispatchContinue() {
+  dispatchRecordsForInstanceTags = JS('', 'Object.create(null)');
+  interceptorsForUncacheableTags = JS('', 'Object.create(null)');
+
+  initHooks();
+
+  // Try to pro-actively patch prototypes of DOM objects.  For each of our known
+  // tags `TAG`, if `window.TAG` is a (constructor) function, set the dispatch
+  // property if the function's prototype to a dispatch record.
+  var map = interceptorsByTag;
+  var tags = JS('JSMutableArray', 'Object.getOwnPropertyNames(#)', map);
+
+  if (JS('bool', 'typeof window != "undefined"')) {
+    var context = JS('=Object', 'window');
+    var fun = JS('=Object', 'function () {}');
+    for (int i = 0; i < tags.length; i++) {
+      var tag = tags[i];
+      var proto = prototypeForTagFunction(tag);
+      if (proto != null) {
+        var interceptorClass = JS('', '#[#]', map, tag);
+        var record = makeDefaultDispatchRecord(tag, interceptorClass, proto);
+        if (record != null) {
+          setDispatchProperty(proto, record);
+          // Ensure the modified prototype is still fast by assigning it to
+          // the prototype property of a function object.
+          JS('', '#.prototype = #', fun, proto);
+        }
+      }
+    }
+  }
+
+  // [interceptorsByTag] maps 'plain' dispatch tags.  Add all the derived
+  // dispatch tags to simplify lookup of derived tags.
+  for (int i = 0; i < tags.length; i++) {
+    var tag = JS('String', '#[#]', tags, i);
+    if (JS('bool', '/^[A-Za-z_]/.test(#)', tag)) {
+      var interceptorClass = propertyGet(map, tag);
+      propertySet(map, INSTANCE_CACHED_MARK + tag, interceptorClass);
+      propertySet(map, UNCACHED_MARK + tag, interceptorClass);
+      propertySet(map, LEAF_MARK + tag, interceptorClass);
+      propertySet(map, INTERIOR_MARK + tag, interceptorClass);
+      propertySet(map, DISCRIMINATED_MARK + tag, interceptorClass);
+    }
+  }
+}
+
+/// Initializes [getTagFunction] and [alternateTagFunction].
+///
+/// These functions are 'hook functions', collectively 'hooks'.  They
+/// initialized by applying a series of hooks transformers.  Built-in hooks
+/// transformers deal with various known browser behaviours.
+///
+/// Each hook tranformer takes a 'hooks' input which is a JavaScript object
+/// containing the hook functions, and returns the same or a new object with
+/// replacements.  The replacements can wrap the originals to provide alternate
+/// or modified behaviour.
+///
+///     { getTag: function(obj) {...},
+///       getUnknownTag: function(obj, tag) {...},
+///       prototypeForTag: function(tag) {...},
+///       discriminator: function(tag) {...},
+///      }
+///
+/// * getTag(obj) returns the dispatch tag, or `null`.
+/// * getUnknownTag(obj, tag) returns a tag when [getTag] fails.
+/// * prototypeForTag(tag) returns the prototype of the constructor for tag,
+///   or `null` if not available or prepatching is undesirable.
+/// * discriminator(tag) returns a function TBD.
+///
+/// The web site can adapt a dart2js application by loading code ahead of the
+/// dart2js application that defines hook transformers to be after the built in
+/// ones.  Code defining a transformer HT should use the following pattern to
+/// ensure multiple transformers can be composed:
+///
+///     (dartNativeDispatchHooksTransformer =
+///      window.dartNativeDispatchHooksTransformer || []).push(HT);
+///
+///
+/// TODO: Implement and describe dispatch tags and their caching methods.
+void initHooks() {
+  // The initial simple hooks:
+  var hooks = JS('', '#()', _baseHooks);
+
+  // Customize for browsers where `object.constructor.name` fails:
+  var _fallbackConstructorHooksTransformer = JS('', '#(#)',
+      _fallbackConstructorHooksTransformerGenerator, _constructorNameFallback);
+  hooks = applyHooksTransformer(_fallbackConstructorHooksTransformer, hooks);
+
+  // Customize for browsers:
+  hooks = applyHooksTransformer(_firefoxHooksTransformer, hooks);
+  hooks = applyHooksTransformer(_ieHooksTransformer, hooks);
+  hooks = applyHooksTransformer(_operaHooksTransformer, hooks);
+  hooks = applyHooksTransformer(_safariHooksTransformer, hooks);
+
+  hooks = applyHooksTransformer(_fixDocumentHooksTransformer, hooks);
+
+  // TODO(sra): Update ShadowDOM polyfil to use
+  // [dartNativeDispatchHooksTransformer] and remove this hook.
+  hooks = applyHooksTransformer(
+      _dartExperimentalFixupGetTagHooksTransformer, hooks);
+
+  // Apply global hooks.
+  //
+  // If defined, dartNativeDispatchHookdTransformer should be a single function
+  // of a JavaScript Array of functions.
+
+  if (JS('bool', 'typeof dartNativeDispatchHooksTransformer != "undefined"')) {
+    var transformers = JS('', 'dartNativeDispatchHooksTransformer');
+    if (JS('bool', 'typeof # == "function"', transformers)) {
+      transformers = [transformers];
+    }
+    if (JS('bool', '#.constructor == Array', transformers)) {
+      for (int i = 0; i < JS('int', '#.length', transformers); i++) {
+        var transformer = JS('', '#[#]', transformers, i);
+        if (JS('bool', 'typeof # == "function"', transformer)) {
+          hooks = applyHooksTransformer(transformer, hooks);
+        }
+      }
+    }
+  }
+
+  var getTag = JS('', '#.getTag', hooks);
+  var getUnknownTag = JS('', '#.getUnknownTag', hooks);
+  var prototypeForTag = JS('', '#.prototypeForTag', hooks);
+
+  getTagFunction = (o) => JS('String|Null', '#(#)', getTag, o);
+  alternateTagFunction =
+      (o, String tag) => JS('String|Null', '#(#, #)', getUnknownTag, o, tag);
+  prototypeForTagFunction =
+      (String tag) => JS('', '#(#)', prototypeForTag, tag);
+}
+
+applyHooksTransformer(transformer, hooks) {
+  var newHooks = JS('=Object|Null', '#(#)', transformer, hooks);
+  return JS('', '# || #', newHooks, hooks);
+}
+
+// JavaScript code fragments.
+//
+// This is a temporary place for the JavaScript code.
+//
+// TODO(sra): These code fragments are not minified.  They could be generated by
+// the code emitter, or JS_CONST could be improved to parse entire functions and
+// take care of the minification.
+
+const _baseHooks = const JS_CONST(r'''
+function() {
+  var toStringFunction = Object.prototype.toString;
+  function getTag(o) {
+    var s = toStringFunction.call(o);
+    return s.substring(8, s.length - 1);
+  }
+  function getUnknownTag(object, tag) {
+    // This code really belongs in [getUnknownTagGenericBrowser] but having it
+    // here allows [getUnknownTag] to be tested on d8.
+    if (/^HTML[A-Z].*Element$/.test(tag)) {
+      // Check that it is not a simple JavaScript object.
+      var name = toStringFunction.call(object);
+      if (name == "[object Object]") return null;
+      return "HTMLElement";
+    }
+  }
+  function getUnknownTagGenericBrowser(object, tag) {
+    if (self.HTMLElement && object instanceof HTMLElement) return "HTMLElement";
+    return getUnknownTag(object, tag);
+  }
+  function prototypeForTag(tag) {
+    if (typeof window == "undefined") return null;
+    if (typeof window[tag] == "undefined") return null;
+    var constructor = window[tag];
+    if (typeof constructor != "function") return null;
+    return constructor.prototype;
+  }
+  function discriminator(tag) { return null; }
+
+  var isBrowser = typeof navigator == "object";
+
+  return {
+    getTag: getTag,
+    getUnknownTag: isBrowser ? getUnknownTagGenericBrowser : getUnknownTag,
+    prototypeForTag: prototypeForTag,
+    discriminator: discriminator };
+}''');
+
+/// Returns the name of the constructor function for browsers where
+/// `object.constructor.name` is not reliable.
+///
+/// This function is split out of
+/// [_fallbackConstructorHooksTransformerGenerator] as it is called from both
+/// the dispatch hooks and via [constructorNameFallback] from objectToString.
+const _constructorNameFallback = const JS_CONST(r'''
+function getTagFallback(o) {
+  var s = Object.prototype.toString.call(o);
+  return s.substring(8, s.length - 1);
+}''');
+
+const _fallbackConstructorHooksTransformerGenerator = const JS_CONST(r'''
+function(getTagFallback) {
+  return function(hooks) {
+    // If we are not in a browser, assume we are in d8.
+    // TODO(sra): Recognize jsshell.
+    if (typeof navigator != "object") return hooks;
+
+    var ua = navigator.userAgent;
+    // TODO(antonm): remove a reference to DumpRenderTree.
+    if (ua.indexOf("DumpRenderTree") >= 0) return hooks;
+    if (ua.indexOf("Chrome") >= 0) {
+      // Confirm constructor name is usable for dispatch.
+      function confirm(p) {
+        return typeof window == "object" && window[p] && window[p].name == p;
+      }
+      if (confirm("Window") && confirm("HTMLElement")) return hooks;
+    }
+
+    hooks.getTag = getTagFallback;
+  };
+}''');
+
+const _ieHooksTransformer = const JS_CONST(r'''
+function(hooks) {
+  var userAgent = typeof navigator == "object" ? navigator.userAgent : "";
+  if (userAgent.indexOf("Trident/") == -1) return hooks;
+
+  var getTag = hooks.getTag;
+
+  var quickMap = {
+    "BeforeUnloadEvent": "Event",
+    "DataTransfer": "Clipboard",
+    "HTMLDDElement": "HTMLElement",
+    "HTMLDTElement": "HTMLElement",
+    "HTMLPhraseElement": "HTMLElement",
+    "Position": "Geoposition"
+  };
+
+  function getTagIE(o) {
+    var tag = getTag(o);
+    var newTag = quickMap[tag];
+    if (newTag) return newTag;
+    // Patches for types which report themselves as Objects.
+    if (tag == "Object") {
+      if (window.DataView && (o instanceof window.DataView)) return "DataView";
+    }
+    return tag;
+  }
+
+  function prototypeForTagIE(tag) {
+    var constructor = window[tag];
+    if (constructor == null) return null;
+    return constructor.prototype;
+  }
+
+  hooks.getTag = getTagIE;
+  hooks.prototypeForTag = prototypeForTagIE;
+}''');
+
+const _fixDocumentHooksTransformer = const JS_CONST(r'''
+function(hooks) {
+  var getTag = hooks.getTag;
+  var prototypeForTag = hooks.prototypeForTag;
+  function getTagFixed(o) {
+    var tag = getTag(o);
+    if (tag == "Document") {
+      // Some browsers and the polymer polyfill call both HTML and XML documents
+      // "Document", so we check for the xmlVersion property, which is the empty
+      // string on HTML documents. Since both dart:html classes Document and
+      // HtmlDocument share the same type, we must patch the instances and not
+      // the prototype.
+      if (!!o.xmlVersion) return "!Document";
+      return "!HTMLDocument";
+    }
+    return tag;
+  }
+
+  function prototypeForTagFixed(tag) {
+    if (tag == "Document") return null;  // Do not pre-patch Document.
+    return prototypeForTag(tag);
+  }
+
+  hooks.getTag = getTagFixed;
+  hooks.prototypeForTag = prototypeForTagFixed;
+}''');
+
+const _firefoxHooksTransformer = const JS_CONST(r'''
+function(hooks) {
+  var userAgent = typeof navigator == "object" ? navigator.userAgent : "";
+  if (userAgent.indexOf("Firefox") == -1) return hooks;
+
+  var getTag = hooks.getTag;
+
+  var quickMap = {
+    "BeforeUnloadEvent": "Event",
+    "DataTransfer": "Clipboard",
+    "GeoGeolocation": "Geolocation",
+    "Location": "!Location",               // Fixes issue 18151
+    "WorkerMessageEvent": "MessageEvent",
+    "XMLDocument": "!Document"};
+
+  function getTagFirefox(o) {
+    var tag = getTag(o);
+    return quickMap[tag] || tag;
+  }
+
+  hooks.getTag = getTagFirefox;
+}''');
+
+const _operaHooksTransformer = const JS_CONST(r'''
+function(hooks) { return hooks; }
+''');
+
+const _safariHooksTransformer = const JS_CONST(r'''
+function(hooks) { return hooks; }
+''');
+
+const _dartExperimentalFixupGetTagHooksTransformer = const JS_CONST(r'''
+function(hooks) {
+  if (typeof dartExperimentalFixupGetTag != "function") return hooks;
+  hooks.getTag = dartExperimentalFixupGetTag(hooks.getTag);
+}''');
diff --git a/sdk_nnbd/lib/_internal/js_runtime/lib/native_typed_data.dart b/sdk_nnbd/lib/_internal/js_runtime/lib/native_typed_data.dart
new file mode 100644
index 0000000..0a91641
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_runtime/lib/native_typed_data.dart
@@ -0,0 +1,1821 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// Specialized integers and floating point numbers,
+/// with SIMD support and efficient lists.
+library dart.typed_data.implementation;
+
+import 'dart:collection' show ListMixin;
+import 'dart:_internal' show FixedLengthListMixin hide Symbol;
+import 'dart:_interceptors' show JSIndexable, JSUInt32, JSUInt31;
+import 'dart:_js_helper'
+    show
+        Creates,
+        JavaScriptIndexingBehavior,
+        JSName,
+        Native,
+        Returns,
+        diagnoseIndexError,
+        diagnoseRangeError;
+import 'dart:_foreign_helper' show JS;
+import 'dart:math' as Math;
+
+import 'dart:typed_data';
+
+@Native('ArrayBuffer')
+class NativeByteBuffer implements ByteBuffer {
+  @JSName('byteLength')
+  final int lengthInBytes;
+
+  Type get runtimeType => ByteBuffer;
+
+  Uint8List asUint8List([int offsetInBytes = 0, int length]) {
+    return new NativeUint8List.view(this, offsetInBytes, length);
+  }
+
+  Int8List asInt8List([int offsetInBytes = 0, int length]) {
+    return new NativeInt8List.view(this, offsetInBytes, length);
+  }
+
+  Uint8ClampedList asUint8ClampedList([int offsetInBytes = 0, int length]) {
+    return new NativeUint8ClampedList.view(this, offsetInBytes, length);
+  }
+
+  Uint16List asUint16List([int offsetInBytes = 0, int length]) {
+    return new NativeUint16List.view(this, offsetInBytes, length);
+  }
+
+  Int16List asInt16List([int offsetInBytes = 0, int length]) {
+    return new NativeInt16List.view(this, offsetInBytes, length);
+  }
+
+  Uint32List asUint32List([int offsetInBytes = 0, int length]) {
+    return new NativeUint32List.view(this, offsetInBytes, length);
+  }
+
+  Int32List asInt32List([int offsetInBytes = 0, int length]) {
+    return new NativeInt32List.view(this, offsetInBytes, length);
+  }
+
+  Uint64List asUint64List([int offsetInBytes = 0, int length]) {
+    throw new UnsupportedError('Uint64List not supported by dart2js.');
+  }
+
+  Int64List asInt64List([int offsetInBytes = 0, int length]) {
+    throw new UnsupportedError('Int64List not supported by dart2js.');
+  }
+
+  Int32x4List asInt32x4List([int offsetInBytes = 0, int length]) {
+    NativeInt32List storage =
+        this.asInt32List(offsetInBytes, length != null ? length * 4 : null);
+    return new NativeInt32x4List._externalStorage(storage);
+  }
+
+  Float32List asFloat32List([int offsetInBytes = 0, int length]) {
+    return new NativeFloat32List.view(this, offsetInBytes, length);
+  }
+
+  Float64List asFloat64List([int offsetInBytes = 0, int length]) {
+    return new NativeFloat64List.view(this, offsetInBytes, length);
+  }
+
+  Float32x4List asFloat32x4List([int offsetInBytes = 0, int length]) {
+    NativeFloat32List storage =
+        this.asFloat32List(offsetInBytes, length != null ? length * 4 : null);
+    return new NativeFloat32x4List._externalStorage(storage);
+  }
+
+  Float64x2List asFloat64x2List([int offsetInBytes = 0, int length]) {
+    NativeFloat64List storage =
+        this.asFloat64List(offsetInBytes, length != null ? length * 2 : null);
+    return new NativeFloat64x2List._externalStorage(storage);
+  }
+
+  ByteData asByteData([int offsetInBytes = 0, int length]) {
+    return new NativeByteData.view(this, offsetInBytes, length);
+  }
+}
+
+/// A fixed-length list of Float32x4 numbers that is viewable as a
+/// [TypedData]. For long lists, this implementation will be considerably more
+/// space- and time-efficient than the default [List] implementation.
+class NativeFloat32x4List extends Object
+    with ListMixin<Float32x4>, FixedLengthListMixin<Float32x4>
+    implements Float32x4List {
+  final NativeFloat32List _storage;
+
+  /// Creates a [Float32x4List] of the specified length (in elements),
+  /// all of whose elements are initially zero.
+  NativeFloat32x4List(int length)
+      : _storage = new NativeFloat32List(length * 4);
+
+  NativeFloat32x4List._externalStorage(this._storage);
+
+  NativeFloat32x4List._slowFromList(List<Float32x4> list)
+      : _storage = new NativeFloat32List(list.length * 4) {
+    for (int i = 0; i < list.length; i++) {
+      var e = list[i];
+      _storage[(i * 4) + 0] = e.x;
+      _storage[(i * 4) + 1] = e.y;
+      _storage[(i * 4) + 2] = e.z;
+      _storage[(i * 4) + 3] = e.w;
+    }
+  }
+
+  Type get runtimeType => Float32x4List;
+
+  /// Creates a [Float32x4List] with the same size as the [elements] list
+  /// and copies over the elements.
+  factory NativeFloat32x4List.fromList(List<Float32x4> list) {
+    if (list is NativeFloat32x4List) {
+      return new NativeFloat32x4List._externalStorage(
+          new NativeFloat32List.fromList(list._storage));
+    } else {
+      return new NativeFloat32x4List._slowFromList(list);
+    }
+  }
+
+  ByteBuffer get buffer => _storage.buffer;
+
+  int get lengthInBytes => _storage.lengthInBytes;
+
+  int get offsetInBytes => _storage.offsetInBytes;
+
+  int get elementSizeInBytes => Float32x4List.bytesPerElement;
+
+  int get length => _storage.length ~/ 4;
+
+  Float32x4 operator [](int index) {
+    _checkValidIndex(index, this, this.length);
+    double _x = _storage[(index * 4) + 0];
+    double _y = _storage[(index * 4) + 1];
+    double _z = _storage[(index * 4) + 2];
+    double _w = _storage[(index * 4) + 3];
+    return new NativeFloat32x4._truncated(_x, _y, _z, _w);
+  }
+
+  void operator []=(int index, Float32x4 value) {
+    _checkValidIndex(index, this, this.length);
+    _storage[(index * 4) + 0] = value.x;
+    _storage[(index * 4) + 1] = value.y;
+    _storage[(index * 4) + 2] = value.z;
+    _storage[(index * 4) + 3] = value.w;
+  }
+
+  Float32x4List sublist(int start, [int end]) {
+    end = _checkValidRange(start, end, this.length);
+    return new NativeFloat32x4List._externalStorage(
+        _storage.sublist(start * 4, end * 4));
+  }
+}
+
+/// A fixed-length list of Int32x4 numbers that is viewable as a
+/// [TypedData]. For long lists, this implementation will be considerably more
+/// space- and time-efficient than the default [List] implementation.
+class NativeInt32x4List extends Object
+    with ListMixin<Int32x4>, FixedLengthListMixin<Int32x4>
+    implements Int32x4List {
+  final Int32List _storage;
+
+  /// Creates a [Int32x4List] of the specified length (in elements),
+  /// all of whose elements are initially zero.
+  NativeInt32x4List(int length) : _storage = new NativeInt32List(length * 4);
+
+  NativeInt32x4List._externalStorage(Int32List storage) : _storage = storage;
+
+  NativeInt32x4List._slowFromList(List<Int32x4> list)
+      : _storage = new NativeInt32List(list.length * 4) {
+    for (int i = 0; i < list.length; i++) {
+      var e = list[i];
+      _storage[(i * 4) + 0] = e.x;
+      _storage[(i * 4) + 1] = e.y;
+      _storage[(i * 4) + 2] = e.z;
+      _storage[(i * 4) + 3] = e.w;
+    }
+  }
+
+  Type get runtimeType => Int32x4List;
+
+  /// Creates a [Int32x4List] with the same size as the [elements] list
+  /// and copies over the elements.
+  factory NativeInt32x4List.fromList(List<Int32x4> list) {
+    if (list is NativeInt32x4List) {
+      return new NativeInt32x4List._externalStorage(
+          new NativeInt32List.fromList(list._storage));
+    } else {
+      return new NativeInt32x4List._slowFromList(list);
+    }
+  }
+
+  ByteBuffer get buffer => _storage.buffer;
+
+  int get lengthInBytes => _storage.lengthInBytes;
+
+  int get offsetInBytes => _storage.offsetInBytes;
+
+  int get elementSizeInBytes => Int32x4List.bytesPerElement;
+
+  int get length => _storage.length ~/ 4;
+
+  Int32x4 operator [](int index) {
+    _checkValidIndex(index, this, this.length);
+    int _x = _storage[(index * 4) + 0];
+    int _y = _storage[(index * 4) + 1];
+    int _z = _storage[(index * 4) + 2];
+    int _w = _storage[(index * 4) + 3];
+    return new NativeInt32x4._truncated(_x, _y, _z, _w);
+  }
+
+  void operator []=(int index, Int32x4 value) {
+    _checkValidIndex(index, this, this.length);
+    _storage[(index * 4) + 0] = value.x;
+    _storage[(index * 4) + 1] = value.y;
+    _storage[(index * 4) + 2] = value.z;
+    _storage[(index * 4) + 3] = value.w;
+  }
+
+  Int32x4List sublist(int start, [int end]) {
+    end = _checkValidRange(start, end, this.length);
+    return new NativeInt32x4List._externalStorage(
+        _storage.sublist(start * 4, end * 4));
+  }
+}
+
+/// A fixed-length list of Float64x2 numbers that is viewable as a
+/// [TypedData]. For long lists, this implementation will be considerably more
+/// space- and time-efficient than the default [List] implementation.
+class NativeFloat64x2List extends Object
+    with ListMixin<Float64x2>, FixedLengthListMixin<Float64x2>
+    implements Float64x2List {
+  final NativeFloat64List _storage;
+
+  /// Creates a [Float64x2List] of the specified length (in elements),
+  /// all of whose elements are initially zero.
+  NativeFloat64x2List(int length)
+      : _storage = new NativeFloat64List(length * 2);
+
+  NativeFloat64x2List._externalStorage(this._storage);
+
+  NativeFloat64x2List._slowFromList(List<Float64x2> list)
+      : _storage = new NativeFloat64List(list.length * 2) {
+    for (int i = 0; i < list.length; i++) {
+      var e = list[i];
+      _storage[(i * 2) + 0] = e.x;
+      _storage[(i * 2) + 1] = e.y;
+    }
+  }
+
+  /// Creates a [Float64x2List] with the same size as the [elements] list
+  /// and copies over the elements.
+  factory NativeFloat64x2List.fromList(List<Float64x2> list) {
+    if (list is NativeFloat64x2List) {
+      return new NativeFloat64x2List._externalStorage(
+          new NativeFloat64List.fromList(list._storage));
+    } else {
+      return new NativeFloat64x2List._slowFromList(list);
+    }
+  }
+
+  Type get runtimeType => Float64x2List;
+
+  ByteBuffer get buffer => _storage.buffer;
+
+  int get lengthInBytes => _storage.lengthInBytes;
+
+  int get offsetInBytes => _storage.offsetInBytes;
+
+  int get elementSizeInBytes => Float64x2List.bytesPerElement;
+
+  int get length => _storage.length ~/ 2;
+
+  Float64x2 operator [](int index) {
+    _checkValidIndex(index, this, this.length);
+    double _x = _storage[(index * 2) + 0];
+    double _y = _storage[(index * 2) + 1];
+    return new Float64x2(_x, _y);
+  }
+
+  void operator []=(int index, Float64x2 value) {
+    _checkValidIndex(index, this, this.length);
+    _storage[(index * 2) + 0] = value.x;
+    _storage[(index * 2) + 1] = value.y;
+  }
+
+  Float64x2List sublist(int start, [int end]) {
+    end = _checkValidRange(start, end, this.length);
+    return new NativeFloat64x2List._externalStorage(
+        _storage.sublist(start * 2, end * 2));
+  }
+}
+
+@Native('ArrayBufferView')
+class NativeTypedData implements TypedData {
+  /// Returns the byte buffer associated with this object.
+  @Creates('NativeByteBuffer')
+  // May be Null for IE's CanvasPixelArray.
+  @Returns('NativeByteBuffer|Null')
+  final ByteBuffer buffer;
+
+  /// Returns the length of this view, in bytes.
+  @JSName('byteLength')
+  final int lengthInBytes;
+
+  /// Returns the offset in bytes into the underlying byte buffer of this view.
+  @JSName('byteOffset')
+  final int offsetInBytes;
+
+  /// Returns the number of bytes in the representation of each element in this
+  /// list.
+  @JSName('BYTES_PER_ELEMENT')
+  final int elementSizeInBytes;
+
+  void _invalidPosition(int position, int length, String name) {
+    if (position is! int) {
+      throw new ArgumentError.value(position, name, 'Invalid list position');
+    } else {
+      throw new RangeError.range(position, 0, length, name);
+    }
+  }
+
+  void _checkPosition(int position, int length, String name) {
+    if (JS('bool', '(# >>> 0) !== #', position, position) ||
+        JS('int', '#', position) > length) {
+      // 'int' guaranteed by above test.
+      _invalidPosition(position, length, name);
+    }
+  }
+}
+
+// Validates the unnamed constructor length argument.  Checking is necessary
+// because passing unvalidated values to the native constructors can cause
+// conversions or create views.
+int _checkLength(length) {
+  return length is int
+      ? length
+      : throw new ArgumentError('Invalid length $length');
+}
+
+// Validates `.view` constructor arguments.  Checking is necessary because
+// passing unvalidated values to the native constructors can cause conversions
+// (e.g. String arguments) or create typed data objects that are not actually
+// views of the input.
+void _checkViewArguments(buffer, offsetInBytes, length) {
+  if (buffer is! NativeByteBuffer) {
+    throw new ArgumentError('Invalid view buffer');
+  }
+  if (offsetInBytes is! int) {
+    throw new ArgumentError('Invalid view offsetInBytes $offsetInBytes');
+  }
+  if (length != null && length is! int) {
+    throw new ArgumentError('Invalid view length $length');
+  }
+}
+
+// Ensures that [list] is a JavaScript Array or a typed array.  If necessary,
+// returns a copy of the list.
+List _ensureNativeList(List list) {
+  if (list is JSIndexable) return list;
+  List result = new List(list.length);
+  for (int i = 0; i < list.length; i++) {
+    result[i] = list[i];
+  }
+  return result;
+}
+
+@Native('DataView')
+class NativeByteData extends NativeTypedData implements ByteData {
+  /// Creates a [ByteData] of the specified length (in elements), all of
+  /// whose elements are initially zero.
+  factory NativeByteData(int length) => _create1(_checkLength(length));
+
+  /// Creates an [ByteData] _view_ of the specified region in the specified
+  /// byte buffer. Changes in the [ByteData] will be visible in the byte
+  /// buffer and vice versa. If the [offsetInBytes] index of the region is not
+  /// specified, it defaults to zero (the first byte in the byte buffer).
+  /// If the length is not specified, it defaults to null, which indicates
+  /// that the view extends to the end of the byte buffer.
+  ///
+  /// Throws [RangeError] if [offsetInBytes] or [length] are negative, or
+  /// if [offsetInBytes] + ([length] * elementSizeInBytes) is greater than
+  /// the length of [buffer].
+  factory NativeByteData.view(
+      ByteBuffer buffer, int offsetInBytes, int length) {
+    _checkViewArguments(buffer, offsetInBytes, length);
+    return length == null
+        ? _create2(buffer, offsetInBytes)
+        : _create3(buffer, offsetInBytes, length);
+  }
+
+  Type get runtimeType => ByteData;
+
+  int get elementSizeInBytes => 1;
+
+  /// Returns the floating point number represented by the four bytes at
+  /// the specified [byteOffset] in this object, in IEEE 754
+  /// single-precision binary floating-point format (binary32).
+  ///
+  /// Throws [RangeError] if [byteOffset] is negative, or
+  /// `byteOffset + 4` is greater than the length of this object.
+  double getFloat32(int byteOffset, [Endian endian = Endian.big]) =>
+      _getFloat32(byteOffset, Endian.little == endian);
+
+  @JSName('getFloat32')
+  @Returns('num')
+  num _getFloat32(int byteOffset, [bool littleEndian]) native;
+
+  /// Returns the floating point number represented by the eight bytes at
+  /// the specified [byteOffset] in this object, in IEEE 754
+  /// double-precision binary floating-point format (binary64).
+  ///
+  /// Throws [RangeError] if [byteOffset] is negative, or
+  /// `byteOffset + 8` is greater than the length of this object.
+  double getFloat64(int byteOffset, [Endian endian = Endian.big]) =>
+      _getFloat64(byteOffset, Endian.little == endian);
+
+  @JSName('getFloat64')
+  @Returns('num')
+  num _getFloat64(int byteOffset, [bool littleEndian]) native;
+
+  /// Returns the (possibly negative) integer represented by the two bytes at
+  /// the specified [byteOffset] in this object, in two's complement binary
+  /// form.
+  /// The return value will be between 2<sup>15</sup> and 2<sup>15</sup> - 1,
+  /// inclusive.
+  ///
+  /// Throws [RangeError] if [byteOffset] is negative, or
+  /// `byteOffset + 2` is greater than the length of this object.
+  int getInt16(int byteOffset, [Endian endian = Endian.big]) =>
+      _getInt16(byteOffset, Endian.little == endian);
+
+  @JSName('getInt16')
+  @Returns('int')
+  int _getInt16(int byteOffset, [bool littleEndian]) native;
+
+  /// Returns the (possibly negative) integer represented by the four bytes at
+  /// the specified [byteOffset] in this object, in two's complement binary
+  /// form.
+  /// The return value will be between 2<sup>31</sup> and 2<sup>31</sup> - 1,
+  /// inclusive.
+  ///
+  /// Throws [RangeError] if [byteOffset] is negative, or
+  /// `byteOffset + 4` is greater than the length of this object.
+  int getInt32(int byteOffset, [Endian endian = Endian.big]) =>
+      _getInt32(byteOffset, Endian.little == endian);
+
+  @JSName('getInt32')
+  @Returns('int')
+  int _getInt32(int byteOffset, [bool littleEndian]) native;
+
+  /// Returns the (possibly negative) integer represented by the eight bytes at
+  /// the specified [byteOffset] in this object, in two's complement binary
+  /// form.
+  /// The return value will be between 2<sup>63</sup> and 2<sup>63</sup> - 1,
+  /// inclusive.
+  ///
+  /// Throws [RangeError] if [byteOffset] is negative, or
+  /// `byteOffset + 8` is greater than the length of this object.
+  int getInt64(int byteOffset, [Endian endian = Endian.big]) {
+    throw new UnsupportedError('Int64 accessor not supported by dart2js.');
+  }
+
+  /// Returns the (possibly negative) integer represented by the byte at the
+  /// specified [byteOffset] in this object, in two's complement binary
+  /// representation. The return value will be between -128 and 127, inclusive.
+  ///
+  /// Throws [RangeError] if [byteOffset] is negative, or
+  /// greater than or equal to the length of this object.
+  int getInt8(int byteOffset) native;
+
+  /// Returns the positive integer represented by the two bytes starting
+  /// at the specified [byteOffset] in this object, in unsigned binary
+  /// form.
+  /// The return value will be between 0 and  2<sup>16</sup> - 1, inclusive.
+  ///
+  /// Throws [RangeError] if [byteOffset] is negative, or
+  /// `byteOffset + 2` is greater than the length of this object.
+  int getUint16(int byteOffset, [Endian endian = Endian.big]) =>
+      _getUint16(byteOffset, Endian.little == endian);
+
+  @JSName('getUint16')
+  @Returns('JSUInt31')
+  int _getUint16(int byteOffset, [bool littleEndian]) native;
+
+  /// Returns the positive integer represented by the four bytes starting
+  /// at the specified [byteOffset] in this object, in unsigned binary
+  /// form.
+  /// The return value will be between 0 and  2<sup>32</sup> - 1, inclusive.
+  ///
+  /// Throws [RangeError] if [byteOffset] is negative, or
+  /// `byteOffset + 4` is greater than the length of this object.
+  int getUint32(int byteOffset, [Endian endian = Endian.big]) =>
+      _getUint32(byteOffset, Endian.little == endian);
+
+  @JSName('getUint32')
+  @Returns('JSUInt32')
+  int _getUint32(int byteOffset, [bool littleEndian]) native;
+
+  /// Returns the positive integer represented by the eight bytes starting
+  /// at the specified [byteOffset] in this object, in unsigned binary
+  /// form.
+  /// The return value will be between 0 and  2<sup>64</sup> - 1, inclusive.
+  ///
+  /// Throws [RangeError] if [byteOffset] is negative, or
+  /// `byteOffset + 8` is greater than the length of this object.
+  int getUint64(int byteOffset, [Endian endian = Endian.big]) {
+    throw new UnsupportedError('Uint64 accessor not supported by dart2js.');
+  }
+
+  /// Returns the positive integer represented by the byte at the specified
+  /// [byteOffset] in this object, in unsigned binary form. The
+  /// return value will be between 0 and 255, inclusive.
+  ///
+  /// Throws [RangeError] if [byteOffset] is negative, or
+  /// greater than or equal to the length of this object.
+  int getUint8(int byteOffset) native;
+
+  /// Sets the four bytes starting at the specified [byteOffset] in this
+  /// object to the IEEE 754 single-precision binary floating-point
+  /// (binary32) representation of the specified [value].
+  ///
+  /// **Note that this method can lose precision.** The input [value] is
+  /// a 64-bit floating point value, which will be converted to 32-bit
+  /// floating point value by IEEE 754 rounding rules before it is stored.
+  /// If [value] cannot be represented exactly as a binary32, it will be
+  /// converted to the nearest binary32 value.  If two binary32 values are
+  /// equally close, the one whose least significant bit is zero will be used.
+  /// Note that finite (but large) values can be converted to infinity, and
+  /// small non-zero values can be converted to zero.
+  ///
+  /// Throws [RangeError] if [byteOffset] is negative, or
+  /// `byteOffset + 4` is greater than the length of this object.
+  void setFloat32(int byteOffset, num value, [Endian endian = Endian.big]) =>
+      _setFloat32(byteOffset, value, Endian.little == endian);
+
+  @JSName('setFloat32')
+  void _setFloat32(int byteOffset, num value, [bool littleEndian]) native;
+
+  /// Sets the eight bytes starting at the specified [byteOffset] in this
+  /// object to the IEEE 754 double-precision binary floating-point
+  /// (binary64) representation of the specified [value].
+  ///
+  /// Throws [RangeError] if [byteOffset] is negative, or
+  /// `byteOffset + 8` is greater than the length of this object.
+  void setFloat64(int byteOffset, num value, [Endian endian = Endian.big]) =>
+      _setFloat64(byteOffset, value, Endian.little == endian);
+
+  @JSName('setFloat64')
+  void _setFloat64(int byteOffset, num value, [bool littleEndian]) native;
+
+  /// Sets the two bytes starting at the specified [byteOffset] in this
+  /// object to the two's complement binary representation of the specified
+  /// [value], which must fit in two bytes. In other words, [value] must lie
+  /// between 2<sup>15</sup> and 2<sup>15</sup> - 1, inclusive.
+  ///
+  /// Throws [RangeError] if [byteOffset] is negative, or
+  /// `byteOffset + 2` is greater than the length of this object.
+  void setInt16(int byteOffset, int value, [Endian endian = Endian.big]) =>
+      _setInt16(byteOffset, value, Endian.little == endian);
+
+  @JSName('setInt16')
+  void _setInt16(int byteOffset, int value, [bool littleEndian]) native;
+
+  /// Sets the four bytes starting at the specified [byteOffset] in this
+  /// object to the two's complement binary representation of the specified
+  /// [value], which must fit in four bytes. In other words, [value] must lie
+  /// between 2<sup>31</sup> and 2<sup>31</sup> - 1, inclusive.
+  ///
+  /// Throws [RangeError] if [byteOffset] is negative, or
+  /// `byteOffset + 4` is greater than the length of this object.
+  void setInt32(int byteOffset, int value, [Endian endian = Endian.big]) =>
+      _setInt32(byteOffset, value, Endian.little == endian);
+
+  @JSName('setInt32')
+  void _setInt32(int byteOffset, int value, [bool littleEndian]) native;
+
+  /// Sets the eight bytes starting at the specified [byteOffset] in this
+  /// object to the two's complement binary representation of the specified
+  /// [value], which must fit in eight bytes. In other words, [value] must lie
+  /// between 2<sup>63</sup> and 2<sup>63</sup> - 1, inclusive.
+  ///
+  /// Throws [RangeError] if [byteOffset] is negative, or
+  /// `byteOffset + 8` is greater than the length of this object.
+  void setInt64(int byteOffset, int value, [Endian endian = Endian.big]) {
+    throw new UnsupportedError('Int64 accessor not supported by dart2js.');
+  }
+
+  /// Sets the byte at the specified [byteOffset] in this object to the
+  /// two's complement binary representation of the specified [value], which
+  /// must fit in a single byte. In other words, [value] must be between
+  /// -128 and 127, inclusive.
+  ///
+  /// Throws [RangeError] if [byteOffset] is negative, or
+  /// greater than or equal to the length of this object.
+  void setInt8(int byteOffset, int value) native;
+
+  /// Sets the two bytes starting at the specified [byteOffset] in this object
+  /// to the unsigned binary representation of the specified [value],
+  /// which must fit in two bytes. in other words, [value] must be between
+  /// 0 and 2<sup>16</sup> - 1, inclusive.
+  ///
+  /// Throws [RangeError] if [byteOffset] is negative, or
+  /// `byteOffset + 2` is greater than the length of this object.
+  void setUint16(int byteOffset, int value, [Endian endian = Endian.big]) =>
+      _setUint16(byteOffset, value, Endian.little == endian);
+
+  @JSName('setUint16')
+  void _setUint16(int byteOffset, int value, [bool littleEndian]) native;
+
+  /// Sets the four bytes starting at the specified [byteOffset] in this object
+  /// to the unsigned binary representation of the specified [value],
+  /// which must fit in four bytes. in other words, [value] must be between
+  /// 0 and 2<sup>32</sup> - 1, inclusive.
+  ///
+  /// Throws [RangeError] if [byteOffset] is negative, or
+  /// `byteOffset + 4` is greater than the length of this object.
+  void setUint32(int byteOffset, int value, [Endian endian = Endian.big]) =>
+      _setUint32(byteOffset, value, Endian.little == endian);
+
+  @JSName('setUint32')
+  void _setUint32(int byteOffset, int value, [bool littleEndian]) native;
+
+  /// Sets the eight bytes starting at the specified [byteOffset] in this object
+  /// to the unsigned binary representation of the specified [value],
+  /// which must fit in eight bytes. in other words, [value] must be between
+  /// 0 and 2<sup>64</sup> - 1, inclusive.
+  ///
+  /// Throws [RangeError] if [byteOffset] is negative, or
+  /// `byteOffset + 8` is greater than the length of this object.
+  void setUint64(int byteOffset, int value, [Endian endian = Endian.big]) {
+    throw new UnsupportedError('Uint64 accessor not supported by dart2js.');
+  }
+
+  /// Sets the byte at the specified [byteOffset] in this object to the
+  /// unsigned binary representation of the specified [value], which must fit
+  /// in a single byte. in other words, [value] must be between 0 and 255,
+  /// inclusive.
+  ///
+  /// Throws [RangeError] if [byteOffset] is negative,
+  /// or greater than or equal to the length of this object.
+  void setUint8(int byteOffset, int value) native;
+
+  static NativeByteData _create1(arg) =>
+      JS('NativeByteData', 'new DataView(new ArrayBuffer(#))', arg);
+
+  static NativeByteData _create2(arg1, arg2) =>
+      JS('NativeByteData', 'new DataView(#, #)', arg1, arg2);
+
+  static NativeByteData _create3(arg1, arg2, arg3) =>
+      JS('NativeByteData', 'new DataView(#, #, #)', arg1, arg2, arg3);
+}
+
+abstract class NativeTypedArray extends NativeTypedData
+    implements JavaScriptIndexingBehavior {
+  int get length => JS('JSUInt32', '#.length', this);
+
+  void _setRangeFast(
+      int start, int end, NativeTypedArray source, int skipCount) {
+    int targetLength = this.length;
+    _checkPosition(start, targetLength, 'start');
+    _checkPosition(end, targetLength, 'end');
+    if (start > end) throw new RangeError.range(start, 0, end);
+    int count = end - start;
+
+    if (skipCount < 0) throw new ArgumentError(skipCount);
+
+    int sourceLength = source.length;
+    if (sourceLength - skipCount < count) {
+      throw new StateError('Not enough elements');
+    }
+
+    if (skipCount != 0 || sourceLength != count) {
+      // Create a view of the exact subrange that is copied from the source.
+      source = JS('', '#.subarray(#, #)', source, skipCount, skipCount + count);
+    }
+    JS('void', '#.set(#, #)', this, source, start);
+  }
+}
+
+abstract class NativeTypedArrayOfDouble extends NativeTypedArray
+    with ListMixin<double>, FixedLengthListMixin<double> {
+  double operator [](int index) {
+    _checkValidIndex(index, this, this.length);
+    return JS('num', '#[#]', this, index);
+  }
+
+  void operator []=(int index, double value) {
+    _checkValidIndex(index, this, this.length);
+    JS('void', '#[#] = #', this, index, value);
+  }
+
+  void setRange(int start, int end, Iterable<double> iterable,
+      [int skipCount = 0]) {
+    if (iterable is NativeTypedArrayOfDouble) {
+      _setRangeFast(start, end, iterable, skipCount);
+      return;
+    }
+    super.setRange(start, end, iterable, skipCount);
+  }
+}
+
+abstract class NativeTypedArrayOfInt extends NativeTypedArray
+    with ListMixin<int>, FixedLengthListMixin<int>
+    implements List<int> {
+  // operator[]() is not here since different versions have different return
+  // types
+
+  void operator []=(int index, int value) {
+    _checkValidIndex(index, this, this.length);
+    JS('void', '#[#] = #', this, index, value);
+  }
+
+  void setRange(int start, int end, Iterable<int> iterable,
+      [int skipCount = 0]) {
+    if (iterable is NativeTypedArrayOfInt) {
+      _setRangeFast(start, end, iterable, skipCount);
+      return;
+    }
+    super.setRange(start, end, iterable, skipCount);
+  }
+}
+
+@Native('Float32Array')
+class NativeFloat32List extends NativeTypedArrayOfDouble
+    implements Float32List {
+  factory NativeFloat32List(int length) => _create1(_checkLength(length));
+
+  factory NativeFloat32List.fromList(List<double> elements) =>
+      _create1(_ensureNativeList(elements));
+
+  factory NativeFloat32List.view(
+      ByteBuffer buffer, int offsetInBytes, int length) {
+    _checkViewArguments(buffer, offsetInBytes, length);
+    return length == null
+        ? _create2(buffer, offsetInBytes)
+        : _create3(buffer, offsetInBytes, length);
+  }
+
+  Type get runtimeType => Float32List;
+
+  Float32List sublist(int start, [int end]) {
+    end = _checkValidRange(start, end, this.length);
+    var source = JS('NativeFloat32List', '#.subarray(#, #)', this, start, end);
+    return _create1(source);
+  }
+
+  static NativeFloat32List _create1(arg) =>
+      JS('NativeFloat32List', 'new Float32Array(#)', arg);
+
+  static NativeFloat32List _create2(arg1, arg2) =>
+      JS('NativeFloat32List', 'new Float32Array(#, #)', arg1, arg2);
+
+  static NativeFloat32List _create3(arg1, arg2, arg3) =>
+      JS('NativeFloat32List', 'new Float32Array(#, #, #)', arg1, arg2, arg3);
+}
+
+@Native('Float64Array')
+class NativeFloat64List extends NativeTypedArrayOfDouble
+    implements Float64List {
+  factory NativeFloat64List(int length) => _create1(_checkLength(length));
+
+  factory NativeFloat64List.fromList(List<double> elements) =>
+      _create1(_ensureNativeList(elements));
+
+  factory NativeFloat64List.view(
+      ByteBuffer buffer, int offsetInBytes, int length) {
+    _checkViewArguments(buffer, offsetInBytes, length);
+    return length == null
+        ? _create2(buffer, offsetInBytes)
+        : _create3(buffer, offsetInBytes, length);
+  }
+
+  Type get runtimeType => Float64List;
+
+  Float64List sublist(int start, [int end]) {
+    end = _checkValidRange(start, end, this.length);
+    var source = JS('NativeFloat64List', '#.subarray(#, #)', this, start, end);
+    return _create1(source);
+  }
+
+  static NativeFloat64List _create1(arg) =>
+      JS('NativeFloat64List', 'new Float64Array(#)', arg);
+
+  static NativeFloat64List _create2(arg1, arg2) =>
+      JS('NativeFloat64List', 'new Float64Array(#, #)', arg1, arg2);
+
+  static NativeFloat64List _create3(arg1, arg2, arg3) =>
+      JS('NativeFloat64List', 'new Float64Array(#, #, #)', arg1, arg2, arg3);
+}
+
+@Native('Int16Array')
+class NativeInt16List extends NativeTypedArrayOfInt implements Int16List {
+  factory NativeInt16List(int length) => _create1(_checkLength(length));
+
+  factory NativeInt16List.fromList(List<int> elements) =>
+      _create1(_ensureNativeList(elements));
+
+  factory NativeInt16List.view(
+      NativeByteBuffer buffer, int offsetInBytes, int length) {
+    _checkViewArguments(buffer, offsetInBytes, length);
+    return length == null
+        ? _create2(buffer, offsetInBytes)
+        : _create3(buffer, offsetInBytes, length);
+  }
+
+  Type get runtimeType => Int16List;
+
+  int operator [](int index) {
+    _checkValidIndex(index, this, this.length);
+    return JS('int', '#[#]', this, index);
+  }
+
+  Int16List sublist(int start, [int end]) {
+    end = _checkValidRange(start, end, this.length);
+    var source = JS('NativeInt16List', '#.subarray(#, #)', this, start, end);
+    return _create1(source);
+  }
+
+  static NativeInt16List _create1(arg) =>
+      JS('NativeInt16List', 'new Int16Array(#)', arg);
+
+  static NativeInt16List _create2(arg1, arg2) =>
+      JS('NativeInt16List', 'new Int16Array(#, #)', arg1, arg2);
+
+  static NativeInt16List _create3(arg1, arg2, arg3) =>
+      JS('NativeInt16List', 'new Int16Array(#, #, #)', arg1, arg2, arg3);
+}
+
+@Native('Int32Array')
+class NativeInt32List extends NativeTypedArrayOfInt implements Int32List {
+  factory NativeInt32List(int length) => _create1(_checkLength(length));
+
+  factory NativeInt32List.fromList(List<int> elements) =>
+      _create1(_ensureNativeList(elements));
+
+  factory NativeInt32List.view(
+      ByteBuffer buffer, int offsetInBytes, int length) {
+    _checkViewArguments(buffer, offsetInBytes, length);
+    return length == null
+        ? _create2(buffer, offsetInBytes)
+        : _create3(buffer, offsetInBytes, length);
+  }
+
+  Type get runtimeType => Int32List;
+
+  int operator [](int index) {
+    _checkValidIndex(index, this, this.length);
+    return JS('int', '#[#]', this, index);
+  }
+
+  Int32List sublist(int start, [int end]) {
+    end = _checkValidRange(start, end, this.length);
+    var source = JS('NativeInt32List', '#.subarray(#, #)', this, start, end);
+    return _create1(source);
+  }
+
+  static NativeInt32List _create1(arg) =>
+      JS('NativeInt32List', 'new Int32Array(#)', arg);
+
+  static NativeInt32List _create2(arg1, arg2) =>
+      JS('NativeInt32List', 'new Int32Array(#, #)', arg1, arg2);
+
+  static NativeInt32List _create3(arg1, arg2, arg3) =>
+      JS('NativeInt32List', 'new Int32Array(#, #, #)', arg1, arg2, arg3);
+}
+
+@Native('Int8Array')
+class NativeInt8List extends NativeTypedArrayOfInt implements Int8List {
+  factory NativeInt8List(int length) => _create1(_checkLength(length));
+
+  factory NativeInt8List.fromList(List<int> elements) =>
+      _create1(_ensureNativeList(elements));
+
+  factory NativeInt8List.view(
+      ByteBuffer buffer, int offsetInBytes, int length) {
+    _checkViewArguments(buffer, offsetInBytes, length);
+    return length == null
+        ? _create2(buffer, offsetInBytes)
+        : _create3(buffer, offsetInBytes, length);
+  }
+
+  Type get runtimeType => Int8List;
+
+  int operator [](int index) {
+    _checkValidIndex(index, this, this.length);
+    return JS('int', '#[#]', this, index);
+  }
+
+  Int8List sublist(int start, [int end]) {
+    end = _checkValidRange(start, end, this.length);
+    var source = JS('NativeInt8List', '#.subarray(#, #)', this, start, end);
+    return _create1(source);
+  }
+
+  static NativeInt8List _create1(arg) =>
+      JS('NativeInt8List', 'new Int8Array(#)', arg);
+
+  static NativeInt8List _create2(arg1, arg2) =>
+      JS('NativeInt8List', 'new Int8Array(#, #)', arg1, arg2);
+
+  static Int8List _create3(arg1, arg2, arg3) =>
+      JS('NativeInt8List', 'new Int8Array(#, #, #)', arg1, arg2, arg3);
+}
+
+@Native('Uint16Array')
+class NativeUint16List extends NativeTypedArrayOfInt implements Uint16List {
+  factory NativeUint16List(int length) => _create1(_checkLength(length));
+
+  factory NativeUint16List.fromList(List<int> list) =>
+      _create1(_ensureNativeList(list));
+
+  factory NativeUint16List.view(
+      ByteBuffer buffer, int offsetInBytes, int length) {
+    _checkViewArguments(buffer, offsetInBytes, length);
+    return length == null
+        ? _create2(buffer, offsetInBytes)
+        : _create3(buffer, offsetInBytes, length);
+  }
+
+  Type get runtimeType => Uint16List;
+
+  int operator [](int index) {
+    _checkValidIndex(index, this, this.length);
+    return JS('JSUInt31', '#[#]', this, index);
+  }
+
+  Uint16List sublist(int start, [int end]) {
+    end = _checkValidRange(start, end, this.length);
+    var source = JS('NativeUint16List', '#.subarray(#, #)', this, start, end);
+    return _create1(source);
+  }
+
+  static NativeUint16List _create1(arg) =>
+      JS('NativeUint16List', 'new Uint16Array(#)', arg);
+
+  static NativeUint16List _create2(arg1, arg2) =>
+      JS('NativeUint16List', 'new Uint16Array(#, #)', arg1, arg2);
+
+  static NativeUint16List _create3(arg1, arg2, arg3) =>
+      JS('NativeUint16List', 'new Uint16Array(#, #, #)', arg1, arg2, arg3);
+}
+
+@Native('Uint32Array')
+class NativeUint32List extends NativeTypedArrayOfInt implements Uint32List {
+  factory NativeUint32List(int length) => _create1(_checkLength(length));
+
+  factory NativeUint32List.fromList(List<int> elements) =>
+      _create1(_ensureNativeList(elements));
+
+  factory NativeUint32List.view(
+      ByteBuffer buffer, int offsetInBytes, int length) {
+    _checkViewArguments(buffer, offsetInBytes, length);
+    return length == null
+        ? _create2(buffer, offsetInBytes)
+        : _create3(buffer, offsetInBytes, length);
+  }
+
+  Type get runtimeType => Uint32List;
+
+  int operator [](int index) {
+    _checkValidIndex(index, this, this.length);
+    return JS('JSUInt32', '#[#]', this, index);
+  }
+
+  Uint32List sublist(int start, [int end]) {
+    end = _checkValidRange(start, end, this.length);
+    var source = JS('NativeUint32List', '#.subarray(#, #)', this, start, end);
+    return _create1(source);
+  }
+
+  static NativeUint32List _create1(arg) =>
+      JS('NativeUint32List', 'new Uint32Array(#)', arg);
+
+  static NativeUint32List _create2(arg1, arg2) =>
+      JS('NativeUint32List', 'new Uint32Array(#, #)', arg1, arg2);
+
+  static NativeUint32List _create3(arg1, arg2, arg3) =>
+      JS('NativeUint32List', 'new Uint32Array(#, #, #)', arg1, arg2, arg3);
+}
+
+@Native('Uint8ClampedArray,CanvasPixelArray')
+class NativeUint8ClampedList extends NativeTypedArrayOfInt
+    implements Uint8ClampedList {
+  factory NativeUint8ClampedList(int length) => _create1(_checkLength(length));
+
+  factory NativeUint8ClampedList.fromList(List<int> elements) =>
+      _create1(_ensureNativeList(elements));
+
+  factory NativeUint8ClampedList.view(
+      ByteBuffer buffer, int offsetInBytes, int length) {
+    _checkViewArguments(buffer, offsetInBytes, length);
+    return length == null
+        ? _create2(buffer, offsetInBytes)
+        : _create3(buffer, offsetInBytes, length);
+  }
+
+  Type get runtimeType => Uint8ClampedList;
+
+  int get length => JS('JSUInt32', '#.length', this);
+
+  int operator [](int index) {
+    _checkValidIndex(index, this, this.length);
+    return JS('JSUInt31', '#[#]', this, index);
+  }
+
+  Uint8ClampedList sublist(int start, [int end]) {
+    end = _checkValidRange(start, end, this.length);
+    var source =
+        JS('NativeUint8ClampedList', '#.subarray(#, #)', this, start, end);
+    return _create1(source);
+  }
+
+  static NativeUint8ClampedList _create1(arg) =>
+      JS('NativeUint8ClampedList', 'new Uint8ClampedArray(#)', arg);
+
+  static NativeUint8ClampedList _create2(arg1, arg2) =>
+      JS('NativeUint8ClampedList', 'new Uint8ClampedArray(#, #)', arg1, arg2);
+
+  static NativeUint8ClampedList _create3(arg1, arg2, arg3) => JS(
+      'NativeUint8ClampedList',
+      'new Uint8ClampedArray(#, #, #)',
+      arg1,
+      arg2,
+      arg3);
+}
+
+// On some browsers Uint8ClampedArray is a subtype of Uint8Array.  Marking
+// Uint8List as !nonleaf ensures that the native dispatch correctly handles
+// the potential for Uint8ClampedArray to 'accidentally' pick up the
+// dispatch record for Uint8List.
+@Native('Uint8Array,!nonleaf')
+class NativeUint8List extends NativeTypedArrayOfInt implements Uint8List {
+  factory NativeUint8List(int length) => _create1(_checkLength(length));
+
+  factory NativeUint8List.fromList(List<int> elements) =>
+      _create1(_ensureNativeList(elements));
+
+  factory NativeUint8List.view(
+      ByteBuffer buffer, int offsetInBytes, int length) {
+    _checkViewArguments(buffer, offsetInBytes, length);
+    return length == null
+        ? _create2(buffer, offsetInBytes)
+        : _create3(buffer, offsetInBytes, length);
+  }
+
+  Type get runtimeType => Uint8List;
+
+  int get length => JS('JSUInt32', '#.length', this);
+
+  int operator [](int index) {
+    _checkValidIndex(index, this, this.length);
+    return JS('JSUInt31', '#[#]', this, index);
+  }
+
+  Uint8List sublist(int start, [int end]) {
+    end = _checkValidRange(start, end, this.length);
+    var source = JS('NativeUint8List', '#.subarray(#, #)', this, start, end);
+    return _create1(source);
+  }
+
+  static NativeUint8List _create1(arg) =>
+      JS('NativeUint8List', 'new Uint8Array(#)', arg);
+
+  static NativeUint8List _create2(arg1, arg2) =>
+      JS('NativeUint8List', 'new Uint8Array(#, #)', arg1, arg2);
+
+  static NativeUint8List _create3(arg1, arg2, arg3) =>
+      JS('NativeUint8List', 'new Uint8Array(#, #, #)', arg1, arg2, arg3);
+}
+
+/// Implementation of Dart Float32x4 immutable value type and operations.
+/// Float32x4 stores 4 32-bit floating point values in "lanes".
+/// The lanes are "x", "y", "z", and "w" respectively.
+class NativeFloat32x4 implements Float32x4 {
+  final double x;
+  final double y;
+  final double z;
+  final double w;
+
+  static final NativeFloat32List _list = new NativeFloat32List(4);
+  static final Uint32List _uint32view = _list.buffer.asUint32List();
+
+  static _truncate(x) {
+    _list[0] = x;
+    return _list[0];
+  }
+
+  NativeFloat32x4(double x, double y, double z, double w)
+      : this.x = _truncate(x),
+        this.y = _truncate(y),
+        this.z = _truncate(z),
+        this.w = _truncate(w) {
+    // We would prefer to check for `double` but in dart2js we can't see the
+    // difference anyway.
+    if (x is! num) throw new ArgumentError(x);
+    if (y is! num) throw new ArgumentError(y);
+    if (z is! num) throw new ArgumentError(z);
+    if (w is! num) throw new ArgumentError(w);
+  }
+
+  NativeFloat32x4.splat(double v) : this(v, v, v, v);
+  NativeFloat32x4.zero() : this._truncated(0.0, 0.0, 0.0, 0.0);
+
+  /// Returns a bit-wise copy of [i] as a Float32x4.
+  factory NativeFloat32x4.fromInt32x4Bits(Int32x4 i) {
+    _uint32view[0] = i.x;
+    _uint32view[1] = i.y;
+    _uint32view[2] = i.z;
+    _uint32view[3] = i.w;
+    return new NativeFloat32x4._truncated(
+        _list[0], _list[1], _list[2], _list[3]);
+  }
+
+  NativeFloat32x4.fromFloat64x2(Float64x2 v)
+      : this._truncated(_truncate(v.x), _truncate(v.y), 0.0, 0.0);
+
+  /// Creates a new NativeFloat32x4.
+  ///
+  /// Does not verify if the given arguments are non-null.
+  NativeFloat32x4._doubles(double x, double y, double z, double w)
+      : this.x = _truncate(x),
+        this.y = _truncate(y),
+        this.z = _truncate(z),
+        this.w = _truncate(w);
+
+  /// Creates a new NativeFloat32x4.
+  ///
+  /// The constructor does not truncate the arguments. They must already be in
+  /// the correct range. It does not verify the type of the given arguments,
+  /// either.
+  NativeFloat32x4._truncated(this.x, this.y, this.z, this.w);
+
+  String toString() {
+    return '[$x, $y, $z, $w]';
+  }
+
+  /// Addition operator.
+  Float32x4 operator +(Float32x4 other) {
+    double _x = x + other.x;
+    double _y = y + other.y;
+    double _z = z + other.z;
+    double _w = w + other.w;
+    return new NativeFloat32x4._doubles(_x, _y, _z, _w);
+  }
+
+  /// Negate operator.
+  Float32x4 operator -() {
+    return new NativeFloat32x4._truncated(-x, -y, -z, -w);
+  }
+
+  /// Subtraction operator.
+  Float32x4 operator -(Float32x4 other) {
+    double _x = x - other.x;
+    double _y = y - other.y;
+    double _z = z - other.z;
+    double _w = w - other.w;
+    return new NativeFloat32x4._doubles(_x, _y, _z, _w);
+  }
+
+  /// Multiplication operator.
+  Float32x4 operator *(Float32x4 other) {
+    double _x = x * other.x;
+    double _y = y * other.y;
+    double _z = z * other.z;
+    double _w = w * other.w;
+    return new NativeFloat32x4._doubles(_x, _y, _z, _w);
+  }
+
+  /// Division operator.
+  Float32x4 operator /(Float32x4 other) {
+    double _x = x / other.x;
+    double _y = y / other.y;
+    double _z = z / other.z;
+    double _w = w / other.w;
+    return new NativeFloat32x4._doubles(_x, _y, _z, _w);
+  }
+
+  /// Relational less than.
+  Int32x4 lessThan(Float32x4 other) {
+    bool _cx = x < other.x;
+    bool _cy = y < other.y;
+    bool _cz = z < other.z;
+    bool _cw = w < other.w;
+    return new NativeInt32x4._truncated(
+        _cx ? -1 : 0, _cy ? -1 : 0, _cz ? -1 : 0, _cw ? -1 : 0);
+  }
+
+  /// Relational less than or equal.
+  Int32x4 lessThanOrEqual(Float32x4 other) {
+    bool _cx = x <= other.x;
+    bool _cy = y <= other.y;
+    bool _cz = z <= other.z;
+    bool _cw = w <= other.w;
+    return new NativeInt32x4._truncated(
+        _cx ? -1 : 0, _cy ? -1 : 0, _cz ? -1 : 0, _cw ? -1 : 0);
+  }
+
+  /// Relational greater than.
+  Int32x4 greaterThan(Float32x4 other) {
+    bool _cx = x > other.x;
+    bool _cy = y > other.y;
+    bool _cz = z > other.z;
+    bool _cw = w > other.w;
+    return new NativeInt32x4._truncated(
+        _cx ? -1 : 0, _cy ? -1 : 0, _cz ? -1 : 0, _cw ? -1 : 0);
+  }
+
+  /// Relational greater than or equal.
+  Int32x4 greaterThanOrEqual(Float32x4 other) {
+    bool _cx = x >= other.x;
+    bool _cy = y >= other.y;
+    bool _cz = z >= other.z;
+    bool _cw = w >= other.w;
+    return new NativeInt32x4._truncated(
+        _cx ? -1 : 0, _cy ? -1 : 0, _cz ? -1 : 0, _cw ? -1 : 0);
+  }
+
+  /// Relational equal.
+  Int32x4 equal(Float32x4 other) {
+    bool _cx = x == other.x;
+    bool _cy = y == other.y;
+    bool _cz = z == other.z;
+    bool _cw = w == other.w;
+    return new NativeInt32x4._truncated(
+        _cx ? -1 : 0, _cy ? -1 : 0, _cz ? -1 : 0, _cw ? -1 : 0);
+  }
+
+  /// Relational not-equal.
+  Int32x4 notEqual(Float32x4 other) {
+    bool _cx = x != other.x;
+    bool _cy = y != other.y;
+    bool _cz = z != other.z;
+    bool _cw = w != other.w;
+    return new NativeInt32x4._truncated(
+        _cx ? -1 : 0, _cy ? -1 : 0, _cz ? -1 : 0, _cw ? -1 : 0);
+  }
+
+  /// Returns a copy of [this] each lane being scaled by [s].
+  Float32x4 scale(double s) {
+    double _x = s * x;
+    double _y = s * y;
+    double _z = s * z;
+    double _w = s * w;
+    return new NativeFloat32x4._doubles(_x, _y, _z, _w);
+  }
+
+  /// Returns the absolute value of this [Float32x4].
+  Float32x4 abs() {
+    double _x = x.abs();
+    double _y = y.abs();
+    double _z = z.abs();
+    double _w = w.abs();
+    return new NativeFloat32x4._truncated(_x, _y, _z, _w);
+  }
+
+  /// Clamps [this] to be in the range [lowerLimit]-[upperLimit].
+  Float32x4 clamp(Float32x4 lowerLimit, Float32x4 upperLimit) {
+    double _lx = lowerLimit.x;
+    double _ly = lowerLimit.y;
+    double _lz = lowerLimit.z;
+    double _lw = lowerLimit.w;
+    double _ux = upperLimit.x;
+    double _uy = upperLimit.y;
+    double _uz = upperLimit.z;
+    double _uw = upperLimit.w;
+    double _x = x;
+    double _y = y;
+    double _z = z;
+    double _w = w;
+    // MAX(MIN(self, upper), lower).
+    _x = _x > _ux ? _ux : _x;
+    _y = _y > _uy ? _uy : _y;
+    _z = _z > _uz ? _uz : _z;
+    _w = _w > _uw ? _uw : _w;
+    _x = _x < _lx ? _lx : _x;
+    _y = _y < _ly ? _ly : _y;
+    _z = _z < _lz ? _lz : _z;
+    _w = _w < _lw ? _lw : _w;
+    return new NativeFloat32x4._truncated(_x, _y, _z, _w);
+  }
+
+  /// Extract the sign bit from each lane return them in the first 4 bits.
+  int get signMask {
+    var view = _uint32view;
+    var mx, my, mz, mw;
+    _list[0] = x;
+    _list[1] = y;
+    _list[2] = z;
+    _list[3] = w;
+    // This is correct because dart2js uses the unsigned right shift.
+    mx = (view[0] & 0x80000000) >> 31;
+    my = (view[1] & 0x80000000) >> 30;
+    mz = (view[2] & 0x80000000) >> 29;
+    mw = (view[3] & 0x80000000) >> 28;
+    return mx | my | mz | mw;
+  }
+
+  /// Shuffle the lane values. [mask] must be one of the 256 shuffle constants.
+  Float32x4 shuffle(int mask) {
+    if ((mask < 0) || (mask > 255)) {
+      throw new RangeError.range(mask, 0, 255, 'mask');
+    }
+    _list[0] = x;
+    _list[1] = y;
+    _list[2] = z;
+    _list[3] = w;
+
+    double _x = _list[mask & 0x3];
+    double _y = _list[(mask >> 2) & 0x3];
+    double _z = _list[(mask >> 4) & 0x3];
+    double _w = _list[(mask >> 6) & 0x3];
+    return new NativeFloat32x4._truncated(_x, _y, _z, _w);
+  }
+
+  /// Shuffle the lane values in [this] and [other]. The returned
+  /// Float32x4 will have XY lanes from [this] and ZW lanes from [other].
+  /// Uses the same [mask] as [shuffle].
+  Float32x4 shuffleMix(Float32x4 other, int mask) {
+    if ((mask < 0) || (mask > 255)) {
+      throw new RangeError.range(mask, 0, 255, 'mask');
+    }
+    _list[0] = x;
+    _list[1] = y;
+    _list[2] = z;
+    _list[3] = w;
+    double _x = _list[mask & 0x3];
+    double _y = _list[(mask >> 2) & 0x3];
+
+    _list[0] = other.x;
+    _list[1] = other.y;
+    _list[2] = other.z;
+    _list[3] = other.w;
+    double _z = _list[(mask >> 4) & 0x3];
+    double _w = _list[(mask >> 6) & 0x3];
+    return new NativeFloat32x4._truncated(_x, _y, _z, _w);
+  }
+
+  /// Copy [this] and replace the [x] lane.
+  Float32x4 withX(double newX) {
+    return new NativeFloat32x4._truncated(_truncate(newX), y, z, w);
+  }
+
+  /// Copy [this] and replace the [y] lane.
+  Float32x4 withY(double newY) {
+    return new NativeFloat32x4._truncated(x, _truncate(newY), z, w);
+  }
+
+  /// Copy [this] and replace the [z] lane.
+  Float32x4 withZ(double newZ) {
+    return new NativeFloat32x4._truncated(x, y, _truncate(newZ), w);
+  }
+
+  /// Copy [this] and replace the [w] lane.
+  Float32x4 withW(double newW) {
+    return new NativeFloat32x4._truncated(x, y, z, _truncate(newW));
+  }
+
+  /// Returns the lane-wise minimum value in [this] or [other].
+  Float32x4 min(Float32x4 other) {
+    double _x = x < other.x ? x : other.x;
+    double _y = y < other.y ? y : other.y;
+    double _z = z < other.z ? z : other.z;
+    double _w = w < other.w ? w : other.w;
+    return new NativeFloat32x4._truncated(_x, _y, _z, _w);
+  }
+
+  /// Returns the lane-wise maximum value in [this] or [other].
+  Float32x4 max(Float32x4 other) {
+    double _x = x > other.x ? x : other.x;
+    double _y = y > other.y ? y : other.y;
+    double _z = z > other.z ? z : other.z;
+    double _w = w > other.w ? w : other.w;
+    return new NativeFloat32x4._truncated(_x, _y, _z, _w);
+  }
+
+  /// Returns the square root of [this].
+  Float32x4 sqrt() {
+    double _x = Math.sqrt(x);
+    double _y = Math.sqrt(y);
+    double _z = Math.sqrt(z);
+    double _w = Math.sqrt(w);
+    return new NativeFloat32x4._doubles(_x, _y, _z, _w);
+  }
+
+  /// Returns the reciprocal of [this].
+  Float32x4 reciprocal() {
+    double _x = 1.0 / x;
+    double _y = 1.0 / y;
+    double _z = 1.0 / z;
+    double _w = 1.0 / w;
+    return new NativeFloat32x4._doubles(_x, _y, _z, _w);
+  }
+
+  /// Returns the square root of the reciprocal of [this].
+  Float32x4 reciprocalSqrt() {
+    double _x = Math.sqrt(1.0 / x);
+    double _y = Math.sqrt(1.0 / y);
+    double _z = Math.sqrt(1.0 / z);
+    double _w = Math.sqrt(1.0 / w);
+    return new NativeFloat32x4._doubles(_x, _y, _z, _w);
+  }
+}
+
+/// Interface of Dart Int32x4 and operations.
+/// Int32x4 stores 4 32-bit bit-masks in "lanes".
+/// The lanes are "x", "y", "z", and "w" respectively.
+class NativeInt32x4 implements Int32x4 {
+  final int x;
+  final int y;
+  final int z;
+  final int w;
+
+  static final _list = new NativeInt32List(4);
+
+  static _truncate(x) {
+    _list[0] = x;
+    return _list[0];
+  }
+
+  NativeInt32x4(int x, int y, int z, int w)
+      : this.x = _truncate(x),
+        this.y = _truncate(y),
+        this.z = _truncate(z),
+        this.w = _truncate(w) {
+    if (x != this.x && x is! int) throw new ArgumentError(x);
+    if (y != this.y && y is! int) throw new ArgumentError(y);
+    if (z != this.z && z is! int) throw new ArgumentError(z);
+    if (w != this.w && w is! int) throw new ArgumentError(w);
+  }
+
+  NativeInt32x4.bool(bool x, bool y, bool z, bool w)
+      : this.x = x ? -1 : 0,
+        this.y = y ? -1 : 0,
+        this.z = z ? -1 : 0,
+        this.w = w ? -1 : 0;
+
+  /// Returns a bit-wise copy of [f] as a Int32x4.
+  factory NativeInt32x4.fromFloat32x4Bits(Float32x4 f) {
+    NativeFloat32List floatList = NativeFloat32x4._list;
+    floatList[0] = f.x;
+    floatList[1] = f.y;
+    floatList[2] = f.z;
+    floatList[3] = f.w;
+    NativeInt32List view = floatList.buffer.asInt32List();
+    return new NativeInt32x4._truncated(view[0], view[1], view[2], view[3]);
+  }
+
+  NativeInt32x4._truncated(this.x, this.y, this.z, this.w);
+
+  String toString() => '[$x, $y, $z, $w]';
+
+  /// The bit-wise or operator.
+  Int32x4 operator |(Int32x4 other) {
+    // Dart2js uses unsigned results for bit-operations.
+    // We use "JS" to fall back to the signed versions.
+    return new NativeInt32x4._truncated(
+        JS('int', '# | #', x, other.x),
+        JS('int', '# | #', y, other.y),
+        JS('int', '# | #', z, other.z),
+        JS('int', '# | #', w, other.w));
+  }
+
+  /// The bit-wise and operator.
+  Int32x4 operator &(Int32x4 other) {
+    // Dart2js uses unsigned results for bit-operations.
+    // We use "JS" to fall back to the signed versions.
+    return new NativeInt32x4._truncated(
+        JS('int', '# & #', x, other.x),
+        JS('int', '# & #', y, other.y),
+        JS('int', '# & #', z, other.z),
+        JS('int', '# & #', w, other.w));
+  }
+
+  /// The bit-wise xor operator.
+  Int32x4 operator ^(Int32x4 other) {
+    // Dart2js uses unsigned results for bit-operations.
+    // We use "JS" to fall back to the signed versions.
+    return new NativeInt32x4._truncated(
+        JS('int', '# ^ #', x, other.x),
+        JS('int', '# ^ #', y, other.y),
+        JS('int', '# ^ #', z, other.z),
+        JS('int', '# ^ #', w, other.w));
+  }
+
+  Int32x4 operator +(Int32x4 other) {
+    // Avoid going through the typed array by "| 0" the result.
+    return new NativeInt32x4._truncated(
+        JS('int', '(# + #) | 0', x, other.x),
+        JS('int', '(# + #) | 0', y, other.y),
+        JS('int', '(# + #) | 0', z, other.z),
+        JS('int', '(# + #) | 0', w, other.w));
+  }
+
+  Int32x4 operator -(Int32x4 other) {
+    // Avoid going through the typed array by "| 0" the result.
+    return new NativeInt32x4._truncated(
+        JS('int', '(# - #) | 0', x, other.x),
+        JS('int', '(# - #) | 0', y, other.y),
+        JS('int', '(# - #) | 0', z, other.z),
+        JS('int', '(# - #) | 0', w, other.w));
+  }
+
+  Int32x4 operator -() {
+    // Avoid going through the typed array by "| 0" the result.
+    return new NativeInt32x4._truncated(
+        JS('int', '(-#) | 0', x),
+        JS('int', '(-#) | 0', y),
+        JS('int', '(-#) | 0', z),
+        JS('int', '(-#) | 0', w));
+  }
+
+  /// Extract the top bit from each lane return them in the first 4 bits.
+  int get signMask {
+    int mx = (x & 0x80000000) >> 31;
+    int my = (y & 0x80000000) >> 31;
+    int mz = (z & 0x80000000) >> 31;
+    int mw = (w & 0x80000000) >> 31;
+    return mx | my << 1 | mz << 2 | mw << 3;
+  }
+
+  /// Shuffle the lane values. [mask] must be one of the 256 shuffle constants.
+  Int32x4 shuffle(int mask) {
+    if ((mask < 0) || (mask > 255)) {
+      throw new RangeError.range(mask, 0, 255, 'mask');
+    }
+    _list[0] = x;
+    _list[1] = y;
+    _list[2] = z;
+    _list[3] = w;
+    int _x = _list[mask & 0x3];
+    int _y = _list[(mask >> 2) & 0x3];
+    int _z = _list[(mask >> 4) & 0x3];
+    int _w = _list[(mask >> 6) & 0x3];
+    return new NativeInt32x4._truncated(_x, _y, _z, _w);
+  }
+
+  /// Shuffle the lane values in [this] and [other]. The returned
+  /// Int32x4 will have XY lanes from [this] and ZW lanes from [other].
+  /// Uses the same [mask] as [shuffle].
+  Int32x4 shuffleMix(Int32x4 other, int mask) {
+    if ((mask < 0) || (mask > 255)) {
+      throw new RangeError.range(mask, 0, 255, 'mask');
+    }
+    _list[0] = x;
+    _list[1] = y;
+    _list[2] = z;
+    _list[3] = w;
+    int _x = _list[mask & 0x3];
+    int _y = _list[(mask >> 2) & 0x3];
+
+    _list[0] = other.x;
+    _list[1] = other.y;
+    _list[2] = other.z;
+    _list[3] = other.w;
+    int _z = _list[(mask >> 4) & 0x3];
+    int _w = _list[(mask >> 6) & 0x3];
+    return new NativeInt32x4._truncated(_x, _y, _z, _w);
+  }
+
+  /// Returns a new [Int32x4] copied from [this] with a new x value.
+  Int32x4 withX(int x) {
+    int _x = _truncate(x);
+    return new NativeInt32x4._truncated(_x, y, z, w);
+  }
+
+  /// Returns a new [Int32x4] copied from [this] with a new y value.
+  Int32x4 withY(int y) {
+    int _y = _truncate(y);
+    return new NativeInt32x4._truncated(x, _y, z, w);
+  }
+
+  /// Returns a new [Int32x4] copied from [this] with a new z value.
+  Int32x4 withZ(int z) {
+    int _z = _truncate(z);
+    return new NativeInt32x4._truncated(x, y, _z, w);
+  }
+
+  /// Returns a new [Int32x4] copied from [this] with a new w value.
+  Int32x4 withW(int w) {
+    int _w = _truncate(w);
+    return new NativeInt32x4._truncated(x, y, z, _w);
+  }
+
+  /// Extracted x value. Returns `false` for 0, `true` for any other value.
+  bool get flagX => x != 0;
+
+  /// Extracted y value. Returns `false` for 0, `true` for any other value.
+  bool get flagY => y != 0;
+
+  /// Extracted z value. Returns `false` for 0, `true` for any other value.
+  bool get flagZ => z != 0;
+
+  /// Extracted w value. Returns `false` for 0, `true` for any other value.
+  bool get flagW => w != 0;
+
+  /// Returns a new [Int32x4] copied from [this] with a new x value.
+  Int32x4 withFlagX(bool flagX) {
+    int _x = flagX ? -1 : 0;
+    return new NativeInt32x4._truncated(_x, y, z, w);
+  }
+
+  /// Returns a new [Int32x4] copied from [this] with a new y value.
+  Int32x4 withFlagY(bool flagY) {
+    int _y = flagY ? -1 : 0;
+    return new NativeInt32x4._truncated(x, _y, z, w);
+  }
+
+  /// Returns a new [Int32x4] copied from [this] with a new z value.
+  Int32x4 withFlagZ(bool flagZ) {
+    int _z = flagZ ? -1 : 0;
+    return new NativeInt32x4._truncated(x, y, _z, w);
+  }
+
+  /// Returns a new [Int32x4] copied from [this] with a new w value.
+  Int32x4 withFlagW(bool flagW) {
+    int _w = flagW ? -1 : 0;
+    return new NativeInt32x4._truncated(x, y, z, _w);
+  }
+
+  /// Merge [trueValue] and [falseValue] based on [this]' bit mask:
+  /// Select bit from [trueValue] when bit in [this] is on.
+  /// Select bit from [falseValue] when bit in [this] is off.
+  Float32x4 select(Float32x4 trueValue, Float32x4 falseValue) {
+    var floatList = NativeFloat32x4._list;
+    var intView = NativeFloat32x4._uint32view;
+
+    floatList[0] = trueValue.x;
+    floatList[1] = trueValue.y;
+    floatList[2] = trueValue.z;
+    floatList[3] = trueValue.w;
+    int stx = intView[0];
+    int sty = intView[1];
+    int stz = intView[2];
+    int stw = intView[3];
+
+    floatList[0] = falseValue.x;
+    floatList[1] = falseValue.y;
+    floatList[2] = falseValue.z;
+    floatList[3] = falseValue.w;
+    int sfx = intView[0];
+    int sfy = intView[1];
+    int sfz = intView[2];
+    int sfw = intView[3];
+    int _x = (x & stx) | (~x & sfx);
+    int _y = (y & sty) | (~y & sfy);
+    int _z = (z & stz) | (~z & sfz);
+    int _w = (w & stw) | (~w & sfw);
+    intView[0] = _x;
+    intView[1] = _y;
+    intView[2] = _z;
+    intView[3] = _w;
+    return new NativeFloat32x4._truncated(
+        floatList[0], floatList[1], floatList[2], floatList[3]);
+  }
+}
+
+class NativeFloat64x2 implements Float64x2 {
+  final double x;
+  final double y;
+
+  static NativeFloat64List _list = new NativeFloat64List(2);
+  static NativeUint32List _uint32View = _list.buffer.asUint32List();
+
+  NativeFloat64x2(this.x, this.y) {
+    if (x is! num) throw new ArgumentError(x);
+    if (y is! num) throw new ArgumentError(y);
+  }
+
+  NativeFloat64x2.splat(double v) : this(v, v);
+
+  NativeFloat64x2.zero() : this.splat(0.0);
+
+  NativeFloat64x2.fromFloat32x4(Float32x4 v) : this(v.x, v.y);
+
+  /// Arguments [x] and [y] must be doubles.
+  NativeFloat64x2._doubles(this.x, this.y);
+
+  String toString() => '[$x, $y]';
+
+  /// Addition operator.
+  Float64x2 operator +(Float64x2 other) {
+    return new NativeFloat64x2._doubles(x + other.x, y + other.y);
+  }
+
+  /// Negate operator.
+  Float64x2 operator -() {
+    return new NativeFloat64x2._doubles(-x, -y);
+  }
+
+  /// Subtraction operator.
+  Float64x2 operator -(Float64x2 other) {
+    return new NativeFloat64x2._doubles(x - other.x, y - other.y);
+  }
+
+  /// Multiplication operator.
+  Float64x2 operator *(Float64x2 other) {
+    return new NativeFloat64x2._doubles(x * other.x, y * other.y);
+  }
+
+  /// Division operator.
+  Float64x2 operator /(Float64x2 other) {
+    return new NativeFloat64x2._doubles(x / other.x, y / other.y);
+  }
+
+  /// Returns a copy of [this] each lane being scaled by [s].
+  Float64x2 scale(double s) {
+    return new NativeFloat64x2._doubles(x * s, y * s);
+  }
+
+  /// Returns the absolute value of this [Float64x2].
+  Float64x2 abs() {
+    return new NativeFloat64x2._doubles(x.abs(), y.abs());
+  }
+
+  /// Clamps [this] to be in the range [lowerLimit]-[upperLimit].
+  Float64x2 clamp(Float64x2 lowerLimit, Float64x2 upperLimit) {
+    double _lx = lowerLimit.x;
+    double _ly = lowerLimit.y;
+    double _ux = upperLimit.x;
+    double _uy = upperLimit.y;
+    double _x = x;
+    double _y = y;
+    // MAX(MIN(self, upper), lower).
+    _x = _x > _ux ? _ux : _x;
+    _y = _y > _uy ? _uy : _y;
+    _x = _x < _lx ? _lx : _x;
+    _y = _y < _ly ? _ly : _y;
+    return new NativeFloat64x2._doubles(_x, _y);
+  }
+
+  /// Extract the sign bits from each lane return them in the first 2 bits.
+  int get signMask {
+    var view = _uint32View;
+    _list[0] = x;
+    _list[1] = y;
+    var mx = (view[1] & 0x80000000) >> 31;
+    var my = (view[3] & 0x80000000) >> 31;
+    return mx | my << 1;
+  }
+
+  /// Returns a new [Float64x2] copied from [this] with a new x value.
+  Float64x2 withX(double x) {
+    if (x is! num) throw new ArgumentError(x);
+    return new NativeFloat64x2._doubles(x, y);
+  }
+
+  /// Returns a new [Float64x2] copied from [this] with a new y value.
+  Float64x2 withY(double y) {
+    if (y is! num) throw new ArgumentError(y);
+    return new NativeFloat64x2._doubles(x, y);
+  }
+
+  /// Returns the lane-wise minimum value in [this] or [other].
+  Float64x2 min(Float64x2 other) {
+    return new NativeFloat64x2._doubles(
+        x < other.x ? x : other.x, y < other.y ? y : other.y);
+  }
+
+  /// Returns the lane-wise maximum value in [this] or [other].
+  Float64x2 max(Float64x2 other) {
+    return new NativeFloat64x2._doubles(
+        x > other.x ? x : other.x, y > other.y ? y : other.y);
+  }
+
+  /// Returns the lane-wise square root of [this].
+  Float64x2 sqrt() {
+    return new NativeFloat64x2._doubles(Math.sqrt(x), Math.sqrt(y));
+  }
+}
+
+/// Checks that the value is a Uint32. If not, it's not valid as an array
+/// index or offset. Also ensures that the value is non-negative.
+bool _isInvalidArrayIndex(int index) {
+  return (JS('bool', '(# >>> 0 !== #)', index, index));
+}
+
+/// Checks that [index] is a valid index into [list] which has length [length].
+///
+/// That is, [index] is an integer in the range `0..length - 1`.
+void _checkValidIndex(int index, List list, int length) {
+  if (_isInvalidArrayIndex(index) || JS('int', '#', index) >= length) {
+    throw diagnoseIndexError(list, index);
+  }
+}
+
+/// Checks that [start] and [end] form a range of a list of length [length].
+///
+/// That is: `start` and `end` are integers with `0 <= start <= end <= length`.
+/// If `end` is `null` in which case it is considered to be `length`
+///
+/// Returns the actual value of `end`, which is `length` if `end` is `null`, and
+/// the original value of `end` otherwise.
+int _checkValidRange(int start, int end, int length) {
+  if (_isInvalidArrayIndex(start) || // Ensures start is non-negative int.
+      ((end == null)
+          ? start > length
+          : (_isInvalidArrayIndex(end) || start > end || end > length))) {
+    throw diagnoseRangeError(start, end, length);
+  }
+  if (end == null) return length;
+  return end;
+}
diff --git a/sdk_nnbd/lib/_internal/js_runtime/lib/preambles/README b/sdk_nnbd/lib/_internal/js_runtime/lib/preambles/README
new file mode 100644
index 0000000..4465012
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_runtime/lib/preambles/README
@@ -0,0 +1,17 @@
+The files in this directory polyfill some of the functionality that browsers
+provide. When running command-line JS evaluators it is frequently necessary to
+execute the preambles before executing the output of dart2js.
+
+=Usage=
+- d8:
+    d8 <sdk>/lib/_internal/js_runtime/lib/preambles/d8.js <output>.js
+
+- jsshell:
+    jsshell -f <sdk>/lib/_internal/js_runtime/lib/preambles/d8.js -f <output>.js
+
+- node.js:
+  The d8 preamble file works for most programs.
+
+  Unfortunately we are not aware of any easy way to provide multiple input files
+  to node. It seems to be necessary to concatenate the d8 preamble and the
+  dart2js output.
diff --git a/sdk_nnbd/lib/_internal/js_runtime/lib/preambles/d8.js b/sdk_nnbd/lib/_internal/js_runtime/lib/preambles/d8.js
new file mode 100644
index 0000000..0174d95
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_runtime/lib/preambles/d8.js
@@ -0,0 +1,348 @@
+// Copyright (c) 2015, 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.
+
+// Javascript preamble, that lets the output of dart2js run on V8's d8 shell.
+
+// Node wraps files and provides them with a different `this`. The global
+// `this` can be accessed through `global`.
+
+var self = this;
+if (typeof global != "undefined") self = global;  // Node.js.
+
+(function(self) {
+  // Using strict mode to avoid accidentally defining global variables.
+  "use strict"; // Should be first statement of this function.
+
+  // Location (Uri.base)
+  var baseUri = 'org-dartlang-d8-preamble:///mock/uri/base/';
+  if (typeof process != "undefined" &&
+             typeof process.cwd == "function") {
+    // Node.js.
+    baseUri = 'file://' + process.cwd() + '/';
+  }
+  self.location = { href: baseUri };
+
+  // Event loop.
+
+  // Task queue as cyclic list queue.
+  var taskQueue = new Array(8);  // Length is power of 2.
+  var head = 0;
+  var tail = 0;
+  var mask = taskQueue.length - 1;
+  function addTask(elem) {
+    taskQueue[head] = elem;
+    head = (head + 1) & mask;
+    if (head == tail) _growTaskQueue();
+  }
+  function removeTask() {
+    if (head == tail) return;
+    var result = taskQueue[tail];
+    taskQueue[tail] = undefined;
+    tail = (tail + 1) & mask;
+    return result;
+  }
+  function _growTaskQueue() {
+    // head == tail.
+    var length = taskQueue.length;
+    var split = head;
+    taskQueue.length = length * 2;
+    if (split * 2 < length) {  // split < length / 2
+      for (var i = 0; i < split; i++) {
+        taskQueue[length + i] = taskQueue[i];
+        taskQueue[i] = undefined;
+      }
+      head += length;
+    } else {
+      for (var i = split; i < length; i++) {
+        taskQueue[length + i] = taskQueue[i];
+        taskQueue[i] = undefined;
+      }
+      tail += length;
+    }
+    mask = taskQueue.length - 1;
+  }
+
+  // Mapping from timer id to timer function.
+  // The timer id is written on the function as .$timerId.
+  // That field is cleared when the timer is cancelled, but it is not returned
+  // from the queue until its time comes.
+  var timerIds = {};
+  var timerIdCounter = 1;  // Counter used to assign ids.
+
+  // Zero-timer queue as simple array queue using push/shift.
+  var zeroTimerQueue = [];
+
+  function addTimer(f, ms) {
+    var id = timerIdCounter++;
+    f.$timerId = id;
+    timerIds[id] = f;
+    if (ms == 0 && !isNextTimerDue()) {
+      zeroTimerQueue.push(f);
+    } else {
+      addDelayedTimer(f, ms);
+    }
+    return id;
+  }
+
+  function nextZeroTimer() {
+    while (zeroTimerQueue.length > 0) {
+      var action = zeroTimerQueue.shift();
+      if (action.$timerId !== undefined) return action;
+    }
+  }
+
+  function nextEvent() {
+    var action = removeTask();
+    if (action) {
+      return action;
+    }
+    do {
+      action = nextZeroTimer();
+      if (action) break;
+      var nextList = nextDelayedTimerQueue();
+      if (!nextList) {
+        return;
+      }
+      var newTime = nextList.shift();
+      advanceTimeTo(newTime);
+      zeroTimerQueue = nextList;
+    } while (true)
+    var id = action.$timerId;
+    clearTimerId(action, id);
+    return action;
+  }
+
+  // Mocking time.
+  var timeOffset = 0;
+  var now = function() {
+    // Install the mock Date object only once.
+    // Following calls to "now" will just use the new (mocked) Date.now
+    // method directly.
+    installMockDate();
+    now = Date.now;
+    return Date.now();
+  };
+  var originalDate = Date;
+  var originalNow = originalDate.now;
+  function advanceTimeTo(time) {
+    var now = originalNow();
+    if (timeOffset < time - now) {
+      timeOffset = time - now;
+    }
+  }
+  function installMockDate() {
+    var NewDate = function Date(Y, M, D, h, m, s, ms) {
+      if (this instanceof Date) {
+        // Assume a construct call.
+        switch (arguments.length) {
+          case 0:  return new originalDate(originalNow() + timeOffset);
+          case 1:  return new originalDate(Y);
+          case 2:  return new originalDate(Y, M);
+          case 3:  return new originalDate(Y, M, D);
+          case 4:  return new originalDate(Y, M, D, h);
+          case 5:  return new originalDate(Y, M, D, h, m);
+          case 6:  return new originalDate(Y, M, D, h, m, s);
+          default: return new originalDate(Y, M, D, h, m, s, ms);
+        }
+      }
+      return new originalDate(originalNow() + timeOffset).toString();
+    };
+    NewDate.UTC = originalDate.UTC;
+    NewDate.parse = originalDate.parse;
+    NewDate.now = function now() { return originalNow() + timeOffset; };
+    NewDate.prototype = originalDate.prototype;
+    originalDate.prototype.constructor = NewDate;
+    Date = NewDate;
+  }
+
+  // Heap priority queue with key index.
+  // Each entry is list of [timeout, callback1 ... callbackn].
+  var timerHeap = [];
+  var timerIndex = {};
+  function addDelayedTimer(f, ms) {
+    var timeout = now() + ms;
+    var timerList = timerIndex[timeout];
+    if (timerList == null) {
+      timerList = [timeout, f];
+      timerIndex[timeout] = timerList;
+      var index = timerHeap.length;
+      timerHeap.length += 1;
+      bubbleUp(index, timeout, timerList);
+    } else {
+      timerList.push(f);
+    }
+  }
+
+  function isNextTimerDue() {
+    if (timerHeap.length == 0) return false;
+    var head = timerHeap[0];
+    return head[0] < originalNow() + timeOffset;
+  }
+
+  function nextDelayedTimerQueue() {
+    if (timerHeap.length == 0) return null;
+    var result = timerHeap[0];
+    var last = timerHeap.pop();
+    if (timerHeap.length > 0) {
+      bubbleDown(0, last[0], last);
+    }
+    return result;
+  }
+
+  function bubbleUp(index, key, value) {
+    while (index != 0) {
+      var parentIndex = (index - 1) >> 1;
+      var parent = timerHeap[parentIndex];
+      var parentKey = parent[0];
+      if (key > parentKey) break;
+      timerHeap[index] = parent;
+      index = parentIndex;
+    }
+    timerHeap[index] = value;
+  }
+
+  function bubbleDown(index, key, value) {
+    while (true) {
+      var leftChildIndex = index * 2 + 1;
+      if (leftChildIndex >= timerHeap.length) break;
+      var minChildIndex = leftChildIndex;
+      var minChild = timerHeap[leftChildIndex];
+      var minChildKey = minChild[0];
+      var rightChildIndex = leftChildIndex + 1;
+      if (rightChildIndex < timerHeap.length) {
+        var rightChild = timerHeap[rightChildIndex];
+        var rightKey = rightChild[0];
+        if (rightKey < minChildKey) {
+          minChildIndex = rightChildIndex;
+          minChild = rightChild;
+          minChildKey = rightKey;
+        }
+      }
+      if (minChildKey > key) break;
+      timerHeap[index] = minChild;
+      index = minChildIndex;
+    }
+    timerHeap[index] = value;
+  }
+
+  function addInterval(f, ms) {
+    var id = timerIdCounter++;
+    function repeat() {
+      // Reactivate with the same id.
+      repeat.$timerId = id;
+      timerIds[id] = repeat;
+      addDelayedTimer(repeat, ms);
+      f();
+    }
+    repeat.$timerId = id;
+    timerIds[id] = repeat;
+    addDelayedTimer(repeat, ms);
+    return id;
+  }
+
+  function cancelTimer(id) {
+    var f = timerIds[id];
+    if (f == null) return;
+    clearTimerId(f, id);
+  }
+
+  function clearTimerId(f, id) {
+    f.$timerId = undefined;
+    delete timerIds[id];
+  }
+
+  function eventLoop(action) {
+    while (action) {
+      try {
+        action();
+      } catch (e) {
+        if (typeof onerror == "function") {
+          onerror(e, null, -1);
+        } else {
+          throw e;
+        }
+      }
+      action = nextEvent();
+    }
+  }
+
+  // Global properties. "self" refers to the global object, so adding a
+  // property to "self" defines a global variable.
+  self.self = self;
+  self.dartMainRunner = function(main, args) {
+    // Initialize.
+    var action = function() { main(args); }
+    eventLoop(action);
+  };
+  self.setTimeout = addTimer;
+  self.clearTimeout = cancelTimer;
+  self.setInterval = addInterval;
+  self.clearInterval = cancelTimer;
+  self.scheduleImmediate = addTask;
+
+  function computeCurrentScript() {
+    try {
+      throw new Error();
+    } catch(e) {
+      var stack = e.stack;
+      // The V8 stack looks like:
+      //    at computeCurrentScript (preambles/d8.js:286:13)
+      //    at Object.currentScript (preambles/d8.js:308:31)
+      //    at init.currentScript (/tmp/foo.js:308:19)
+      //    at /tmp/foo.js:320:7
+      //    at /tmp/foo.js:331:4
+      // Sometimes the 'init.currentScript' line is in the format without the
+      // function name, so match with or without parentheses.
+
+      //              vvvvvvvvvvvv Optional prefix up to '('.
+      var re = /^ *at (?:[^(]*\()?(.*):[0-9]*:[0-9]*\)?$/mg
+      //              Optional ')' at end           ^^^
+
+      var lastMatch = null;
+      do {
+        var match = re.exec(stack);
+        if (match != null) lastMatch = match;
+      } while (match != null);
+      return lastMatch[1];
+    }
+  }
+
+  // Adding a 'document' is dangerous since it invalidates the 'typeof document'
+  // test to see if we are running in the browser. It means that the runtime
+  // needs to do more precise checks.
+  // Note that we can't run "currentScript" right away, since that would give
+  // us the location of the preamble file. Instead we wait for the first access
+  // which should happen just before invoking main. At this point we are in
+  // the main file and setting the currentScript property is correct.
+  var cachedCurrentScript = null;
+  self.document = { get currentScript() {
+      if (cachedCurrentScript == null) {
+        cachedCurrentScript = {src: computeCurrentScript()};
+      }
+      return cachedCurrentScript;
+    }
+  };
+
+  // Support for deferred loading.
+  self.dartDeferredLibraryLoader = function(uri, successCallback, errorCallback) {
+    try {
+      load(uri);
+      successCallback();
+    } catch (error) {
+      errorCallback(error);
+    }
+  };
+
+  // Mock cryptographically secure random by using plain random.
+  self.crypto = {getRandomValues: function(array) {
+    for (var i = 0; i < array.length; i++) {
+      array[i] = Math.random() * 256;
+    }
+  }};
+
+  // D8 Workers are not sufficiently compatible with browser Workers
+  // so pretend they don't exist.
+  // TODO(30217): Try to use D8's worker.
+  delete self.Worker;
+})(self);
diff --git a/sdk_nnbd/lib/_internal/js_runtime/lib/preambles/jsshell.js b/sdk_nnbd/lib/_internal/js_runtime/lib/preambles/jsshell.js
new file mode 100644
index 0000000..a6b41c4
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_runtime/lib/preambles/jsshell.js
@@ -0,0 +1,340 @@
+// Copyright (c) 2015, 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.
+
+// Javascript preamble, that lets the output of dart2js run on JSShell.
+
+(function(self) {
+  // Using strict mode to avoid accidentally defining global variables.
+  "use strict"; // Should be first statement of this function.
+
+  // Location (Uri.base)
+
+  var workingDirectory = os.getenv("PWD");
+
+  // Global properties. "self" refers to the global object, so adding a
+  // property to "self" defines a global variable.
+  self.self = self;
+
+  self.location = { href: "file://" + workingDirectory + "/" };
+
+  // Event loop.
+
+  // Task queue as cyclic list queue.
+  var taskQueue = new Array(8);  // Length is power of 2.
+  var head = 0;
+  var tail = 0;
+  var mask = taskQueue.length - 1;
+  function addTask(elem) {
+    taskQueue[head] = elem;
+    head = (head + 1) & mask;
+    if (head == tail) _growTaskQueue();
+  }
+  function removeTask() {
+    if (head == tail) return;
+    var result = taskQueue[tail];
+    taskQueue[tail] = undefined;
+    tail = (tail + 1) & mask;
+    return result;
+  }
+  function _growTaskQueue() {
+    // head == tail.
+    var length = taskQueue.length;
+    var split = head;
+    taskQueue.length = length * 2;
+    if (split * 2 < length) {  // split < length / 2
+      for (var i = 0; i < split; i++) {
+        taskQueue[length + i] = taskQueue[i];
+        taskQueue[i] = undefined;
+      }
+      head += length;
+    } else {
+      for (var i = split; i < length; i++) {
+        taskQueue[length + i] = taskQueue[i];
+        taskQueue[i] = undefined;
+      }
+      tail += length;
+    }
+    mask = taskQueue.length - 1;
+  }
+
+  // Mapping from timer id to timer function.
+  // The timer id is written on the function as .$timerId.
+  // That field is cleared when the timer is cancelled, but it is not returned
+  // from the queue until its time comes.
+  var timerIds = {};
+  var timerIdCounter = 1;  // Counter used to assign ids.
+
+  // Zero-timer queue as simple array queue using push/shift.
+  var zeroTimerQueue = [];
+
+  function addTimer(f, ms) {
+    var id = timerIdCounter++;
+    f.$timerId = id;
+    timerIds[id] = f;
+    if (ms == 0 && !isNextTimerDue()) {
+      zeroTimerQueue.push(f);
+    } else {
+      addDelayedTimer(f, ms);
+    }
+    return id;
+  }
+
+  function nextZeroTimer() {
+    while (zeroTimerQueue.length > 0) {
+      var action = zeroTimerQueue.shift();
+      if (action.$timerId !== undefined) return action;
+    }
+  }
+
+  function nextEvent() {
+    var action = removeTask();
+    if (action) {
+      return action;
+    }
+    do {
+      action = nextZeroTimer();
+      if (action) break;
+      var nextList = nextDelayedTimerQueue();
+      if (!nextList) {
+        return;
+      }
+      var newTime = nextList.shift();
+      advanceTimeTo(newTime);
+      zeroTimerQueue = nextList;
+    } while (true)
+    var id = action.$timerId;
+    clearTimerId(action, id);
+    return action;
+  }
+
+  // Mocking time.
+  var timeOffset = 0;
+  var now = function() {
+    // Install the mock Date object only once.
+    // Following calls to "now" will just use the new (mocked) Date.now
+    // method directly.
+    installMockDate();
+    now = Date.now;
+    return Date.now();
+  };
+  var originalDate = Date;
+  var originalNow = originalDate.now;
+  function advanceTimeTo(time) {
+    var now = originalNow();
+    if (timeOffset < time - now) {
+      timeOffset = time - now;
+    }
+  }
+  function installMockDate() {
+    var NewDate = function Date(Y, M, D, h, m, s, ms) {
+      if (this instanceof Date) {
+        // Assume a construct call.
+        switch (arguments.length) {
+          case 0:  return new originalDate(originalNow() + timeOffset);
+          case 1:  return new originalDate(Y);
+          case 2:  return new originalDate(Y, M);
+          case 3:  return new originalDate(Y, M, D);
+          case 4:  return new originalDate(Y, M, D, h);
+          case 5:  return new originalDate(Y, M, D, h, m);
+          case 6:  return new originalDate(Y, M, D, h, m, s);
+          default: return new originalDate(Y, M, D, h, m, s, ms);
+        }
+      }
+      return new originalDate(originalNow() + timeOffset).toString();
+    };
+    NewDate.UTC = originalDate.UTC;
+    NewDate.parse = originalDate.parse;
+    NewDate.now = function now() { return originalNow() + timeOffset; };
+    NewDate.prototype = originalDate.prototype;
+    originalDate.prototype.constructor = NewDate;
+    Date = NewDate;
+  }
+
+  // Heap priority queue with key index.
+  // Each entry is list of [timeout, callback1 ... callbackn].
+  var timerHeap = [];
+  var timerIndex = {};
+  function addDelayedTimer(f, ms) {
+    var timeout = now() + ms;
+    var timerList = timerIndex[timeout];
+    if (timerList == null) {
+      timerList = [timeout, f];
+      timerIndex[timeout] = timerList;
+      var index = timerHeap.length;
+      timerHeap.length += 1;
+      bubbleUp(index, timeout, timerList);
+    } else {
+      timerList.push(f);
+    }
+  }
+
+  function isNextTimerDue() {
+    if (timerHeap.length == 0) return false;
+    var head = timerHeap[0];
+    return head[0] < originalNow() + timeOffset;
+  }
+
+  function nextDelayedTimerQueue() {
+    if (timerHeap.length == 0) return null;
+    var result = timerHeap[0];
+    var last = timerHeap.pop();
+    if (timerHeap.length > 0) {
+      bubbleDown(0, last[0], last);
+    }
+    return result;
+  }
+
+  function bubbleUp(index, key, value) {
+    while (index != 0) {
+      var parentIndex = (index - 1) >> 1;
+      var parent = timerHeap[parentIndex];
+      var parentKey = parent[0];
+      if (key > parentKey) break;
+      timerHeap[index] = parent;
+      index = parentIndex;
+    }
+    timerHeap[index] = value;
+  }
+
+  function bubbleDown(index, key, value) {
+    while (true) {
+      var leftChildIndex = index * 2 + 1;
+      if (leftChildIndex >= timerHeap.length) break;
+      var minChildIndex = leftChildIndex;
+      var minChild = timerHeap[leftChildIndex];
+      var minChildKey = minChild[0];
+      var rightChildIndex = leftChildIndex + 1;
+      if (rightChildIndex < timerHeap.length) {
+        var rightChild = timerHeap[rightChildIndex];
+        var rightKey = rightChild[0];
+        if (rightKey < minChildKey) {
+          minChildIndex = rightChildIndex;
+          minChild = rightChild;
+          minChildKey = rightKey;
+        }
+      }
+      if (minChildKey > key) break;
+      timerHeap[index] = minChild;
+      index = minChildIndex;
+    }
+    timerHeap[index] = value;
+  }
+
+  function addInterval(f, ms) {
+    var id = timerIdCounter++;
+    function repeat() {
+      // Reactivate with the same id.
+      repeat.$timerId = id;
+      timerIds[id] = repeat;
+      addDelayedTimer(repeat, ms);
+      f();
+    }
+    repeat.$timerId = id;
+    timerIds[id] = repeat;
+    addDelayedTimer(repeat, ms);
+    return id;
+  }
+
+  function cancelTimer(id) {
+    var f = timerIds[id];
+    if (f == null) return;
+    clearTimerId(f, id);
+  }
+
+  function clearTimerId(f, id) {
+    f.$timerId = undefined;
+    delete timerIds[id];
+  }
+
+  function eventLoop(action) {
+    while (action) {
+      try {
+        action();
+      } catch (e) {
+        if (typeof onerror == "function") {
+          onerror(e, null, -1);
+        } else {
+          throw e;
+        }
+      }
+      action = nextEvent();
+    }
+  }
+
+  self.dartMainRunner = function(main, args) {
+    // Initialize.
+    var action = function() { main(args); }
+    eventLoop(action);
+  };
+  self.setTimeout = addTimer;
+  self.clearTimeout = cancelTimer;
+  self.setInterval = addInterval;
+  self.clearInterval = cancelTimer;
+  self.scheduleImmediate = addTask;
+
+  function computeCurrentScript() {
+    try {
+      throw new Error();
+    } catch(e) {
+      var stack = e.stack;
+      print(stack);
+      // The jsshell stack looks like:
+      //   computeCurrentScript@...preambles/jsshell.js:23:13
+      //   self.document.currentScript@...preambles/jsshell.js:53:37
+      //   @/tmp/foo.js:308:1
+      //   @/tmp/foo.js:303:1
+      //   @/tmp/foo.js:5:1
+      var re = new RegExp("^.*@(.*):[0-9]*:[0-9]*$", "mg");
+      var lastMatch = null;
+      do {
+        var match = re.exec(stack);
+        if (match != null) lastMatch = match;
+      } while (match != null);
+      return lastMatch[1];
+    }
+  }
+
+  // Adding a 'document' is dangerous since it invalidates the 'typeof document'
+  // test to see if we are running in the browser. It means that the runtime
+  // needs to do more precise checks.
+  // Note that we can't run "currentScript" right away, since that would give
+  // us the location of the preamble file. Instead we wait for the first access
+  // which should happen just before invoking main. At this point we are in
+  // the main file and setting the currentScript property is correct.
+  // Note that we cannot use `thisFileName()`, since that would give us the
+  // preamble and not the script file.
+  var cachedCurrentScript = null;
+  self.document = { get currentScript() {
+      if (cachedCurrentScript == null) {
+        cachedCurrentScript = {src: computeCurrentScript()};
+      }
+      return cachedCurrentScript;
+    }
+  };
+
+  // Support for deferred loading.
+  self.dartDeferredLibraryLoader = function(uri, successCallback, errorCallback) {
+    try {
+      load(uri);
+      successCallback();
+    } catch (error) {
+      errorCallback(error);
+    }
+  };
+
+  // Mock cryptographically secure random by using plain random.
+  self.crypto = {getRandomValues: function(array) {
+    for (var i = 0; i < array.length; i++) {
+      array[i] = Math.random() * 256;
+    }
+  }};
+})(this)
+
+var getKeys = function(obj){
+   var keys = [];
+   for(var key in obj){
+      keys.push(key);
+   }
+   return keys;
+}
diff --git a/sdk_nnbd/lib/_internal/js_runtime/lib/regexp_helper.dart b/sdk_nnbd/lib/_internal/js_runtime/lib/regexp_helper.dart
new file mode 100644
index 0000000..3dacc06
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_runtime/lib/regexp_helper.dart
@@ -0,0 +1,295 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of _js_helper;
+
+// Helper method used by internal libraries.
+regExpGetNative(JSSyntaxRegExp regexp) => regexp._nativeRegExp;
+
+/// Returns a native version of the RegExp with the global flag set.
+///
+/// The RegExp's `lastIndex` property is zero when it is returned.
+///
+/// The returned regexp is shared, and its `lastIndex` property may be
+/// modified by other uses, so the returned regexp must be used immediately
+/// when it's returned, with no user-provided code run in between.
+regExpGetGlobalNative(JSSyntaxRegExp regexp) {
+  var nativeRegexp = regexp._nativeGlobalVersion;
+  JS('void', '#.lastIndex = 0', nativeRegexp);
+  return nativeRegexp;
+}
+
+/// Computes the number of captures in a regexp.
+///
+/// This currently involves creating a new RegExp object with a different
+/// source and running it against the empty string (the last part is usually
+/// fast).
+///
+/// The JSSyntaxRegExp could cache the result, and set the cache any time
+/// it finds a match.
+int regExpCaptureCount(JSSyntaxRegExp regexp) {
+  var nativeAnchoredRegExp = regexp._nativeAnchoredVersion;
+  var match = JS('JSExtendableArray', '#.exec("")', nativeAnchoredRegExp);
+  // The native-anchored regexp always have one capture more than the original,
+  // and always matches the empty string.
+  return match.length - 2;
+}
+
+class JSSyntaxRegExp implements RegExp {
+  final String pattern;
+  final _nativeRegExp;
+  var _nativeGlobalRegExp;
+  var _nativeAnchoredRegExp;
+
+  String toString() =>
+      'RegExp/$pattern/' + JS('String', '#.flags', _nativeRegExp);
+
+  JSSyntaxRegExp(String source,
+      {bool multiLine: false,
+      bool caseSensitive: true,
+      bool unicode: false,
+      bool dotAll: false})
+      : this.pattern = source,
+        this._nativeRegExp = makeNative(
+            source, multiLine, caseSensitive, unicode, dotAll, false);
+
+  get _nativeGlobalVersion {
+    if (_nativeGlobalRegExp != null) return _nativeGlobalRegExp;
+    return _nativeGlobalRegExp = makeNative(
+        pattern, _isMultiLine, _isCaseSensitive, _isUnicode, _isDotAll, true);
+  }
+
+  get _nativeAnchoredVersion {
+    if (_nativeAnchoredRegExp != null) return _nativeAnchoredRegExp;
+    // An "anchored version" of a regexp is created by adding "|()" to the
+    // source. This means that the regexp always matches at the first position
+    // that it tries, and you can see if the original regexp matched, or it
+    // was the added zero-width match that matched, by looking at the last
+    // capture. If it is a String, the match participated, otherwise it didn't.
+    return _nativeAnchoredRegExp = makeNative('$pattern|()', _isMultiLine,
+        _isCaseSensitive, _isUnicode, _isDotAll, true);
+  }
+
+  bool get _isMultiLine => JS('bool', '#.multiline', _nativeRegExp);
+  bool get _isCaseSensitive => JS('bool', '!#.ignoreCase', _nativeRegExp);
+  bool get _isUnicode => JS('bool', '#.unicode', _nativeRegExp);
+  bool get _isDotAll => JS('bool', '#.dotAll', _nativeRegExp);
+
+  static makeNative(String source, bool multiLine, bool caseSensitive,
+      bool unicode, bool dotAll, bool global) {
+    checkString(source);
+    String m = multiLine == true ? 'm' : '';
+    String i = caseSensitive == true ? '' : 'i';
+    String u = unicode ? 'u' : '';
+    String s = dotAll ? 's' : '';
+    String g = global ? 'g' : '';
+    // We're using the JavaScript's try catch instead of the Dart one to avoid
+    // dragging in Dart runtime support just because of using RegExp.
+    var regexp = JS(
+        '',
+        r'''
+          (function(source, modifiers) {
+            try {
+              return new RegExp(source, modifiers);
+            } catch (e) {
+              return e;
+            }
+          })(#, # + # + # + # + #)''',
+        source,
+        m,
+        i,
+        u,
+        s,
+        g);
+    if (JS('bool', '# instanceof RegExp', regexp)) return regexp;
+    // The returned value is the JavaScript exception. Turn it into a
+    // Dart exception.
+    String errorMessage = JS('String', r'String(#)', regexp);
+    throw new FormatException('Illegal RegExp pattern ($errorMessage)', source);
+  }
+
+  RegExpMatch firstMatch(String string) {
+    List m = JS('JSExtendableArray|Null', r'#.exec(#)', _nativeRegExp,
+        checkString(string));
+    if (m == null) return null;
+    return new _MatchImplementation(this, m);
+  }
+
+  bool hasMatch(String string) {
+    return JS('bool', r'#.test(#)', _nativeRegExp, checkString(string));
+  }
+
+  String stringMatch(String string) {
+    var match = firstMatch(string);
+    if (match != null) return match.group(0);
+    return null;
+  }
+
+  Iterable<RegExpMatch> allMatches(String string, [int start = 0]) {
+    checkString(string);
+    checkInt(start);
+    if (start < 0 || start > string.length) {
+      throw new RangeError.range(start, 0, string.length);
+    }
+    return new _AllMatchesIterable(this, string, start);
+  }
+
+  RegExpMatch _execGlobal(String string, int start) {
+    Object regexp = _nativeGlobalVersion;
+    JS('void', '#.lastIndex = #', regexp, start);
+    List match = JS('JSExtendableArray|Null', '#.exec(#)', regexp, string);
+    if (match == null) return null;
+    return new _MatchImplementation(this, match);
+  }
+
+  RegExpMatch _execAnchored(String string, int start) {
+    Object regexp = _nativeAnchoredVersion;
+    JS('void', '#.lastIndex = #', regexp, start);
+    List match = JS('JSExtendableArray|Null', '#.exec(#)', regexp, string);
+    if (match == null) return null;
+    // If the last capture group participated, the original regexp did not
+    // match at the start position.
+    if (match.removeLast() != null) return null;
+    return new _MatchImplementation(this, match);
+  }
+
+  RegExpMatch matchAsPrefix(String string, [int start = 0]) {
+    if (start < 0 || start > string.length) {
+      throw new RangeError.range(start, 0, string.length);
+    }
+    return _execAnchored(string, start);
+  }
+
+  bool get isMultiLine => _isMultiLine;
+  bool get isCaseSensitive => _isCaseSensitive;
+  bool get isUnicode => _isUnicode;
+  bool get isDotAll => _isDotAll;
+}
+
+class _MatchImplementation implements RegExpMatch {
+  final Pattern pattern;
+  // Contains a JS RegExp match object.
+  // It is an Array of String values with extra 'index' and 'input' properties.
+  // If there were named capture groups, there will also be an extra 'groups'
+  // property containing an object with capture group names as keys and
+  // matched strings as values.
+  // We didn't force it to be JSArray<String>, so it is JSArray<dynamic>, but
+  // containing String or `undefined` values.
+  final JSArray _match;
+
+  _MatchImplementation(this.pattern, this._match) {
+    assert(JS('var', '#.input', _match) is String);
+    assert(JS('var', '#.index', _match) is int);
+  }
+
+  String get input => JS('String', '#.input', _match);
+
+  int get start =>
+      JS('returns:int;depends:none;effects:none;gvn:true', '#.index', _match);
+
+  int get end =>
+      start +
+      JS('returns:int;depends:none;effects:none;gvn:true', '#[0].length',
+          _match);
+
+  // The JS below changes the static type to avoid an implicit cast.
+  // TODO(sra): Find a nicer way to do this, e.g. unsafeCast.
+  String group(int index) => JS('String|Null', '#', _match[index]);
+
+  String operator [](int index) => group(index);
+
+  int get groupCount => _match.length - 1;
+
+  List<String> groups(List<int> groups) {
+    List<String> out = [];
+    for (int i in groups) {
+      out.add(group(i));
+    }
+    return out;
+  }
+
+  String namedGroup(String name) {
+    var groups = JS('Object', '#.groups', _match);
+    if (groups != null) {
+      var result = JS('String|Null', '#[#]', groups, name);
+      if (result != null || JS('bool', '# in #', name, groups)) {
+        return result;
+      }
+    }
+    throw ArgumentError.value(name, "name", "Not a capture group name");
+  }
+
+  Iterable<String> get groupNames {
+    var groups = JS('Object', '#.groups', _match);
+    if (groups != null) {
+      var keys = new JSArray<String>.markGrowable(
+          JS('returns:JSExtendableArray;new:true', 'Object.keys(#)', groups));
+      return SubListIterable(keys, 0, null);
+    }
+    return Iterable.empty();
+  }
+}
+
+class _AllMatchesIterable extends IterableBase<RegExpMatch> {
+  final JSSyntaxRegExp _re;
+  final String _string;
+  final int _start;
+
+  _AllMatchesIterable(this._re, this._string, this._start);
+
+  Iterator<RegExpMatch> get iterator =>
+      new _AllMatchesIterator(_re, _string, _start);
+}
+
+class _AllMatchesIterator implements Iterator<RegExpMatch> {
+  final JSSyntaxRegExp _regExp;
+  String _string;
+  int _nextIndex;
+  RegExpMatch _current;
+
+  _AllMatchesIterator(this._regExp, this._string, this._nextIndex);
+
+  RegExpMatch get current => _current;
+
+  static bool _isLeadSurrogate(int c) {
+    return c >= 0xd800 && c <= 0xdbff;
+  }
+
+  static bool _isTrailSurrogate(int c) {
+    return c >= 0xdc00 && c <= 0xdfff;
+  }
+
+  bool moveNext() {
+    if (_string == null) return false;
+    if (_nextIndex <= _string.length) {
+      var match = _regExp._execGlobal(_string, _nextIndex);
+      if (match != null) {
+        _current = match;
+        int nextIndex = match.end;
+        if (match.start == nextIndex) {
+          // Zero-width match. Advance by one more, unless the regexp
+          // is in unicode mode and it would put us within a surrogate
+          // pair. In that case, advance past the code point as a whole.
+          if (_regExp.isUnicode &&
+              _nextIndex + 1 < _string.length &&
+              _isLeadSurrogate(_string.codeUnitAt(_nextIndex)) &&
+              _isTrailSurrogate(_string.codeUnitAt(_nextIndex + 1))) {
+            nextIndex++;
+          }
+          nextIndex++;
+        }
+        _nextIndex = nextIndex;
+        return true;
+      }
+    }
+    _current = null;
+    _string = null; // Marks iteration as ended.
+    return false;
+  }
+}
+
+/// Find the first match of [regExp] in [string] at or after [start].
+RegExpMatch firstMatchAfter(JSSyntaxRegExp regExp, String string, int start) {
+  return regExp._execGlobal(string, start);
+}
diff --git a/sdk_nnbd/lib/_internal/js_runtime/lib/rti.dart b/sdk_nnbd/lib/_internal/js_runtime/lib/rti.dart
new file mode 100644
index 0000000..f7ca527
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_runtime/lib/rti.dart
@@ -0,0 +1,2492 @@
+// 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.
+
+/// This library contains support for runtime type information.
+library rti;
+
+import 'dart:_foreign_helper'
+    show
+        getInterceptor,
+        getJSArrayInteropRti,
+        JS,
+        JS_BUILTIN,
+        JS_EMBEDDED_GLOBAL,
+        JS_GET_FLAG,
+        JS_GET_NAME,
+        JS_STRING_CONCAT,
+        RAW_DART_FUNCTION_REF;
+
+import 'dart:_interceptors' show JSArray, JSUnmodifiableArray;
+
+import 'dart:_js_names' show unmangleGlobalNameIfPreservedAnyways;
+
+import 'dart:_js_embedded_names'
+    show JsBuiltin, JsGetName, RtiUniverseFieldNames, RTI_UNIVERSE, TYPES;
+
+import 'dart:_recipe_syntax';
+
+/// An Rti object represents both a type (e.g `Map<int, String>`) and a type
+/// environment (`Map<int, String>` binds `Map.K=int` and `Map.V=String`).
+///
+/// There is a single [Rti] class to help reduce polymorphism in the JavaScript
+/// runtime. The class has a default constructor and no final fields so it can
+/// be created before much of the runtime exists.
+///
+/// The fields are declared in an order that gets shorter minified names for the
+/// more commonly used fields. (TODO: we should exploit the fact that an Rti
+/// instance never appears in a dynamic context, so does not need field names to
+/// be distinct from dynamic selectors).
+///
+class Rti {
+  /// JavaScript method for 'as' check. The method is called from generated code,
+  /// e.g. `o as T` generates something like `rtiForT._as(o)`.
+  @pragma('dart2js:noElision')
+  dynamic _as;
+
+  /// JavaScript method for type check.  The method is called from generated
+  /// code, e.g. parameter check for `T param` generates something like
+  /// `rtiForT._check(param)`.
+  @pragma('dart2js:noElision')
+  dynamic _check;
+
+  /// JavaScript method for 'is' test.  The method is called from generated
+  /// code, e.g. `o is T` generates something like `rtiForT._is(o)`.
+  @pragma('dart2js:noElision')
+  dynamic _is;
+
+  static void _setAsCheckFunction(Rti rti, fn) {
+    rti._as = fn;
+  }
+
+  static void _setTypeCheckFunction(Rti rti, fn) {
+    rti._check = fn;
+  }
+
+  static void _setIsTestFunction(Rti rti, fn) {
+    rti._is = fn;
+  }
+
+  @pragma('dart2js:tryInline')
+  static bool _isCheck(Rti rti, object) {
+    return JS(
+        'bool', '#.#(#)', rti, JS_GET_NAME(JsGetName.RTI_FIELD_IS), object);
+  }
+
+  /// Method called from generated code to evaluate a type environment recipe in
+  /// `this` type environment.
+  Rti _eval(recipe) {
+    // TODO(sra): Clone the fast-path of _Universe.evalInEnvironment to here.
+    return _rtiEval(this, _Utils.asString(recipe));
+  }
+
+  /// Method called from generated code to extend `this` type environment (an
+  /// interface or binding Rti) with function type arguments (a singleton
+  /// argument or tuple of arguments).
+  Rti _bind(typeOrTuple) => _rtiBind(this, _castToRti(typeOrTuple));
+
+  /// Method called from generated code to extend `this` type (as a singleton
+  /// type environment) with function type arguments (a singleton argument or
+  /// tuple of arguments).
+  Rti _bind1(Rti typeOrTuple) => _rtiBind1(this, typeOrTuple);
+
+  // Precomputed derived types. These fields are used to hold derived types that
+  // are computed eagerly.
+  // TODO(sra): Implement precomputed type optimizations.
+  dynamic _precomputed1;
+  dynamic _precomputed2;
+  dynamic _precomputed3;
+  dynamic _precomputed4;
+
+  // The Type object corresponding to this Rti.
+  Object _cachedRuntimeType;
+  static _Type _getCachedRuntimeType(Rti rti) =>
+      JS('_Type|Null', '#', rti._cachedRuntimeType);
+  static void _setCachedRuntimeType(Rti rti, _Type type) {
+    rti._cachedRuntimeType = type;
+  }
+
+  /// The kind of Rti `this` is, one of the kindXXX constants below.
+  ///
+  /// We don't use an enum since we need to create Rti objects very early.
+  ///
+  /// The zero initializer ensures dart2js type analysis considers [_kind] is
+  /// non-nullable.
+  Object /*int*/ _kind = 0;
+
+  static int _getKind(Rti rti) => _Utils.asInt(rti._kind);
+  static void _setKind(Rti rti, int kind) {
+    rti._kind = kind;
+  }
+
+  // Terminal terms.
+  static const kindNever = 1;
+  static const kindDynamic = 2;
+  static const kindVoid = 3; // TODO(sra): Use `dynamic` instead?
+  static const kindAny = 4; // Dart1-style 'dynamic' for JS-interop.
+  // Unary terms.
+  static const kindStar = 5;
+  static const kindQuestion = 6;
+  static const kindFutureOr = 7;
+  // More complex terms.
+  static const kindInterface = 8;
+  // A vector of type parameters from enclosing functions and closures.
+  static const kindBinding = 9;
+  static const kindFunction = 10;
+  static const kindGenericFunction = 11;
+  static const kindGenericFunctionParameter = 12;
+
+  static bool _isUnionOfFunctionType(Rti rti) {
+    int kind = Rti._getKind(rti);
+    if (kind == kindStar || kind == kindQuestion || kind == kindFutureOr) {
+      return _isUnionOfFunctionType(_castToRti(_getPrimary(rti)));
+    }
+    return kind == kindFunction || kind == kindGenericFunction;
+  }
+
+  /// Primary data associated with type.
+  ///
+  /// - Minified name of interface for interface types.
+  /// - Underlying type for unary terms.
+  /// - Class part of a type environment inside a generic class, or `null` for
+  ///   type tuple.
+  /// - Return type of a function type.
+  /// - Underlying function type for a generic function.
+  /// - de Bruijn index for a generic function parameter.
+  dynamic _primary;
+
+  static Object _getPrimary(Rti rti) => rti._primary;
+  static void _setPrimary(Rti rti, value) {
+    rti._primary = value;
+  }
+
+  /// Additional data associated with type.
+  ///
+  /// - The type arguments of an interface type.
+  /// - The type arguments from enclosing functions and closures for a
+  ///   kindBinding.
+  /// - The [_FunctionParameters] of a function type.
+  /// - The type parameter bounds of a generic function.
+  dynamic _rest;
+
+  static Object _getRest(Rti rti) => rti._rest;
+  static void _setRest(Rti rti, value) {
+    rti._rest = value;
+  }
+
+  static String _getInterfaceName(Rti rti) {
+    assert(_getKind(rti) == kindInterface);
+    return _Utils.asString(_getPrimary(rti));
+  }
+
+  static JSArray _getInterfaceTypeArguments(Rti rti) {
+    // The array is a plain JavaScript Array, otherwise we would need the type
+    // `JSArray<Rti>` to exist before we could create the type `JSArray<Rti>`.
+    assert(_getKind(rti) == kindInterface);
+    return JS('JSUnmodifiableArray', '#', _getRest(rti));
+  }
+
+  static Rti _getBindingBase(Rti rti) {
+    assert(_getKind(rti) == kindBinding);
+    return _castToRti(_getPrimary(rti));
+  }
+
+  static JSArray _getBindingArguments(Rti rti) {
+    assert(_getKind(rti) == kindBinding);
+    return JS('JSUnmodifiableArray', '#', _getRest(rti));
+  }
+
+  static Rti _getStarArgument(Rti rti) {
+    assert(_getKind(rti) == kindStar);
+    return _castToRti(_getPrimary(rti));
+  }
+
+  static Rti _getQuestionArgument(Rti rti) {
+    assert(_getKind(rti) == kindQuestion);
+    return _castToRti(_getPrimary(rti));
+  }
+
+  static Rti _getFutureOrArgument(Rti rti) {
+    assert(_getKind(rti) == kindFutureOr);
+    return _castToRti(_getPrimary(rti));
+  }
+
+  static Rti _getReturnType(Rti rti) {
+    assert(_getKind(rti) == kindFunction);
+    return _castToRti(_getPrimary(rti));
+  }
+
+  static _FunctionParameters _getFunctionParameters(Rti rti) {
+    assert(_getKind(rti) == kindFunction);
+    return JS('_FunctionParameters', '#', _getRest(rti));
+  }
+
+  static Rti _getGenericFunctionBase(Rti rti) {
+    assert(_getKind(rti) == kindGenericFunction);
+    return _castToRti(_getPrimary(rti));
+  }
+
+  static JSArray _getGenericFunctionBounds(Rti rti) {
+    assert(_getKind(rti) == kindGenericFunction);
+    return JS('JSUnmodifiableArray', '#', _getRest(rti));
+  }
+
+  static int _getGenericFunctionParameterIndex(Rti rti) {
+    assert(_getKind(rti) == kindGenericFunctionParameter);
+    return _Utils.asInt(_getPrimary(rti));
+  }
+
+  /// On [Rti]s that are type environments*, derived types are cached on the
+  /// environment to ensure fast canonicalization. Ground-term types (i.e. not
+  /// dependent on class or function type parameters) are cached in the
+  /// universe. This field starts as `null` and the cache is created on demand.
+  ///
+  /// *Any Rti can be a type environment, since we use the type for a function
+  /// type environment. The ambiguity between 'generic class is the environment'
+  /// and 'generic class is a singleton type argument' is resolved by using
+  /// different indexing in the recipe.
+  Object _evalCache;
+
+  static Object _getEvalCache(Rti rti) => rti._evalCache;
+  static void _setEvalCache(Rti rti, value) {
+    rti._evalCache = value;
+  }
+
+  /// On [Rti]s that are type environments*, extended environments are cached on
+  /// the base environment to ensure fast canonicalization.
+  ///
+  /// This field starts as `null` and the cache is created on demand.
+  ///
+  /// *This is valid only on kindInterface and kindBinding Rtis. The ambiguity
+  /// between 'generic class is the base environment' and 'generic class is a
+  /// singleton type argument' is resolved [TBD] (either (1) a bind1 cache, or
+  /// (2)using `env._eval("@<0>")._bind(args)` in place of `env._bind1(args)`).
+  ///
+  /// On [Rti]s that are generic function types, results of instantiation are
+  /// cached on the generic function type to ensure fast repeated
+  /// instantiations.
+  Object _bindCache;
+
+  static Object _getBindCache(Rti rti) => rti._bindCache;
+  static void _setBindCache(Rti rti, value) {
+    rti._bindCache = value;
+  }
+
+  static Rti allocate() {
+    return new Rti();
+  }
+
+  Object _canonicalRecipe;
+
+  static String _getCanonicalRecipe(Rti rti) {
+    Object s = rti._canonicalRecipe;
+    assert(_Utils.isString(s), 'Missing canonical recipe');
+    return _Utils.asString(s);
+  }
+
+  static void _setCanonicalRecipe(Rti rti, String s) {
+    rti._canonicalRecipe = s;
+  }
+}
+
+class _FunctionParameters {
+  // TODO(fishythefish): Support required named parameters.
+
+  static _FunctionParameters allocate() => _FunctionParameters();
+
+  Object _requiredPositional;
+  static JSArray _getRequiredPositional(_FunctionParameters parameters) =>
+      JS('JSUnmodifiableArray', '#', parameters._requiredPositional);
+  static void _setRequiredPositional(
+      _FunctionParameters parameters, Object requiredPositional) {
+    parameters._requiredPositional = requiredPositional;
+  }
+
+  Object _optionalPositional;
+  static JSArray _getOptionalPositional(_FunctionParameters parameters) =>
+      JS('JSUnmodifiableArray', '#', parameters._optionalPositional);
+  static void _setOptionalPositional(
+      _FunctionParameters parameters, Object optionalPositional) {
+    parameters._optionalPositional = optionalPositional;
+  }
+
+  /// These are alternating name/type pairs; that is, the optional named
+  /// parameters of the function
+  ///
+  ///   void foo({int bar, double baz})
+  ///
+  /// would be encoded as ["bar", int, "baz", double], where the even indices are
+  /// the name [String]s and the odd indices are the type [Rti]s.
+  ///
+  /// Invariant: These pairs are sorted by name in lexicographically ascending order.
+  Object _optionalNamed;
+  static JSArray _getOptionalNamed(_FunctionParameters parameters) =>
+      JS('JSUnmodifiableArray', '#', parameters._optionalNamed);
+  static void _setOptionalNamed(
+      _FunctionParameters parameters, Object optionalNamed) {
+    parameters._optionalNamed = optionalNamed;
+  }
+}
+
+Object _theUniverse() => JS_EMBEDDED_GLOBAL('', RTI_UNIVERSE);
+
+Rti _rtiEval(Rti environment, String recipe) {
+  return _Universe.evalInEnvironment(_theUniverse(), environment, recipe);
+}
+
+Rti _rtiBind1(Rti environment, Rti types) {
+  return _Universe.bind1(_theUniverse(), environment, types);
+}
+
+Rti _rtiBind(Rti environment, Rti types) {
+  return _Universe.bind(_theUniverse(), environment, types);
+}
+
+/// Evaluate a ground-term type.
+/// Called from generated code.
+Rti findType(String recipe) {
+  return _Universe.eval(_theUniverse(), recipe);
+}
+
+/// Evaluate a type recipe in the environment of an instance.
+Rti evalInInstance(instance, String recipe) {
+  return _rtiEval(instanceType(instance), recipe);
+}
+
+/// Returns [genericFunctionRti] with type parameters bound to those specified
+/// by [instantiationRti].
+///
+/// [genericFunctionRti] must be an rti representation with a number of generic
+/// type parameters matching the number of types provided by [instantiationRti].
+///
+/// Called from generated code.
+@pragma('dart2js:noInline')
+Rti instantiatedGenericFunctionType(
+    Rti genericFunctionRti, Rti instantiationRti) {
+  var bounds = Rti._getGenericFunctionBounds(genericFunctionRti);
+  var typeArguments = Rti._getInterfaceTypeArguments(instantiationRti);
+  assert(_Utils.arrayLength(bounds) == _Utils.arrayLength(typeArguments));
+
+  var cache = Rti._getBindCache(genericFunctionRti);
+  if (cache == null) {
+    cache = JS('', 'new Map()');
+    Rti._setBindCache(genericFunctionRti, cache);
+  }
+  String key = Rti._getCanonicalRecipe(instantiationRti);
+  var probe = _Utils.mapGet(cache, key);
+  if (probe != null) return _castToRti(probe);
+  Rti rti = _instantiate(_theUniverse(),
+      Rti._getGenericFunctionBase(genericFunctionRti), typeArguments, 0);
+  _Utils.mapSet(cache, key, rti);
+  return rti;
+}
+
+/// Substitutes [typeArguments] for generic function parameters in [rti].
+///
+/// Generic function parameters are de Bruijn indices counting up through the
+/// parameters' scopes to index into [typeArguments].
+///
+/// [depth] is the number of subsequent generic function parameters that are in
+/// scope. This is subtracted off the de Bruijn index for the type parameter to
+/// arrive at an potential index into [typeArguments].
+Rti _instantiate(universe, Rti rti, Object typeArguments, int depth) {
+  int kind = Rti._getKind(rti);
+  switch (kind) {
+    case Rti.kindNever:
+    case Rti.kindDynamic:
+    case Rti.kindVoid:
+    case Rti.kindAny:
+      return rti;
+    case Rti.kindStar:
+      Rti baseType = _castToRti(Rti._getPrimary(rti));
+      Rti instantiatedBaseType =
+          _instantiate(universe, baseType, typeArguments, depth);
+      if (_Utils.isIdentical(instantiatedBaseType, baseType)) return rti;
+      return _Universe._lookupStarRti(universe, instantiatedBaseType);
+    case Rti.kindQuestion:
+      Rti baseType = _castToRti(Rti._getPrimary(rti));
+      Rti instantiatedBaseType =
+          _instantiate(universe, baseType, typeArguments, depth);
+      if (_Utils.isIdentical(instantiatedBaseType, baseType)) return rti;
+      return _Universe._lookupQuestionRti(universe, instantiatedBaseType);
+    case Rti.kindFutureOr:
+      Rti baseType = _castToRti(Rti._getPrimary(rti));
+      Rti instantiatedBaseType =
+          _instantiate(universe, baseType, typeArguments, depth);
+      if (_Utils.isIdentical(instantiatedBaseType, baseType)) return rti;
+      return _Universe._lookupFutureOrRti(universe, instantiatedBaseType);
+    case Rti.kindInterface:
+      Object interfaceTypeArguments = Rti._getInterfaceTypeArguments(rti);
+      Object instantiatedInterfaceTypeArguments = _instantiateArray(
+          universe, interfaceTypeArguments, typeArguments, depth);
+      if (_Utils.isIdentical(
+          instantiatedInterfaceTypeArguments, interfaceTypeArguments))
+        return rti;
+      return _Universe._lookupInterfaceRti(universe, Rti._getInterfaceName(rti),
+          instantiatedInterfaceTypeArguments);
+    case Rti.kindBinding:
+      Rti base = Rti._getBindingBase(rti);
+      Rti instantiatedBase = _instantiate(universe, base, typeArguments, depth);
+      Object arguments = Rti._getBindingArguments(rti);
+      Object instantiatedArguments =
+          _instantiateArray(universe, arguments, typeArguments, depth);
+      if (_Utils.isIdentical(instantiatedBase, base) &&
+          _Utils.isIdentical(instantiatedArguments, arguments)) return rti;
+      return _Universe._lookupBindingRti(
+          universe, instantiatedBase, instantiatedArguments);
+    case Rti.kindFunction:
+      Rti returnType = Rti._getReturnType(rti);
+      Rti instantiatedReturnType =
+          _instantiate(universe, returnType, typeArguments, depth);
+      _FunctionParameters functionParameters = Rti._getFunctionParameters(rti);
+      _FunctionParameters instantiatedFunctionParameters =
+          _instantiateFunctionParameters(
+              universe, functionParameters, typeArguments, depth);
+      if (_Utils.isIdentical(instantiatedReturnType, returnType) &&
+          _Utils.isIdentical(
+              instantiatedFunctionParameters, functionParameters)) return rti;
+      return _Universe._lookupFunctionRti(
+          universe, instantiatedReturnType, instantiatedFunctionParameters);
+    case Rti.kindGenericFunction:
+      Object bounds = Rti._getGenericFunctionBounds(rti);
+      depth += _Utils.arrayLength(bounds);
+      Object instantiatedBounds =
+          _instantiateArray(universe, bounds, typeArguments, depth);
+      Rti base = Rti._getGenericFunctionBase(rti);
+      Rti instantiatedBase = _instantiate(universe, base, typeArguments, depth);
+      if (_Utils.isIdentical(instantiatedBounds, bounds) &&
+          _Utils.isIdentical(instantiatedBase, base)) return rti;
+      return _Universe._lookupGenericFunctionRti(
+          universe, instantiatedBase, instantiatedBounds);
+    case Rti.kindGenericFunctionParameter:
+      int index = Rti._getGenericFunctionParameterIndex(rti);
+      if (index < depth) return null;
+      return _castToRti(_Utils.arrayAt(typeArguments, index - depth));
+    default:
+      throw AssertionError(
+          'Attempted to instantiate unexpected RTI kind $kind');
+  }
+}
+
+Object _instantiateArray(
+    universe, Object rtiArray, Object typeArguments, int depth) {
+  bool changed = false;
+  int length = _Utils.arrayLength(rtiArray);
+  Object result = JS('', '[]');
+  for (int i = 0; i < length; i++) {
+    Rti rti = _castToRti(_Utils.arrayAt(rtiArray, i));
+    Rti instantiatedRti = _instantiate(universe, rti, typeArguments, depth);
+    if (!_Utils.isIdentical(instantiatedRti, rti)) {
+      changed = true;
+    }
+    _Utils.arrayPush(result, instantiatedRti);
+  }
+  return changed ? result : rtiArray;
+}
+
+Object _instantiateNamed(
+    universe, Object namedArray, Object typeArguments, int depth) {
+  bool changed = false;
+  int length = _Utils.arrayLength(namedArray);
+  assert(length.isEven);
+  Object result = JS('', '[]');
+  for (int i = 0; i < length; i += 2) {
+    String name = _Utils.asString(_Utils.arrayAt(namedArray, i));
+    Rti rti = _castToRti(_Utils.arrayAt(namedArray, i + 1));
+    Rti instantiatedRti = _instantiate(universe, rti, typeArguments, depth);
+    if (!_Utils.isIdentical(instantiatedRti, rti)) {
+      changed = true;
+    }
+    _Utils.arrayPush(result, name);
+    _Utils.arrayPush(result, instantiatedRti);
+  }
+  return changed ? result : namedArray;
+}
+
+// TODO(fishythefish): Support required named parameters.
+_FunctionParameters _instantiateFunctionParameters(universe,
+    _FunctionParameters functionParameters, Object typeArguments, int depth) {
+  Object requiredPositional =
+      _FunctionParameters._getRequiredPositional(functionParameters);
+  Object instantiatedRequiredPositional =
+      _instantiateArray(universe, requiredPositional, typeArguments, depth);
+  Object optionalPositional =
+      _FunctionParameters._getOptionalPositional(functionParameters);
+  Object instantiatedOptionalPositional =
+      _instantiateArray(universe, optionalPositional, typeArguments, depth);
+  Object optionalNamed =
+      _FunctionParameters._getOptionalNamed(functionParameters);
+  Object instantiatedOptionalNamed =
+      _instantiateNamed(universe, optionalNamed, typeArguments, depth);
+  if (_Utils.isIdentical(instantiatedRequiredPositional, requiredPositional) &&
+      _Utils.isIdentical(instantiatedOptionalPositional, optionalPositional) &&
+      _Utils.isIdentical(instantiatedOptionalNamed, optionalNamed))
+    return functionParameters;
+  _FunctionParameters result = _FunctionParameters.allocate();
+  _FunctionParameters._setRequiredPositional(
+      result, instantiatedRequiredPositional);
+  _FunctionParameters._setOptionalPositional(
+      result, instantiatedOptionalPositional);
+  _FunctionParameters._setOptionalNamed(result, instantiatedOptionalNamed);
+  return result;
+}
+
+bool _isClosure(object) => _Utils.instanceOf(object,
+    JS_BUILTIN('depends:none;effects:none;', JsBuiltin.dartClosureConstructor));
+
+/// Returns the structural function [Rti] of [closure].
+/// Called from generated code.
+Rti closureFunctionType(closure) {
+  var signatureName = JS_GET_NAME(JsGetName.SIGNATURE_NAME);
+  var signature = JS('', '#[#]', closure, signatureName);
+  if (signature != null) {
+    if (JS('bool', 'typeof # == "number"', signature)) {
+      return getTypeFromTypesTable(_Utils.asInt(signature));
+    }
+    return _castToRti(JS('', '#[#]()', closure, signatureName));
+  }
+  return null;
+}
+
+// Subclasses of Closure are synthetic classes. The synthetic classes all
+// extend a 'normal' class (Closure, BoundClosure, StaticClosure), so make
+// them appear to be the superclass.
+// TODO(sra): Can this be done less expensively, e.g. by putting $ti on the
+// prototype of Closure/BoundClosure/StaticClosure classes?
+Rti _closureInterfaceType(closure) {
+  var rti = JS('', r'#[#]', closure, JS_GET_NAME(JsGetName.RTI_NAME));
+  return rti != null
+      ? _castToRti(rti)
+      : _instanceTypeFromConstructor(
+          JS('', '#.__proto__.__proto__.constructor', closure));
+}
+
+/// Returns the Rti type of [object]. Closures have both an interface type
+/// (Closures implement `Function`) and a structural function type. Uses
+/// [testRti] to choose the appropriate type.
+///
+/// Called from generated code.
+Rti instanceOrFunctionType(object, Rti testRti) {
+  if (Rti._isUnionOfFunctionType(testRti)) {
+    if (_isClosure(object)) {
+      // If [testRti] is e.g. `FutureOr<Action>` (where `Action` is some
+      // function type), we don't need to worry about the `Future<Action>`
+      // branch because closures can't be `Future`s.
+      Rti rti = closureFunctionType(object);
+      if (rti != null) return rti;
+    }
+  }
+  return instanceType(object);
+}
+
+/// Returns the Rti type of [object].
+/// Called from generated code.
+Rti instanceType(object) {
+  if (_isClosure(object)) return _closureInterfaceType(object);
+  return _nonClosureInstanceType(object);
+}
+
+Rti _nonClosureInstanceType(object) {
+  // TODO(sra): Add specializations of this method. One possible way is to
+  // arrange that the interceptor has a _getType method that is injected into
+  // DartObject, Interceptor and JSArray. Then this method can be replaced-by
+  // `getInterceptor(o)._getType(o)`, allowing interceptor optimizations to
+  // select the specialization.
+
+  if (_Utils.instanceOf(
+      object,
+      JS_BUILTIN(
+          'depends:none;effects:none;', JsBuiltin.dartObjectConstructor))) {
+    return _instanceType(object);
+  }
+
+  if (_Utils.isArray(object)) {
+    return _arrayInstanceType(object);
+  }
+
+  var interceptor = getInterceptor(object);
+  return _instanceTypeFromConstructor(JS('', '#.constructor', interceptor));
+}
+
+/// Returns the Rti type of JavaScript Array [object].
+/// Called from generated code.
+Rti _arrayInstanceType(object) {
+  // TODO(sra): Do we need to protect against an Array passed between two Dart
+  // programs loaded into the same JavaScript isolate (e.g. via JS-interop).
+  // FWIW, the legacy rti has this problem too. Perhaps JSArrays should use a
+  // program-local `symbol` for the type field.
+  var rti = JS('', r'#[#]', object, JS_GET_NAME(JsGetName.RTI_NAME));
+  return rti != null ? _castToRti(rti) : _castToRti(getJSArrayInteropRti());
+}
+
+/// Returns the Rti type of user-defined class [object].
+/// [object] must not be an intercepted class or a closure.
+/// Called from generated code.
+Rti _instanceType(object) {
+  var rti = JS('', r'#[#]', object, JS_GET_NAME(JsGetName.RTI_NAME));
+  return rti != null
+      ? _castToRti(rti)
+      : _instanceTypeFromConstructor(JS('', '#.constructor', object));
+}
+
+String instanceTypeName(object) {
+  Rti rti = instanceType(object);
+  return _rtiToString(rti, null);
+}
+
+Rti _instanceTypeFromConstructor(constructor) {
+  // TODO(sra): Cache Rti on constructor.
+  return findType(JS('String', '#.name', constructor));
+}
+
+/// Returns the structural function type of [object], or `null` if the object is
+/// not a closure.
+Rti _instanceFunctionType(object) =>
+    _isClosure(object) ? closureFunctionType(object) : null;
+
+/// Returns Rti from types table. The types table is initialized with recipe
+/// strings.
+Rti getTypeFromTypesTable(/*int*/ _index) {
+  int index = _Utils.asInt(_index);
+  var table = JS_EMBEDDED_GLOBAL('', TYPES);
+  var type = _Utils.arrayAt(table, index);
+  if (_Utils.isString(type)) {
+    Rti rti = findType(_Utils.asString(type));
+    _Utils.arraySetAt(table, index, rti);
+    return rti;
+  }
+  return _castToRti(type);
+}
+
+Type getRuntimeType(object) {
+  Rti rti = _instanceFunctionType(object) ?? _nonClosureInstanceType(object);
+  return createRuntimeType(rti);
+}
+
+/// Called from generated code.
+Type createRuntimeType(Rti rti) {
+  _Type type = Rti._getCachedRuntimeType(rti);
+  if (type != null) return type;
+  // TODO(https://github.com/dart-lang/language/issues/428) For NNBD transition,
+  // canonicalization may be needed. It might be possible to generate a
+  // star-free recipe from the canonical recipe and evaluate that.
+  type = _Type(rti);
+  Rti._setCachedRuntimeType(rti, type);
+  return type;
+}
+
+/// Called from generated code in the constant pool.
+Type typeLiteral(String recipe) {
+  return createRuntimeType(findType(recipe));
+}
+
+/// Implementation of [Type] based on Rti.
+class _Type implements Type {
+  final Rti _rti;
+  int _hashCode;
+
+  _Type(this._rti);
+
+  int get hashCode => _hashCode ??= Rti._getCanonicalRecipe(_rti).hashCode;
+
+  @pragma('dart2js:noInline')
+  bool operator ==(other) {
+    return (other is _Type) && identical(_rti, other._rti);
+  }
+
+  @override
+  String toString() => _rtiToString(_rti, null);
+}
+
+/// Called from generated code.
+bool _generalIsTestImplementation(object) {
+  // This static method is installed on an Rti object as a JavaScript instance
+  // method. The Rti object is 'this'.
+  Rti testRti = _castToRti(JS('', 'this'));
+  Rti objectRti = instanceOrFunctionType(object, testRti);
+  return isSubtype(_theUniverse(), objectRti, testRti);
+}
+
+/// Called from generated code.
+_generalAsCheckImplementation(object) {
+  if (object == null) return object;
+  // This static method is installed on an Rti object as a JavaScript instance
+  // method. The Rti object is 'this'.
+  Rti testRti = _castToRti(JS('', 'this'));
+  if (Rti._isCheck(testRti, object)) return object;
+
+  Rti objectRti = instanceOrFunctionType(object, testRti);
+  String message =
+      _Error.compose(object, objectRti, _rtiToString(testRti, null));
+  throw _CastError.fromMessage(message);
+}
+
+/// Called from generated code.
+_generalTypeCheckImplementation(object) {
+  if (object == null) return object;
+  // This static method is installed on an Rti object as a JavaScript instance
+  // method. The Rti object is 'this'.
+  Rti testRti = _castToRti(JS('', 'this'));
+  if (Rti._isCheck(testRti, object)) return object;
+
+  Rti objectRti = instanceOrFunctionType(object, testRti);
+  String message =
+      _Error.compose(object, objectRti, _rtiToString(testRti, null));
+  throw _TypeError.fromMessage(message);
+}
+
+/// Called from generated code.
+checkTypeBound(Rti type, Rti bound, variable) {
+  if (isSubtype(_theUniverse(), type, bound)) return type;
+  String message = "Type '${_rtiToString(type, null)}'"
+      " is not a subtype of type '${_rtiToString(bound, null)}'"
+      " of '${_Utils.asString(variable)}'";
+  throw _TypeError.fromMessage(message);
+}
+
+/// Base class to _CastError and _TypeError.
+class _Error extends Error {
+  final String _message;
+  _Error(this._message);
+
+  static String compose(object, objectRti, checkedTypeDescription) {
+    String objectDescription = Error.safeToString(object);
+    objectRti ??= instanceType(object);
+    String objectTypeDescription = _rtiToString(objectRti, null);
+    return "${objectDescription}:"
+        " type '${objectTypeDescription}'"
+        " is not a subtype of type '${checkedTypeDescription}'";
+  }
+
+  @override
+  String toString() => _message;
+}
+
+class _CastError extends _Error implements CastError {
+  _CastError.fromMessage(String message) : super('CastError: $message');
+
+  factory _CastError.forType(object, String type) {
+    return _CastError.fromMessage(_Error.compose(object, null, type));
+  }
+}
+
+class _TypeError extends _Error implements TypeError {
+  _TypeError.fromMessage(String message) : super('TypeError: $message');
+
+  factory _TypeError.forType(object, String type) {
+    return _TypeError.fromMessage(_Error.compose(object, null, type));
+  }
+
+  @override
+  String get message => _message;
+}
+
+// Specializations.
+//
+// Specializations can be placed on Rti objects as the _as, _check and _is
+// 'methods'. They can also be called directly called from generated code.
+
+/// Specialization for 'is bool'.
+/// Called from generated code.
+bool _isBool(object) {
+  return true == object || false == object;
+}
+
+/// Specialization for 'as bool?'.
+/// Called from generated code.
+bool /*?*/ _asBoolNullable(object) {
+  if (_isBool(object)) return _Utils.asBool(object);
+  if (object == null) return object;
+  throw _CastError.forType(object, 'bool');
+}
+
+/// Specialization for check on 'bool?'.
+/// Called from generated code.
+bool /*?*/ _checkBoolNullable(object) {
+  if (_isBool(object)) return _Utils.asBool(object);
+  if (object == null) return object;
+  throw _TypeError.forType(object, 'bool');
+}
+
+/// Specialization for 'as double?'.
+/// Called from generated code.
+double /*?*/ _asDoubleNullable(object) {
+  if (_isNum(object)) return _Utils.asDouble(object);
+  if (object == null) return object;
+  throw _CastError.forType(object, 'double');
+}
+
+/// Specialization for check on 'double?'.
+/// Called from generated code.
+double /*?*/ _checkDoubleNullable(object) {
+  if (_isNum(object)) return _Utils.asDouble(object);
+  if (object == null) return object;
+  throw _TypeError.forType(object, 'double');
+}
+
+/// Specialization for 'is int'.
+/// Called from generated code.
+bool _isInt(object) {
+  return JS('bool', 'typeof # == "number"', object) &&
+      JS('bool', 'Math.floor(#) === #', object, object);
+}
+
+/// Specialization for 'as int?'.
+/// Called from generated code.
+int /*?*/ _asIntNullable(object) {
+  if (_isInt(object)) return _Utils.asInt(object);
+  if (object == null) return object;
+  throw _CastError.forType(object, 'int');
+}
+
+/// Specialization for check on 'int?'.
+/// Called from generated code.
+int /*?*/ _checkIntNullable(object) {
+  if (_isInt(object)) return _Utils.asInt(object);
+  if (object == null) return object;
+  throw _TypeError.forType(object, 'int');
+}
+
+/// Specialization for 'is num' and 'is double'.
+/// Called from generated code.
+bool _isNum(object) {
+  return JS('bool', 'typeof # == "number"', object);
+}
+
+/// Specialization for 'as num?'.
+/// Called from generated code.
+num /*?*/ _asNumNullable(object) {
+  if (_isNum(object)) return _Utils.asNum(object);
+  if (object == null) return object;
+  throw _CastError.forType(object, 'num');
+}
+
+/// Specialization for check on 'num?'.
+/// Called from generated code.
+num /*?*/ _checkNumNullable(object) {
+  if (_isNum(object)) return _Utils.asNum(object);
+  if (object == null) return object;
+  throw _TypeError.forType(object, 'num');
+}
+
+/// Specialization for 'is String'.
+/// Called from generated code.
+bool _isString(object) {
+  return JS('bool', 'typeof # == "string"', object);
+}
+
+/// Specialization for 'as String?'.
+/// Called from generated code.
+String /*?*/ _asStringNullable(object) {
+  if (_isString(object)) return _Utils.asString(object);
+  if (object == null) return object;
+  throw _CastError.forType(object, 'String');
+}
+
+/// Specialization for check on 'String?'.
+/// Called from generated code.
+String /*?*/ _checkStringNullable(object) {
+  if (_isString(object)) return _Utils.asString(object);
+  if (object == null) return object;
+  throw _TypeError.forType(object, 'String');
+}
+
+String _rtiArrayToString(Object array, List<String> genericContext) {
+  String s = '', sep = '';
+  for (int i = 0; i < _Utils.arrayLength(array); i++) {
+    s += sep +
+        _rtiToString(_castToRti(_Utils.arrayAt(array, i)), genericContext);
+    sep = ', ';
+  }
+  return s;
+}
+
+String _functionRtiToString(Rti functionType, List<String> genericContext,
+    {Object bounds = null}) {
+  String typeParametersText = '';
+  int outerContextLength;
+
+  if (bounds != null) {
+    int boundsLength = _Utils.arrayLength(bounds);
+    if (genericContext == null) {
+      genericContext = <String>[];
+    } else {
+      outerContextLength = genericContext.length;
+    }
+    int offset = genericContext.length;
+    for (int i = boundsLength; i > 0; i--) {
+      genericContext.add('T${offset + i}');
+    }
+
+    String typeSep = '';
+    typeParametersText = '<';
+    for (int i = 0; i < boundsLength; i++) {
+      typeParametersText += typeSep;
+      typeParametersText += genericContext[genericContext.length - 1 - i];
+      Rti boundRti = _castToRti(_Utils.arrayAt(bounds, i));
+      if (!isTopType(boundRti)) {
+        typeParametersText +=
+            ' extends ' + _rtiToString(boundRti, genericContext);
+      }
+      typeSep = ', ';
+    }
+    typeParametersText += '>';
+  }
+
+  // TODO(fishythefish): Support required named parameters.
+  Rti returnType = Rti._getReturnType(functionType);
+  _FunctionParameters parameters = Rti._getFunctionParameters(functionType);
+  var requiredPositional =
+      _FunctionParameters._getRequiredPositional(parameters);
+  int requiredPositionalLength = _Utils.arrayLength(requiredPositional);
+  var optionalPositional =
+      _FunctionParameters._getOptionalPositional(parameters);
+  int optionalPositionalLength = _Utils.arrayLength(optionalPositional);
+  var optionalNamed = _FunctionParameters._getOptionalNamed(parameters);
+  int optionalNamedLength = _Utils.arrayLength(optionalNamed);
+  assert(optionalPositionalLength == 0 || optionalNamedLength == 0);
+
+  String returnTypeText = _rtiToString(returnType, genericContext);
+
+  String argumentsText = '';
+  String sep = '';
+  for (int i = 0; i < requiredPositionalLength; i++) {
+    argumentsText += sep +
+        _rtiToString(
+            _castToRti(_Utils.arrayAt(requiredPositional, i)), genericContext);
+    sep = ', ';
+  }
+
+  if (optionalPositionalLength > 0) {
+    argumentsText += sep + '[';
+    sep = '';
+    for (int i = 0; i < optionalPositionalLength; i++) {
+      argumentsText += sep +
+          _rtiToString(_castToRti(_Utils.arrayAt(optionalPositional, i)),
+              genericContext);
+      sep = ', ';
+    }
+    argumentsText += ']';
+  }
+
+  if (optionalNamedLength > 0) {
+    argumentsText += sep + '{';
+    sep = '';
+    for (int i = 0; i < optionalNamedLength; i += 2) {
+      argumentsText += sep +
+          _rtiToString(_castToRti(_Utils.arrayAt(optionalNamed, i + 1)),
+              genericContext) +
+          ' ' +
+          _Utils.asString(_Utils.arrayAt(optionalNamed, i));
+      sep = ', ';
+    }
+    argumentsText += '}';
+  }
+
+  if (outerContextLength != null) {
+    // Pop all of the generic type parameters.
+    JS('', '#.length = #', genericContext, outerContextLength);
+  }
+
+  // TODO(fishythefish): Below is the same format as the VM. Change to:
+  //
+  //     return '${returnTypeText} Function${typeParametersText}(${argumentsText})';
+  //
+  return '${typeParametersText}(${argumentsText}) => ${returnTypeText}';
+}
+
+String _rtiToString(Rti rti, List<String> genericContext) {
+  int kind = Rti._getKind(rti);
+
+  if (kind == Rti.kindDynamic) return 'dynamic';
+  if (kind == Rti.kindVoid) return 'void';
+  if (kind == Rti.kindNever) return 'Never';
+  if (kind == Rti.kindAny) return 'any';
+
+  if (kind == Rti.kindStar) {
+    Rti starArgument = Rti._getStarArgument(rti);
+    return '${_rtiToString(starArgument, genericContext)}*';
+  }
+
+  if (kind == Rti.kindQuestion) {
+    Rti questionArgument = Rti._getQuestionArgument(rti);
+    return '${_rtiToString(questionArgument, genericContext)}?';
+  }
+
+  if (kind == Rti.kindFutureOr) {
+    Rti futureOrArgument = Rti._getFutureOrArgument(rti);
+    return 'FutureOr<${_rtiToString(futureOrArgument, genericContext)}>';
+  }
+
+  if (kind == Rti.kindInterface) {
+    String name = Rti._getInterfaceName(rti);
+    name = _unminifyOrTag(name);
+    var arguments = Rti._getInterfaceTypeArguments(rti);
+    if (arguments.length != 0) {
+      name += '<' + _rtiArrayToString(arguments, genericContext) + '>';
+    }
+    return name;
+  }
+
+  if (kind == Rti.kindFunction) {
+    return _functionRtiToString(rti, genericContext);
+  }
+
+  if (kind == Rti.kindGenericFunction) {
+    Rti baseFunctionType = Rti._getGenericFunctionBase(rti);
+    Object bounds = Rti._getGenericFunctionBounds(rti);
+    return _functionRtiToString(baseFunctionType, genericContext,
+        bounds: bounds);
+  }
+
+  if (kind == Rti.kindGenericFunctionParameter) {
+    int index = Rti._getGenericFunctionParameterIndex(rti);
+    return genericContext[genericContext.length - 1 - index];
+  }
+
+  return '?';
+}
+
+String _unminifyOrTag(String rawClassName) {
+  String preserved = unmangleGlobalNameIfPreservedAnyways(rawClassName);
+  if (preserved != null) return preserved;
+  return JS_GET_FLAG('MINIFIED') ? 'minified:$rawClassName' : rawClassName;
+}
+
+String _rtiArrayToDebugString(Object array) {
+  String s = '[', sep = '';
+  for (int i = 0; i < _Utils.arrayLength(array); i++) {
+    s += sep + _rtiToDebugString(_castToRti(_Utils.arrayAt(array, i)));
+    sep = ', ';
+  }
+  return s + ']';
+}
+
+String functionParametersToString(_FunctionParameters parameters) {
+  // TODO(fishythefish): Support required named parameters.
+  String s = '(', sep = '';
+  var requiredPositional =
+      _FunctionParameters._getRequiredPositional(parameters);
+  int requiredPositionalLength = _Utils.arrayLength(requiredPositional);
+  var optionalPositional =
+      _FunctionParameters._getOptionalPositional(parameters);
+  int optionalPositionalLength = _Utils.arrayLength(optionalPositional);
+  var optionalNamed = _FunctionParameters._getOptionalNamed(parameters);
+  int optionalNamedLength = _Utils.arrayLength(optionalNamed);
+  assert(optionalPositionalLength == 0 || optionalNamedLength == 0);
+
+  for (int i = 0; i < requiredPositionalLength; i++) {
+    s += sep +
+        _rtiToDebugString(_castToRti(_Utils.arrayAt(requiredPositional, i)));
+    sep = ', ';
+  }
+
+  if (optionalPositionalLength > 0) {
+    s += sep + '[';
+    sep = '';
+    for (int i = 0; i < optionalPositionalLength; i++) {
+      s += sep +
+          _rtiToDebugString(_castToRti(_Utils.arrayAt(optionalPositional, i)));
+      sep = ', ';
+    }
+    s += ']';
+  }
+
+  if (optionalNamedLength > 0) {
+    s += sep + '{';
+    sep = '';
+    for (int i = 0; i < optionalNamedLength; i += 2) {
+      s += sep +
+          _rtiToDebugString(_castToRti(_Utils.arrayAt(optionalNamed, i + 1))) +
+          ' ' +
+          _Utils.asString(_Utils.arrayAt(optionalNamed, i));
+      sep = ', ';
+    }
+    s += '}';
+  }
+
+  return s + ')';
+}
+
+String _rtiToDebugString(Rti rti) {
+  int kind = Rti._getKind(rti);
+
+  if (kind == Rti.kindDynamic) return 'dynamic';
+  if (kind == Rti.kindVoid) return 'void';
+  if (kind == Rti.kindNever) return 'Never';
+  if (kind == Rti.kindAny) return 'any';
+
+  if (kind == Rti.kindStar) {
+    Rti starArgument = Rti._getStarArgument(rti);
+    return 'star(${_rtiToDebugString(starArgument)})';
+  }
+
+  if (kind == Rti.kindQuestion) {
+    Rti questionArgument = Rti._getQuestionArgument(rti);
+    return 'question(${_rtiToDebugString(questionArgument)})';
+  }
+
+  if (kind == Rti.kindFutureOr) {
+    Rti futureOrArgument = Rti._getFutureOrArgument(rti);
+    return 'FutureOr(${_rtiToDebugString(futureOrArgument)})';
+  }
+
+  if (kind == Rti.kindInterface) {
+    String name = Rti._getInterfaceName(rti);
+    var arguments = Rti._getInterfaceTypeArguments(rti);
+    if (_Utils.arrayLength(arguments) == 0) {
+      return 'interface("$name")';
+    } else {
+      return 'interface("$name", ${_rtiArrayToDebugString(arguments)})';
+    }
+  }
+
+  if (kind == Rti.kindBinding) {
+    Rti base = Rti._getBindingBase(rti);
+    var arguments = Rti._getBindingArguments(rti);
+    return 'binding(${_rtiToDebugString(base)}, ${_rtiArrayToDebugString(arguments)})';
+  }
+
+  if (kind == Rti.kindFunction) {
+    Rti returnType = Rti._getReturnType(rti);
+    _FunctionParameters parameters = Rti._getFunctionParameters(rti);
+    return 'function(${_rtiToDebugString(returnType)}, ${functionParametersToString(parameters)})';
+  }
+
+  if (kind == Rti.kindGenericFunction) {
+    Rti baseFunctionType = Rti._getGenericFunctionBase(rti);
+    Object bounds = Rti._getGenericFunctionBounds(rti);
+    return 'genericFunction(${_rtiToDebugString(baseFunctionType)}, ${_rtiArrayToDebugString(bounds)})';
+  }
+
+  if (kind == Rti.kindGenericFunctionParameter) {
+    int index = Rti._getGenericFunctionParameterIndex(rti);
+    return 'genericFunctionParameter($index)';
+  }
+
+  return 'other(kind=$kind)';
+}
+
+/// Class of static methods for the universe of Rti objects.
+///
+/// The universe is the manager object for the Rti instances.
+///
+/// The universe itself is allocated at startup before any types or Dart objects
+/// can be created, so it does not have a Dart type.
+class _Universe {
+  _Universe._() {
+    throw UnimplementedError('_Universe is static methods only');
+  }
+
+  @pragma('dart2js:noInline')
+  static Object create() {
+    // This needs to be kept in sync with `FragmentEmitter.createRtiUniverse` in
+    // `fragment_emitter.dart`.
+    return JS(
+        '',
+        '{'
+            '#: new Map(),'
+            '#: {},'
+            '#: [],' // shared empty array.
+            '}',
+        RtiUniverseFieldNames.evalCache,
+        RtiUniverseFieldNames.typeRules,
+        RtiUniverseFieldNames.sharedEmptyArray);
+  }
+
+  // Field accessors.
+
+  static evalCache(universe) =>
+      JS('', '#.#', universe, RtiUniverseFieldNames.evalCache);
+
+  static Object typeRules(universe) =>
+      JS('', '#.#', universe, RtiUniverseFieldNames.typeRules);
+
+  static Object findRule(universe, String targetType) =>
+      JS('', '#.#', typeRules(universe), targetType);
+
+  static void addRules(universe, rules) {
+    // TODO(fishythefish): Use `Object.assign()` when IE11 is deprecated.
+    var keys = JS('JSArray', 'Object.keys(#)', rules);
+    int length = _Utils.arrayLength(keys);
+    Object ruleset = typeRules(universe);
+    for (int i = 0; i < length; i++) {
+      String targetType = _Utils.asString(_Utils.arrayAt(keys, i));
+      JS('', '#[#] = #[#]', ruleset, targetType, rules, targetType);
+    }
+  }
+
+  static Object sharedEmptyArray(universe) =>
+      JS('JSArray', '#.#', universe, RtiUniverseFieldNames.sharedEmptyArray);
+
+  /// Evaluates [recipe] in the global environment.
+  static Rti eval(Object universe, String recipe) {
+    var cache = evalCache(universe);
+    var probe = _cacheGet(cache, recipe);
+    if (probe != null) return _castToRti(probe);
+    Rti rti = _parseRecipe(universe, null, recipe);
+    _cacheSet(cache, recipe, rti);
+    return rti;
+  }
+
+  static Rti evalInEnvironment(
+      Object universe, Rti environment, String recipe) {
+    var cache = Rti._getEvalCache(environment);
+    if (cache == null) {
+      cache = JS('', 'new Map()');
+      Rti._setEvalCache(environment, cache);
+    }
+    var probe = _cacheGet(cache, recipe);
+    if (probe != null) return _castToRti(probe);
+    Rti rti = _parseRecipe(universe, environment, recipe);
+    _cacheSet(cache, recipe, rti);
+    return rti;
+  }
+
+  static Rti bind(Object universe, Rti environment, Rti argumentsRti) {
+    var cache = Rti._getBindCache(environment);
+    if (cache == null) {
+      cache = JS('', 'new Map()');
+      Rti._setBindCache(environment, cache);
+    }
+    String argumentsRecipe = Rti._getCanonicalRecipe(argumentsRti);
+    var probe = _cacheGet(cache, argumentsRecipe);
+    if (probe != null) return _castToRti(probe);
+    var argumentsArray;
+    if (Rti._getKind(argumentsRti) == Rti.kindBinding) {
+      argumentsArray = Rti._getBindingArguments(argumentsRti);
+    } else {
+      argumentsArray = JS('', '[#]', argumentsRti);
+    }
+    Rti rti = _lookupBindingRti(universe, environment, argumentsArray);
+    _cacheSet(cache, argumentsRecipe, rti);
+    return rti;
+  }
+
+  static Rti bind1(Object universe, Rti environment, Rti argumentsRti) {
+    throw UnimplementedError('_Universe.bind1');
+  }
+
+  static Rti evalTypeVariable(Object universe, Rti environment, String name) {
+    if (Rti._getKind(environment) == Rti.kindBinding) {
+      environment = Rti._getBindingBase(environment);
+    }
+
+    assert(Rti._getKind(environment) == Rti.kindInterface);
+    String interfaceName = Rti._getInterfaceName(environment);
+    Object rule = _Universe.findRule(universe, interfaceName);
+    assert(rule != null);
+    String recipe = TypeRule.lookupTypeVariable(rule, name);
+    return _Universe.evalInEnvironment(universe, environment, recipe);
+  }
+
+  static _cacheGet(cache, key) => JS('', '#.get(#)', cache, key);
+  static void _cacheSet(cache, key, value) {
+    JS('', '#.set(#, #)', cache, key, value);
+  }
+
+  static Rti _parseRecipe(Object universe, Object environment, String recipe) {
+    Object parser = _Parser.create(universe, environment, recipe);
+    Rti rti = _Parser.parse(parser);
+    if (rti != null) return rti;
+    throw UnimplementedError('_Universe._parseRecipe("$recipe")');
+  }
+
+  static Rti _finishRti(Object universe, Rti rti) {
+    // Enter fresh Rti in global table under it's canonical recipe.
+    String key = Rti._getCanonicalRecipe(rti);
+    _cacheSet(evalCache(universe), key, rti);
+
+    // Set up methods to perform type tests.
+
+    // TODO(sra): Find better way to install specializations. Perhaps the
+    // installed version should replace itself with the specialization.
+    var checkFn = RAW_DART_FUNCTION_REF(_generalTypeCheckImplementation);
+    var asFn = RAW_DART_FUNCTION_REF(_generalAsCheckImplementation);
+    var isFn = RAW_DART_FUNCTION_REF(_generalIsTestImplementation);
+
+    if (JS_GET_NAME(JsGetName.INT_RECIPE) == key) {
+      isFn = RAW_DART_FUNCTION_REF(_isInt);
+    } else if (JS_GET_NAME(JsGetName.DOUBLE_RECIPE) == key) {
+      isFn = RAW_DART_FUNCTION_REF(_isNum);
+    } else if (JS_GET_NAME(JsGetName.NUM_RECIPE) == key) {
+      isFn = RAW_DART_FUNCTION_REF(_isNum);
+    } else if (JS_GET_NAME(JsGetName.STRING_RECIPE) == key) {
+      isFn = RAW_DART_FUNCTION_REF(_isString);
+    } else if (JS_GET_NAME(JsGetName.BOOL_RECIPE) == key) {
+      isFn = RAW_DART_FUNCTION_REF(_isBool);
+    }
+
+    Rti._setAsCheckFunction(rti, asFn);
+    Rti._setTypeCheckFunction(rti, checkFn);
+    Rti._setIsTestFunction(rti, isFn);
+    return rti;
+  }
+
+  // For each kind of Rti there are three methods:
+  //
+  // * `lookupXXX` which takes the component parts and returns an existing Rti
+  //   object if it exists.
+  // * `canonicalRecipeOfXXX` that returns the compositional canonical recipe
+  //   for the proposed type.
+  // * `createXXX` to create the type if it does not exist.
+
+  static String _canonicalRecipeOfDynamic() => Recipe.pushDynamicString;
+  static String _canonicalRecipeOfVoid() => Recipe.pushVoidString;
+  static String _canonicalRecipeOfNever() =>
+      Recipe.pushNeverExtensionString + Recipe.extensionOpString;
+  static String _canonicalRecipeOfAny() =>
+      Recipe.pushAnyExtensionString + Recipe.extensionOpString;
+
+  static String _canonicalRecipeOfStar(Rti baseType) =>
+      Rti._getCanonicalRecipe(baseType) + Recipe.wrapStarString;
+  static String _canonicalRecipeOfQuestion(Rti baseType) =>
+      Rti._getCanonicalRecipe(baseType) + Recipe.wrapQuestionString;
+  static String _canonicalRecipeOfFutureOr(Rti baseType) =>
+      Rti._getCanonicalRecipe(baseType) + Recipe.wrapFutureOrString;
+
+  static String _canonicalRecipeOfGenericFunctionParameter(int index) =>
+      '$index' + Recipe.genericFunctionTypeParameterIndexString;
+
+  static Rti _lookupDynamicRti(universe) {
+    return _lookupTerminalRti(
+        universe, Rti.kindDynamic, _canonicalRecipeOfDynamic());
+  }
+
+  static Rti _lookupVoidRti(universe) {
+    return _lookupTerminalRti(universe, Rti.kindVoid, _canonicalRecipeOfVoid());
+  }
+
+  static Rti _lookupNeverRti(universe) {
+    return _lookupTerminalRti(
+        universe, Rti.kindNever, _canonicalRecipeOfNever());
+  }
+
+  static Rti _lookupAnyRti(universe) {
+    return _lookupTerminalRti(universe, Rti.kindAny, _canonicalRecipeOfAny());
+  }
+
+  static Rti _lookupTerminalRti(universe, int kind, String canonicalRecipe) {
+    var cache = evalCache(universe);
+    var probe = _cacheGet(cache, canonicalRecipe);
+    if (probe != null) return _castToRti(probe);
+    return _createTerminalRti(universe, kind, canonicalRecipe);
+  }
+
+  static Rti _createTerminalRti(universe, int kind, String canonicalRecipe) {
+    Rti rti = Rti.allocate();
+    Rti._setKind(rti, kind);
+    Rti._setCanonicalRecipe(rti, canonicalRecipe);
+    return _finishRti(universe, rti);
+  }
+
+  static Rti _lookupStarRti(universe, Rti baseType) => _lookupUnaryRti(
+      universe, Rti.kindStar, baseType, _canonicalRecipeOfStar(baseType));
+
+  static Rti _lookupQuestionRti(universe, Rti baseType) => _lookupUnaryRti(
+      universe,
+      Rti.kindQuestion,
+      baseType,
+      _canonicalRecipeOfQuestion(baseType));
+
+  static Rti _lookupFutureOrRti(universe, Rti baseType) => _lookupUnaryRti(
+      universe,
+      Rti.kindFutureOr,
+      baseType,
+      _canonicalRecipeOfFutureOr(baseType));
+
+  static Rti _lookupUnaryRti(
+      universe, int kind, Rti baseType, String canonicalRecipe) {
+    var cache = evalCache(universe);
+    var probe = _cacheGet(cache, canonicalRecipe);
+    if (probe != null) return _castToRti(probe);
+    return _createUnaryRti(universe, kind, baseType, canonicalRecipe);
+  }
+
+  static Rti _createUnaryRti(
+      universe, int kind, Rti baseType, String canonicalRecipe) {
+    Rti rti = Rti.allocate();
+    Rti._setKind(rti, kind);
+    Rti._setPrimary(rti, baseType);
+    Rti._setCanonicalRecipe(rti, canonicalRecipe);
+    return _finishRti(universe, rti);
+  }
+
+  static Rti _lookupGenericFunctionParameterRti(universe, int index) {
+    String canonicalRecipe = _canonicalRecipeOfGenericFunctionParameter(index);
+    var cache = evalCache(universe);
+    var probe = _cacheGet(cache, canonicalRecipe);
+    if (probe != null) return _castToRti(probe);
+    return _createGenericFunctionParameterRti(universe, index, canonicalRecipe);
+  }
+
+  static Rti _createGenericFunctionParameterRti(
+      universe, int index, String canonicalRecipe) {
+    Rti rti = Rti.allocate();
+    Rti._setKind(rti, Rti.kindGenericFunctionParameter);
+    Rti._setPrimary(rti, index);
+    Rti._setCanonicalRecipe(rti, canonicalRecipe);
+    return _finishRti(universe, rti);
+  }
+
+  static String _canonicalRecipeJoin(Object arguments) {
+    String s = '', sep = '';
+    int length = _Utils.arrayLength(arguments);
+    for (int i = 0; i < length; i++) {
+      Rti argument = _castToRti(_Utils.arrayAt(arguments, i));
+      String subrecipe = Rti._getCanonicalRecipe(argument);
+      s += sep + subrecipe;
+      sep = Recipe.separatorString;
+    }
+    return s;
+  }
+
+  static String _canonicalRecipeJoinNamed(Object arguments) {
+    String s = '', sep = '';
+    int length = _Utils.arrayLength(arguments);
+    assert(length.isEven);
+    for (int i = 0; i < length; i += 2) {
+      String name = _Utils.asString(_Utils.arrayAt(arguments, i));
+      Rti type = _castToRti(_Utils.arrayAt(arguments, i + 1));
+      String subrecipe = Rti._getCanonicalRecipe(type);
+      s += sep + name + Recipe.nameSeparatorString + subrecipe;
+      sep = Recipe.separatorString;
+    }
+    return s;
+  }
+
+  static String _canonicalRecipeOfInterface(String name, Object arguments) {
+    assert(_Utils.isString(name));
+    String s = _Utils.asString(name);
+    int length = _Utils.arrayLength(arguments);
+    if (length != 0) {
+      s += Recipe.startTypeArgumentsString +
+          _canonicalRecipeJoin(arguments) +
+          Recipe.endTypeArgumentsString;
+    }
+    return s;
+  }
+
+  static Rti _lookupInterfaceRti(
+      Object universe, String name, Object arguments) {
+    String key = _canonicalRecipeOfInterface(name, arguments);
+    var cache = evalCache(universe);
+    var probe = _cacheGet(cache, key);
+    if (probe != null) return _castToRti(probe);
+    return _createInterfaceRti(universe, name, arguments, key);
+  }
+
+  static Rti _createInterfaceRti(
+      Object universe, String name, Object typeArguments, String key) {
+    Rti rti = Rti.allocate();
+    Rti._setKind(rti, Rti.kindInterface);
+    Rti._setPrimary(rti, name);
+    Rti._setRest(rti, typeArguments);
+    Rti._setCanonicalRecipe(rti, key);
+    return _finishRti(universe, rti);
+  }
+
+  static String _canonicalRecipeOfBinding(Rti base, Object arguments) {
+    String s = Rti._getCanonicalRecipe(base);
+    s += Recipe
+        .toTypeString; // TODO(sra): Omit when base encoding is Rti without ToType.
+    s += Recipe.startTypeArgumentsString +
+        _canonicalRecipeJoin(arguments) +
+        Recipe.endTypeArgumentsString;
+    return s;
+  }
+
+  /// [arguments] becomes owned by the created Rti.
+  static Rti _lookupBindingRti(Object universe, Rti base, Object arguments) {
+    Rti newBase = base;
+    Object newArguments = arguments;
+    if (Rti._getKind(base) == Rti.kindBinding) {
+      newBase = Rti._getBindingBase(base);
+      newArguments =
+          _Utils.arrayConcat(Rti._getBindingArguments(base), arguments);
+    }
+    String key = _canonicalRecipeOfBinding(newBase, newArguments);
+    var cache = evalCache(universe);
+    var probe = _cacheGet(cache, key);
+    if (probe != null) return _castToRti(probe);
+    return _createBindingRti(universe, newBase, newArguments, key);
+  }
+
+  static Rti _createBindingRti(
+      Object universe, Rti base, Object arguments, String key) {
+    Rti rti = Rti.allocate();
+    Rti._setKind(rti, Rti.kindBinding);
+    Rti._setPrimary(rti, base);
+    Rti._setRest(rti, arguments);
+    Rti._setCanonicalRecipe(rti, key);
+    return _finishRti(universe, rti);
+  }
+
+  static String _canonicalRecipeOfFunction(
+          Rti returnType, _FunctionParameters parameters) =>
+      Rti._getCanonicalRecipe(returnType) +
+      _canonicalRecipeOfFunctionParameters(parameters);
+
+  // TODO(fishythefish): Support required named parameters.
+  static String _canonicalRecipeOfFunctionParameters(
+      _FunctionParameters parameters) {
+    var requiredPositional =
+        _FunctionParameters._getRequiredPositional(parameters);
+    int requiredPositionalLength = _Utils.arrayLength(requiredPositional);
+    var optionalPositional =
+        _FunctionParameters._getOptionalPositional(parameters);
+    int optionalPositionalLength = _Utils.arrayLength(optionalPositional);
+    var optionalNamed = _FunctionParameters._getOptionalNamed(parameters);
+    int optionalNamedLength = _Utils.arrayLength(optionalNamed);
+    assert(optionalPositionalLength == 0 || optionalNamedLength == 0);
+
+    String recipe = Recipe.startFunctionArgumentsString +
+        _canonicalRecipeJoin(requiredPositional);
+
+    if (optionalPositionalLength > 0) {
+      String sep = requiredPositionalLength > 0 ? Recipe.separatorString : '';
+      recipe += sep +
+          Recipe.startOptionalGroupString +
+          _canonicalRecipeJoin(optionalPositional) +
+          Recipe.endOptionalGroupString;
+    }
+
+    if (optionalNamedLength > 0) {
+      String sep = requiredPositionalLength > 0 ? Recipe.separatorString : '';
+      recipe += sep +
+          Recipe.startNamedGroupString +
+          _canonicalRecipeJoinNamed(optionalNamed) +
+          Recipe.endNamedGroupString;
+    }
+
+    return recipe + Recipe.endFunctionArgumentsString;
+  }
+
+  static Rti _lookupFunctionRti(
+      Object universe, Rti returnType, _FunctionParameters parameters) {
+    String key = _canonicalRecipeOfFunction(returnType, parameters);
+    var cache = evalCache(universe);
+    var probe = _cacheGet(cache, key);
+    if (probe != null) return _castToRti(probe);
+    return _createFunctionRti(universe, returnType, parameters, key);
+  }
+
+  static Rti _createFunctionRti(Object universe, Rti returnType,
+      _FunctionParameters parameters, String canonicalRecipe) {
+    Rti rti = Rti.allocate();
+    Rti._setKind(rti, Rti.kindFunction);
+    Rti._setPrimary(rti, returnType);
+    Rti._setRest(rti, parameters);
+    Rti._setCanonicalRecipe(rti, canonicalRecipe);
+    return _finishRti(universe, rti);
+  }
+
+  static String _canonicalRecipeOfGenericFunction(
+          Rti baseFunctionType, Object bounds) =>
+      Rti._getCanonicalRecipe(baseFunctionType) +
+      Recipe.startTypeArgumentsString +
+      _canonicalRecipeJoin(bounds) +
+      Recipe.endTypeArgumentsString;
+
+  static Rti _lookupGenericFunctionRti(
+      Object universe, Rti baseFunctionType, Object bounds) {
+    String key = _canonicalRecipeOfGenericFunction(baseFunctionType, bounds);
+    var cache = evalCache(universe);
+    var probe = _cacheGet(cache, key);
+    if (probe != null) return _castToRti(probe);
+    return _createGenericFunctionRti(universe, baseFunctionType, bounds, key);
+  }
+
+  static Rti _createGenericFunctionRti(Object universe, Rti baseFunctionType,
+      Object bounds, String canonicalRecipe) {
+    Rti rti = Rti.allocate();
+    Rti._setKind(rti, Rti.kindGenericFunction);
+    Rti._setPrimary(rti, baseFunctionType);
+    Rti._setRest(rti, bounds);
+    Rti._setCanonicalRecipe(rti, canonicalRecipe);
+    return _finishRti(universe, rti);
+  }
+}
+
+/// Class of static methods implementing recipe parser.
+///
+/// The recipe is a sequence of operations on a stack machine. The operations
+/// are described below using the format
+///
+///      operation: stack elements before --- stack elements after
+///
+/// integer:  --- integer-value
+///
+/// identifier:  --- string-value
+///
+/// identifier-with-one-period:  --- type-variable-value
+///
+///   Period may be in any position, including first and last e.g. `.x`.
+///
+/// ',':  ---
+///
+///   Ignored. Used to separate elements.
+///
+/// ';': item  ---  ToType(item)
+///
+///   Used to separate elements.
+///
+/// '@': --- dynamicType
+///
+/// '~': --- voidType
+///
+/// '?':  type  ---  type?
+///
+/// '&':  0  ---  NeverType
+/// '&':  1  ---  anyType
+///
+///   Escape op-code with small integer values for encoding rare operations.
+///
+/// '<':  --- position
+///
+///   Saves (pushes) position register, sets position register to end of stack.
+///
+/// '>':  name saved-position type ... type  ---  name<type, ..., type>
+/// '>':  type saved-position type ... type  ---  binding(type, type, ..., type)
+///
+///   When first element is a String: Creates interface type from string 'name'
+///   and the types pushed since the position register was last set. The types
+///   are converted with a ToType operation. Restores position register to
+///   previous saved value.
+///
+///   When first element is an Rti: Creates binding Rti wrapping the first
+///   element. Binding Rtis are flattened: if the first element is a binding
+///   Rti, the new binding Rti has the concatentation of the first element
+///   bindings and new type.
+///
+///
+/// The ToType operation coerces an item to an Rti. This saves encoding looking
+/// up simple interface names and indexed variables.
+///
+///   ToType(string): Creates an interface Rti for the non-generic class.
+///   ToType(integer): Indexes into the environment.
+///   ToType(Rti): Same Rti
+///
+///
+/// Notes on enviroments and indexing.
+///
+/// To avoid creating a binding Rti for a single function type parameter, the
+/// type is passed without creating a 1-tuple object. This means that the
+/// interface Rti for, say, `Map<num,dynamic>` serves as two environments with
+/// different shapes. It is a class environment (K=num, V=dynamic) and a simple
+/// 1-tuple environment. This is supported by index '0' refering to the whole
+/// type, and '1 and '2' refering to K and V positionally:
+///
+///     interface("Map", [num,dynamic])
+///     0                 1   2
+///
+/// Thus the type expression `List<K>` encodes as `List<1>` and in this
+/// environment evaluates to `List<num>`. `List<Map<K,V>>` could be encoded as
+/// either `List<0>` or `List<Map<1,2>>` (and in this environment evaluates to
+/// `List<Map<num,dynamic>>`).
+///
+/// When `Map<num,dynamic>` is combined with a binding `<int,bool>` (e.g. inside
+/// the instance method `Map<K,V>.cast<RK,RV>()`), '0' refers to the base object
+/// of the binding, and then the numbering counts the bindings followed by the
+/// class parameters.
+///
+///     binding(interface("Map", [num,dynamic]), [int, bool])
+///             0                 3   4           1    2
+///
+/// Any environment can be reconstructed via a recipe. The above enviroment for
+/// method `cast` can be constructed as the ground term
+/// `Map<num,dynamic><int,bool>`, or (somewhat pointlessly) reconstructed via
+/// `0<1,2>` or `Map<3,4><1,2>`. The ability to construct an environment
+/// directly rather than via `bind` calls is used in folding sequences of `eval`
+/// and `bind` calls.
+///
+/// While a single type parameter is passed as the type, multiple type
+/// parameters are passed as a tuple. Tuples are encoded as a binding with an
+/// ignored base. `dynamic` can be used as the base, giving an encoding like
+/// `@<int,bool>`.
+///
+/// Bindings flatten, so `@<int><bool><num>` is the same as `@<int,bool,num>`.
+///
+/// The base of a binding does not have to have type parameters. Consider
+/// `CodeUnits`, which mixes in `ListMixin<int>`. The environment inside of
+/// `ListMixin.fold` (from the call `x.codeUnits.fold<bool>(...)`) would be
+///
+///     binding(interface("CodeUnits", []), [bool])
+///
+/// This can be encoded as `CodeUnits;<bool>` (note the `;` to force ToType to
+/// avoid creating an interface type Rti with a single class type
+/// argument). Metadata about the supertypes is used to resolve the recipe
+/// `ListMixin.E` to `int`.
+
+class _Parser {
+  _Parser._() {
+    throw UnimplementedError('_Parser is static methods only');
+  }
+
+  /// Creates a parser object for parsing a recipe against an environment in a
+  /// universe.
+  ///
+  /// Marked as no-inline so the object literal is not cloned by inlining.
+  @pragma('dart2js:noInline')
+  static Object create(Object universe, Object environment, String recipe) {
+    return JS(
+        '',
+        '{'
+            'u:#,' // universe
+            'e:#,' // environment
+            'r:#,' // recipe
+            's:[],' // stack
+            'p:0,' // position of sequence start.
+            '}',
+        universe,
+        environment,
+        recipe);
+  }
+
+  // Field accessors for the parser.
+  static Object universe(Object parser) => JS('', '#.u', parser);
+  static Rti environment(Object parser) => JS('Rti', '#.e', parser);
+  static String recipe(Object parser) => JS('String', '#.r', parser);
+  static Object stack(Object parser) => JS('', '#.s', parser);
+  static int position(Object parser) => JS('int', '#.p', parser);
+  static void setPosition(Object parser, int p) {
+    JS('', '#.p = #', parser, p);
+  }
+
+  static int charCodeAt(String s, int i) => JS('int', '#.charCodeAt(#)', s, i);
+  static void push(Object stack, Object value) {
+    JS('', '#.push(#)', stack, value);
+  }
+
+  static Object pop(Object stack) => JS('', '#.pop()', stack);
+
+  static Rti parse(Object parser) {
+    String source = _Parser.recipe(parser);
+    Object stack = _Parser.stack(parser);
+    int i = 0;
+    while (i < source.length) {
+      int ch = charCodeAt(source, i);
+      if (Recipe.isDigit(ch)) {
+        i = handleDigit(i + 1, ch, source, stack);
+      } else if (Recipe.isIdentifierStart(ch)) {
+        i = handleIdentifer(parser, i, source, stack, false);
+      } else if (ch == Recipe.period) {
+        i = handleIdentifer(parser, i, source, stack, true);
+      } else {
+        i++;
+        switch (ch) {
+          case Recipe.separator:
+            break;
+
+          case Recipe.nameSeparator:
+            break;
+
+          case Recipe.toType:
+            push(stack,
+                toType(universe(parser), environment(parser), pop(stack)));
+            break;
+
+          case Recipe.genericFunctionTypeParameterIndex:
+            push(stack,
+                toGenericFunctionParameter(universe(parser), pop(stack)));
+            break;
+
+          case Recipe.pushDynamic:
+            push(stack, _Universe._lookupDynamicRti(universe(parser)));
+            break;
+
+          case Recipe.pushVoid:
+            push(stack, _Universe._lookupVoidRti(universe(parser)));
+            break;
+
+          case Recipe.startTypeArguments:
+            pushStackFrame(parser, stack);
+            break;
+
+          case Recipe.endTypeArguments:
+            handleTypeArguments(parser, stack);
+            break;
+
+          case Recipe.extensionOp:
+            handleExtendedOperations(parser, stack);
+            break;
+
+          case Recipe.wrapStar:
+            Object u = universe(parser);
+            push(
+                stack,
+                _Universe._lookupStarRti(
+                    u, toType(u, environment(parser), pop(stack))));
+            break;
+
+          case Recipe.wrapQuestion:
+            Object u = universe(parser);
+            push(
+                stack,
+                _Universe._lookupQuestionRti(
+                    u, toType(u, environment(parser), pop(stack))));
+            break;
+
+          case Recipe.wrapFutureOr:
+            Object u = universe(parser);
+            push(
+                stack,
+                _Universe._lookupFutureOrRti(
+                    u, toType(u, environment(parser), pop(stack))));
+            break;
+
+          case Recipe.startFunctionArguments:
+            pushStackFrame(parser, stack);
+            break;
+
+          case Recipe.endFunctionArguments:
+            handleFunctionArguments(parser, stack);
+            break;
+
+          case Recipe.startOptionalGroup:
+            pushStackFrame(parser, stack);
+            break;
+
+          case Recipe.endOptionalGroup:
+            handleOptionalGroup(parser, stack);
+            break;
+
+          case Recipe.startNamedGroup:
+            pushStackFrame(parser, stack);
+            break;
+
+          case Recipe.endNamedGroup:
+            handleNamedGroup(parser, stack);
+            break;
+
+          default:
+            JS('', 'throw "Bad character " + #', ch);
+        }
+      }
+    }
+    Object item = pop(stack);
+    return toType(universe(parser), environment(parser), item);
+  }
+
+  static void pushStackFrame(Object parser, Object stack) {
+    push(stack, position(parser));
+    setPosition(parser, _Utils.arrayLength(stack));
+  }
+
+  static int handleDigit(int i, int digit, String source, Object stack) {
+    int value = Recipe.digitValue(digit);
+    for (; i < source.length; i++) {
+      int ch = charCodeAt(source, i);
+      if (!Recipe.isDigit(ch)) break;
+      value = value * 10 + Recipe.digitValue(ch);
+    }
+    push(stack, value);
+    return i;
+  }
+
+  static int handleIdentifer(
+      Object parser, int start, String source, Object stack, bool hasPeriod) {
+    int i = start + 1;
+    for (; i < source.length; i++) {
+      int ch = charCodeAt(source, i);
+      if (ch == Recipe.period) {
+        if (hasPeriod) break;
+        hasPeriod = true;
+      } else if (Recipe.isIdentifierStart(ch) || Recipe.isDigit(ch)) {
+        // Accept.
+      } else {
+        break;
+      }
+    }
+    String string = _Utils.substring(source, start, i);
+    if (hasPeriod) {
+      push(
+          stack,
+          _Universe.evalTypeVariable(
+              universe(parser), environment(parser), string));
+    } else {
+      push(stack, string);
+    }
+    return i;
+  }
+
+  static void handleTypeArguments(Object parser, Object stack) {
+    Object universe = _Parser.universe(parser);
+    Object arguments = collectArray(parser, stack);
+    Object head = pop(stack);
+    if (_Utils.isString(head)) {
+      String name = _Utils.asString(head);
+      push(stack, _Universe._lookupInterfaceRti(universe, name, arguments));
+    } else {
+      Rti base = toType(universe, environment(parser), head);
+      switch (Rti._getKind(base)) {
+        case Rti.kindFunction:
+          push(stack,
+              _Universe._lookupGenericFunctionRti(universe, base, arguments));
+          break;
+
+        default:
+          push(stack, _Universe._lookupBindingRti(universe, base, arguments));
+          break;
+      }
+    }
+  }
+
+  static const int optionalPositionalSentinel = -1;
+  static const int optionalNamedSentinel = -2;
+
+  static void handleFunctionArguments(Object parser, Object stack) {
+    Object universe = _Parser.universe(parser);
+    _FunctionParameters parameters = _FunctionParameters.allocate();
+    var optionalPositional = _Universe.sharedEmptyArray(universe);
+    var optionalNamed = _Universe.sharedEmptyArray(universe);
+
+    Object head = pop(stack);
+    if (_Utils.isNum(head)) {
+      int sentinel = _Utils.asInt(head);
+      switch (sentinel) {
+        case optionalPositionalSentinel:
+          optionalPositional = pop(stack);
+          break;
+
+        case optionalNamedSentinel:
+          optionalNamed = pop(stack);
+          break;
+
+        default:
+          push(stack, head);
+          break;
+      }
+    } else {
+      push(stack, head);
+    }
+
+    _FunctionParameters._setRequiredPositional(
+        parameters, collectArray(parser, stack));
+    _FunctionParameters._setOptionalPositional(parameters, optionalPositional);
+    _FunctionParameters._setOptionalNamed(parameters, optionalNamed);
+    Rti returnType = toType(universe, environment(parser), pop(stack));
+    push(stack, _Universe._lookupFunctionRti(universe, returnType, parameters));
+  }
+
+  static void handleOptionalGroup(Object parser, Object stack) {
+    Object parameters = collectArray(parser, stack);
+    push(stack, parameters);
+    push(stack, optionalPositionalSentinel);
+  }
+
+  static void handleNamedGroup(Object parser, Object stack) {
+    Object parameters = collectNamed(parser, stack);
+    push(stack, parameters);
+    push(stack, optionalNamedSentinel);
+  }
+
+  static void handleExtendedOperations(Object parser, Object stack) {
+    Object top = pop(stack);
+    if (0 == top) {
+      push(stack, _Universe._lookupNeverRti(universe(parser)));
+      return;
+    }
+    if (1 == top) {
+      push(stack, _Universe._lookupAnyRti(universe(parser)));
+      return;
+    }
+    throw AssertionError('Unexpected extended operation $top');
+  }
+
+  static Object collectArray(Object parser, Object stack) {
+    var array = _Utils.arraySplice(stack, position(parser));
+    toTypes(_Parser.universe(parser), environment(parser), array);
+    setPosition(parser, _Utils.asInt(pop(stack)));
+    return array;
+  }
+
+  static Object collectNamed(Object parser, Object stack) {
+    var array = _Utils.arraySplice(stack, position(parser));
+    toTypesNamed(_Parser.universe(parser), environment(parser), array);
+    setPosition(parser, _Utils.asInt(pop(stack)));
+    return array;
+  }
+
+  /// Coerce a stack item into an Rti object. Strings are converted to interface
+  /// types, integers are looked up in the type environment.
+  static Rti toType(Object universe, Rti environment, Object item) {
+    if (_Utils.isString(item)) {
+      String name = _Utils.asString(item);
+      // TODO(sra): Compile this out for minified code.
+      if ('dynamic' == name) {
+        return _Universe._lookupDynamicRti(universe);
+      }
+      return _Universe._lookupInterfaceRti(
+          universe, name, _Universe.sharedEmptyArray(universe));
+    } else if (_Utils.isNum(item)) {
+      return _Parser.indexToType(universe, environment, _Utils.asInt(item));
+    } else {
+      return _castToRti(item);
+    }
+  }
+
+  static void toTypes(Object universe, Rti environment, Object items) {
+    int length = _Utils.arrayLength(items);
+    for (int i = 0; i < length; i++) {
+      var item = _Utils.arrayAt(items, i);
+      Rti type = toType(universe, environment, item);
+      _Utils.arraySetAt(items, i, type);
+    }
+  }
+
+  static void toTypesNamed(Object universe, Rti environment, Object items) {
+    int length = _Utils.arrayLength(items);
+    assert(length.isEven);
+    for (int i = 1; i < length; i += 2) {
+      var item = _Utils.arrayAt(items, i);
+      Rti type = toType(universe, environment, item);
+      _Utils.arraySetAt(items, i, type);
+    }
+  }
+
+  static Rti indexToType(Object universe, Rti environment, int index) {
+    int kind = Rti._getKind(environment);
+    if (kind == Rti.kindBinding) {
+      if (index == 0) return Rti._getBindingBase(environment);
+      var typeArguments = Rti._getBindingArguments(environment);
+      int len = _Utils.arrayLength(typeArguments);
+      if (index <= len) {
+        return _castToRti(_Utils.arrayAt(typeArguments, index - 1));
+      }
+      // Is index into interface Rti in base.
+      index -= len;
+      environment = Rti._getBindingBase(environment);
+      kind = Rti._getKind(environment);
+    } else {
+      if (index == 0) return environment;
+    }
+    if (kind != Rti.kindInterface) {
+      throw AssertionError('Indexed base must be an interface type');
+    }
+    var typeArguments = Rti._getInterfaceTypeArguments(environment);
+    int len = _Utils.arrayLength(typeArguments);
+    if (index <= len) {
+      return _castToRti(_Utils.arrayAt(typeArguments, index - 1));
+    }
+    throw AssertionError('Bad index $index for $environment');
+  }
+
+  static Rti toGenericFunctionParameter(Object universe, Object item) {
+    assert(_Utils.isNum(item));
+    return _Universe._lookupGenericFunctionParameterRti(
+        universe, _Utils.asInt(item));
+  }
+}
+
+/// Represents the set of supertypes and type variable bindings for a given
+/// target type. The target type itself is not stored on the [TypeRule].
+class TypeRule {
+  TypeRule._() {
+    throw UnimplementedError("TypeRule is static methods only.");
+  }
+
+  static String lookupTypeVariable(rule, String typeVariable) =>
+      JS('', '#.#', rule, typeVariable);
+
+  static JSArray lookupSupertype(rule, String supertype) =>
+      JS('', '#.#', rule, supertype);
+}
+
+// -------- Subtype tests ------------------------------------------------------
+
+// Future entry point from compiled code.
+bool isSubtype(universe, Rti s, Rti t) {
+  return _isSubtype(universe, s, null, t, null);
+}
+
+bool _isSubtype(universe, Rti s, sEnv, Rti t, tEnv) {
+  // TODO(fishythefish): Update for NNBD. See
+  // https://github.com/dart-lang/language/blob/master/resources/type-system/subtyping.md#rules
+
+  // Subtyping is reflexive.
+  if (_Utils.isIdentical(s, t)) return true;
+
+  if (isTopType(t)) return true;
+
+  if (isJsInteropType(s)) return true;
+
+  if (isTopType(s)) {
+    if (isGenericFunctionTypeParameter(t)) return false;
+    if (isFutureOrType(t)) {
+      // [t] is FutureOr<T>. Check [s] <: T.
+      Rti tTypeArgument = Rti._getFutureOrArgument(t);
+      return _isSubtype(universe, s, sEnv, tTypeArgument, tEnv);
+    }
+    return false;
+  }
+
+  // Generic function type parameters must match exactly, which would have
+  // exited earlier.
+  if (isGenericFunctionTypeParameter(s)) return false;
+  if (isGenericFunctionTypeParameter(t)) return false;
+
+  if (isNullType(s)) return true;
+
+  if (isFutureOrType(t)) {
+    // [t] is FutureOr<T>.
+    Rti tTypeArgument = Rti._getFutureOrArgument(t);
+    if (isFutureOrType(s)) {
+      // [s] is FutureOr<S>. Check S <: T.
+      Rti sTypeArgument = Rti._getFutureOrArgument(s);
+      return _isSubtype(universe, sTypeArgument, sEnv, tTypeArgument, tEnv);
+    } else if (_isSubtype(universe, s, sEnv, tTypeArgument, tEnv)) {
+      // `true` because [s] <: T.
+      return true;
+    } else {
+      // Check [s] <: Future<T>.
+      String futureClass = JS_GET_NAME(JsGetName.FUTURE_CLASS_TYPE_NAME);
+      var argumentsArray = JS('', '[#]', tTypeArgument);
+      return _isSubtypeOfInterface(
+          universe, s, sEnv, futureClass, argumentsArray, tEnv);
+    }
+  }
+
+  if (isGenericFunctionKind(t)) {
+    return _isGenericFunctionSubtype(universe, s, sEnv, t, tEnv);
+  }
+
+  if (isFunctionKind(t)) {
+    return _isFunctionSubtype(universe, s, sEnv, t, tEnv);
+  }
+
+  if (isFunctionKind(s) || isGenericFunctionKind(s)) {
+    return isFunctionType(t);
+  }
+
+  assert(Rti._getKind(t) == Rti.kindInterface);
+  String tName = Rti._getInterfaceName(t);
+  var tArgs = Rti._getInterfaceTypeArguments(t);
+
+  return _isSubtypeOfInterface(universe, s, sEnv, tName, tArgs, tEnv);
+}
+
+bool _isGenericFunctionSubtype(universe, Rti s, sEnv, Rti t, tEnv) {
+  assert(isGenericFunctionKind(t));
+  if (!isGenericFunctionKind(s)) return false;
+
+  var sBounds = Rti._getGenericFunctionBounds(s);
+  var tBounds = Rti._getGenericFunctionBounds(t);
+  if (!typesEqual(sBounds, tBounds)) return false;
+  // TODO(fishythefish): Extend [sEnv] and [tEnv] with bindings for the [s]
+  // and [t] type parameters to enable checking the bound against
+  // non-type-parameter terms.
+
+  return _isFunctionSubtype(universe, Rti._getGenericFunctionBase(s), sEnv,
+      Rti._getGenericFunctionBase(t), tEnv);
+}
+
+// TODO(fishythefish): Support required named parameters.
+bool _isFunctionSubtype(universe, Rti s, sEnv, Rti t, tEnv) {
+  assert(isFunctionKind(t));
+  if (!isFunctionKind(s)) return false;
+
+  Rti sReturnType = Rti._getReturnType(s);
+  Rti tReturnType = Rti._getReturnType(t);
+  if (!_isSubtype(universe, sReturnType, sEnv, tReturnType, tEnv)) return false;
+
+  _FunctionParameters sParameters = Rti._getFunctionParameters(s);
+  _FunctionParameters tParameters = Rti._getFunctionParameters(t);
+
+  var sRequiredPositional =
+      _FunctionParameters._getRequiredPositional(sParameters);
+  var tRequiredPositional =
+      _FunctionParameters._getRequiredPositional(tParameters);
+  int sRequiredPositionalLength = _Utils.arrayLength(sRequiredPositional);
+  int tRequiredPositionalLength = _Utils.arrayLength(tRequiredPositional);
+  if (sRequiredPositionalLength > tRequiredPositionalLength) return false;
+  int requiredPositionalDelta =
+      tRequiredPositionalLength - sRequiredPositionalLength;
+
+  var sOptionalPositional =
+      _FunctionParameters._getOptionalPositional(sParameters);
+  var tOptionalPositional =
+      _FunctionParameters._getOptionalPositional(tParameters);
+  int sOptionalPositionalLength = _Utils.arrayLength(sOptionalPositional);
+  int tOptionalPositionalLength = _Utils.arrayLength(tOptionalPositional);
+  if (sRequiredPositionalLength + sOptionalPositionalLength <
+      tRequiredPositionalLength + tOptionalPositionalLength) return false;
+
+  for (int i = 0; i < sRequiredPositionalLength; i++) {
+    Rti sParameter = _castToRti(_Utils.arrayAt(sRequiredPositional, i));
+    Rti tParameter = _castToRti(_Utils.arrayAt(tRequiredPositional, i));
+    if (!_isSubtype(universe, tParameter, tEnv, sParameter, sEnv)) return false;
+  }
+
+  for (int i = 0; i < requiredPositionalDelta; i++) {
+    Rti sParameter = _castToRti(_Utils.arrayAt(sOptionalPositional, i));
+    Rti tParameter = _castToRti(
+        _Utils.arrayAt(tRequiredPositional, sRequiredPositionalLength + i));
+    if (!_isSubtype(universe, tParameter, tEnv, sParameter, sEnv)) return false;
+  }
+
+  for (int i = 0; i < tOptionalPositionalLength; i++) {
+    Rti sParameter = _castToRti(
+        _Utils.arrayAt(sOptionalPositional, requiredPositionalDelta + i));
+    Rti tParameter = _castToRti(_Utils.arrayAt(tOptionalPositional, i));
+    if (!_isSubtype(universe, tParameter, tEnv, sParameter, sEnv)) return false;
+  }
+
+  var sOptionalNamed = _FunctionParameters._getOptionalNamed(sParameters);
+  var tOptionalNamed = _FunctionParameters._getOptionalNamed(tParameters);
+  int sOptionalNamedLength = _Utils.arrayLength(sOptionalNamed);
+  int tOptionalNamedLength = _Utils.arrayLength(tOptionalNamed);
+
+  for (int i = 0, j = 0; j < tOptionalNamedLength; j += 2) {
+    String sName;
+    String tName = _Utils.asString(_Utils.arrayAt(tOptionalNamed, j));
+    do {
+      if (i >= sOptionalNamedLength) return false;
+      sName = _Utils.asString(_Utils.arrayAt(sOptionalNamed, i));
+      i += 2;
+    } while (_Utils.stringLessThan(sName, tName));
+    if (_Utils.stringLessThan(tName, sName)) return false;
+    Rti sType = _castToRti(_Utils.arrayAt(sOptionalNamed, i - 1));
+    Rti tType = _castToRti(_Utils.arrayAt(tOptionalNamed, j + 1));
+    if (!_isSubtype(universe, tType, tEnv, sType, sEnv)) return false;
+  }
+
+  return true;
+}
+
+bool _isSubtypeOfInterface(
+    universe, Rti s, sEnv, String tName, Object tArgs, tEnv) {
+  assert(Rti._getKind(s) == Rti.kindInterface);
+  String sName = Rti._getInterfaceName(s);
+
+  if (sName == tName) {
+    var sArgs = Rti._getInterfaceTypeArguments(s);
+    int length = _Utils.arrayLength(sArgs);
+    assert(length == _Utils.arrayLength(tArgs));
+    for (int i = 0; i < length; i++) {
+      Rti sArg = _castToRti(_Utils.arrayAt(sArgs, i));
+      Rti tArg = _castToRti(_Utils.arrayAt(tArgs, i));
+      if (!_isSubtype(universe, sArg, sEnv, tArg, tEnv)) return false;
+    }
+    return true;
+  }
+
+  Object rule = _Universe.findRule(universe, sName);
+  if (rule == null) return false;
+  var supertypeArgs = TypeRule.lookupSupertype(rule, tName);
+  if (supertypeArgs == null) return false;
+  int length = _Utils.arrayLength(supertypeArgs);
+  assert(length == _Utils.arrayLength(tArgs));
+  for (int i = 0; i < length; i++) {
+    String recipe = _Utils.asString(_Utils.arrayAt(supertypeArgs, i));
+    Rti supertypeArg = _Universe.evalInEnvironment(universe, s, recipe);
+    Rti tArg = _castToRti(_Utils.arrayAt(tArgs, i));
+    if (!_isSubtype(universe, supertypeArg, sEnv, tArg, tEnv)) return false;
+  }
+
+  return true;
+}
+
+/// Types are equal if they are structurally equal up to renaming of bound type
+/// variables and equating all top types.
+///
+/// We ignore renaming of bound type variables because we operate on de Bruijn
+/// indices, not names.
+bool typeEqual(Rti s, Rti t) {
+  if (_Utils.isIdentical(s, t)) return true;
+
+  if (isTopType(s)) return isTopType(t);
+
+  int sKind = Rti._getKind(s);
+  int tKind = Rti._getKind(t);
+  if (sKind != tKind) return false;
+
+  switch (sKind) {
+    case Rti.kindStar:
+    case Rti.kindQuestion:
+    case Rti.kindFutureOr:
+      return typeEqual(
+          _castToRti(Rti._getPrimary(s)), _castToRti(Rti._getPrimary(t)));
+
+    case Rti.kindInterface:
+      if (Rti._getInterfaceName(s) != Rti._getInterfaceName(t)) return false;
+      return typesEqual(
+          Rti._getInterfaceTypeArguments(s), Rti._getInterfaceTypeArguments(t));
+
+    case Rti.kindBinding:
+      return typeEqual(Rti._getBindingBase(s), Rti._getBindingBase(t)) &&
+          typesEqual(Rti._getBindingArguments(s), Rti._getBindingArguments(t));
+
+    case Rti.kindFunction:
+      return typeEqual(Rti._getReturnType(s), Rti._getReturnType(t)) &&
+          functionParametersEqual(
+              Rti._getFunctionParameters(s), Rti._getFunctionParameters(t));
+
+    case Rti.kindGenericFunction:
+      return typeEqual(
+              Rti._getGenericFunctionBase(s), Rti._getGenericFunctionBase(t)) &&
+          typesEqual(Rti._getGenericFunctionBounds(s),
+              Rti._getGenericFunctionBounds(t));
+
+    default:
+      return false;
+  }
+}
+
+bool typesEqual(Object sArray, Object tArray) {
+  int sLength = _Utils.arrayLength(sArray);
+  int tLength = _Utils.arrayLength(tArray);
+  if (sLength != tLength) return false;
+  for (int i = 0; i < sLength; i++) {
+    if (!typeEqual(_castToRti(_Utils.arrayAt(sArray, i)),
+        _castToRti(_Utils.arrayAt(tArray, i)))) return false;
+  }
+  return true;
+}
+
+bool namedTypesEqual(Object sArray, Object tArray) {
+  int sLength = _Utils.arrayLength(sArray);
+  int tLength = _Utils.arrayLength(tArray);
+  assert(sLength.isEven);
+  assert(tLength.isEven);
+  if (sLength != tLength) return false;
+  for (int i = 0; i < sLength; i += 2) {
+    if (_Utils.asString(_Utils.arrayAt(sArray, i)) !=
+        _Utils.asString(_Utils.arrayAt(tArray, i))) return false;
+    if (!typeEqual(_castToRti(_Utils.arrayAt(sArray, i + 1)),
+        _castToRti(_Utils.arrayAt(tArray, i + 1)))) return false;
+  }
+  return true;
+}
+
+// TODO(fishythefish): Support required named parameters.
+bool functionParametersEqual(
+        _FunctionParameters sParameters, _FunctionParameters tParameters) =>
+    typesEqual(_FunctionParameters._getRequiredPositional(sParameters),
+        _FunctionParameters._getRequiredPositional(tParameters)) &&
+    typesEqual(_FunctionParameters._getOptionalPositional(sParameters),
+        _FunctionParameters._getOptionalPositional(tParameters)) &&
+    namedTypesEqual(_FunctionParameters._getOptionalNamed(sParameters),
+        _FunctionParameters._getOptionalNamed(tParameters));
+
+bool isTopType(Rti t) =>
+    isDynamicType(t) || isVoidType(t) || isObjectType(t) || isJsInteropType(t);
+
+bool isDynamicType(Rti t) => Rti._getKind(t) == Rti.kindDynamic;
+bool isVoidType(Rti t) => Rti._getKind(t) == Rti.kindVoid;
+bool isJsInteropType(Rti t) => Rti._getKind(t) == Rti.kindAny;
+
+bool isFutureOrType(Rti t) => Rti._getKind(t) == Rti.kindFutureOr;
+
+bool isFunctionKind(Rti t) => Rti._getKind(t) == Rti.kindFunction;
+bool isGenericFunctionKind(Rti t) => Rti._getKind(t) == Rti.kindGenericFunction;
+
+bool isGenericFunctionTypeParameter(Rti t) =>
+    Rti._getKind(t) == Rti.kindGenericFunctionParameter;
+
+bool isObjectType(Rti t) =>
+    Rti._getKind(t) == Rti.kindInterface &&
+    Rti._getInterfaceName(t) == JS_GET_NAME(JsGetName.OBJECT_CLASS_TYPE_NAME);
+
+// TODO(fishythefish): Which representation should we use for NNBD?
+// Do we also need to check for `Never?`, etc.?
+bool isNullType(Rti t) =>
+    Rti._getKind(t) == Rti.kindInterface &&
+    Rti._getInterfaceName(t) == JS_GET_NAME(JsGetName.NULL_CLASS_TYPE_NAME);
+
+bool isFunctionType(Rti t) =>
+    Rti._getKind(t) == Rti.kindInterface &&
+    Rti._getInterfaceName(t) == JS_GET_NAME(JsGetName.FUNCTION_CLASS_TYPE_NAME);
+
+/// Unchecked cast to Rti.
+Rti _castToRti(s) => JS('Rti', '#', s);
+
+///
+class _Utils {
+  static bool asBool(Object o) => JS('bool', '#', o);
+  static double asDouble(Object o) => JS('double', '#', o);
+  static int asInt(Object o) => JS('int', '#', o);
+  static num asNum(Object o) => JS('num', '#', o);
+  static String asString(Object o) => JS('String', '#', o);
+
+  static bool isString(Object o) => JS('bool', 'typeof # == "string"', o);
+  static bool isNum(Object o) => JS('bool', 'typeof # == "number"', o);
+
+  static bool instanceOf(Object o, Object constructor) =>
+      JS('bool', '# instanceof #', o, constructor);
+
+  static bool isIdentical(s, t) => JS('bool', '# === #', s, t);
+
+  static bool isArray(Object o) => JS('bool', 'Array.isArray(#)', o);
+
+  static int arrayLength(Object array) => JS('int', '#.length', array);
+
+  static Object arrayAt(Object array, int i) => JS('', '#[#]', array, i);
+
+  static void arraySetAt(Object array, int i, Object value) {
+    JS('', '#[#] = #', array, i, value);
+  }
+
+  static JSArray arrayShallowCopy(Object array) =>
+      JS('JSArray', '#.slice()', array);
+
+  static JSArray arraySplice(Object array, int position) =>
+      JS('JSArray', '#.splice(#)', array, position);
+
+  static JSArray arrayConcat(Object a1, Object a2) =>
+      JS('JSArray', '#.concat(#)', a1, a2);
+
+  static void arrayPush(Object array, Object value) {
+    JS('', '#.push(#)', array, value);
+  }
+
+  static String substring(String s, int start, int end) =>
+      JS('String', '#.substring(#, #)', s, start, end);
+
+  static bool stringLessThan(String s1, String s2) =>
+      JS('bool', '# < #', s1, s2);
+
+  static mapGet(cache, key) => JS('', '#.get(#)', cache, key);
+
+  static void mapSet(cache, key, value) {
+    JS('', '#.set(#, #)', cache, key, value);
+  }
+}
+// -------- Entry points for testing -------------------------------------------
+
+String testingCanonicalRecipe(rti) {
+  return Rti._getCanonicalRecipe(rti);
+}
+
+String testingRtiToString(rti) {
+  return _rtiToString(_castToRti(rti), null);
+}
+
+String testingRtiToDebugString(rti) {
+  return _rtiToDebugString(_castToRti(rti));
+}
+
+Object testingCreateUniverse() {
+  return _Universe.create();
+}
+
+void testingAddRules(universe, rules) {
+  _Universe.addRules(universe, rules);
+}
+
+bool testingIsSubtype(universe, rti1, rti2) {
+  return isSubtype(universe, _castToRti(rti1), _castToRti(rti2));
+}
+
+Object testingUniverseEval(universe, String recipe) {
+  return _Universe.eval(universe, recipe);
+}
+
+Object testingEnvironmentEval(universe, environment, String recipe) {
+  return _Universe.evalInEnvironment(universe, _castToRti(environment), recipe);
+}
+
+Object testingEnvironmentBind(universe, environment, arguments) {
+  return _Universe.bind(
+      universe, _castToRti(environment), _castToRti(arguments));
+}
diff --git a/sdk_nnbd/lib/_internal/js_runtime/lib/shared/async_await_error_codes.dart b/sdk_nnbd/lib/_internal/js_runtime/lib/shared/async_await_error_codes.dart
new file mode 100644
index 0000000..f87406b
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_runtime/lib/shared/async_await_error_codes.dart
@@ -0,0 +1,10 @@
+// Copyright (c) 2015, 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.
+
+/// Contains error codes that transformed async/async* functions use to
+/// communicate with js_helper functions.
+
+const int SUCCESS = 0;
+const int ERROR = 1;
+const int STREAM_WAS_CANCELED = 2;
diff --git a/sdk_nnbd/lib/_internal/js_runtime/lib/shared/embedded_names.dart b/sdk_nnbd/lib/_internal/js_runtime/lib/shared/embedded_names.dart
new file mode 100644
index 0000000..50cf7e8
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_runtime/lib/shared/embedded_names.dart
@@ -0,0 +1,452 @@
+// Copyright (c) 2014, 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.
+
+/// Contains the names of globals that are embedded into the output by the
+/// compiler.
+///
+/// Variables embedded this way should be access with `JS_EMBEDDED_GLOBAL` from
+/// the `_foreign_helper` library.
+///
+/// This library is shared between the compiler and the runtime system.
+library dart2js._embedded_names;
+
+/// The name of the property that is used to mark a type as typedef.
+///
+/// Without reflection typedefs are removed (expanded to their function type)
+/// but with reflection an object is needed to have the typedef's name. The
+/// object is marked with this property.
+///
+/// This property name only lives on internal type-objects and is only used
+/// when reflection is enabled.
+const TYPEDEF_PREDICATE_PROPERTY_NAME = r"$$isTypedef";
+
+/// The name of the property that is used to find the function type of a
+/// typedef.
+///
+/// Without reflection typedefs are removed (expanded to their function type)
+/// but with reflection an object is needed to have the typedef's name.
+///
+/// The typedef's object contains a pointer to its function type (as an index
+/// into the embedded global [TYPES]) in this property.
+///
+/// This property name only lives on internal type-objects and is only used
+/// when reflection is enabled.
+const TYPEDEF_TYPE_PROPERTY_NAME = r"$typedefType";
+
+/// The name of the property that is used to find the native superclass of
+/// an extended class.
+///
+/// Every class that extends a native class has this property set on its
+/// native class.
+const NATIVE_SUPERCLASS_TAG_NAME = r"$nativeSuperclassTag";
+
+/// The name of the static-function property name.
+///
+/// This property is set for all tear-offs of static functions, and provides
+/// the static function's unique (potentially minified) name.
+const STATIC_FUNCTION_NAME_PROPERTY_NAME = r'$static_name';
+
+/// The name of the embedded global for metadata.
+///
+/// Use [JsBuiltin.getMetadata] instead of directly accessing this embedded
+/// global.
+const METADATA = 'metadata';
+
+/// A list of types used in the program e.g. for reflection or encoding of
+/// function types.
+///
+/// Use [JsBuiltin.getType] instead of directly accessing this embedded global.
+const TYPES = 'types';
+
+/// Returns a function that maps a name of a class to its type.
+///
+/// This embedded global is used by the runtime when computing the internal
+/// runtime-type-information (rti) object.
+const GET_TYPE_FROM_NAME = 'getTypeFromName';
+
+/// A JS map from mangled global names to their unmangled names.
+///
+/// If the program does not use reflection, this embedded global may be empty
+/// (but not null or undefined).
+const MANGLED_GLOBAL_NAMES = 'mangledGlobalNames';
+
+/// A JS map from mangled instance names to their unmangled names.
+///
+/// This embedded global is mainly used for reflection, but is also used to
+/// map const-symbols (`const Symbol('x')`) to the mangled instance names.
+///
+/// This embedded global may be empty (but not null or undefined).
+const MANGLED_NAMES = 'mangledNames';
+
+/// A JS map from dispatch tags (usually constructor names of DOM classes) to
+/// interceptor class. This map is used to find the correct interceptor for
+/// native classes.
+///
+/// This embedded global is used for natives.
+const INTERCEPTORS_BY_TAG = 'interceptorsByTag';
+
+/// A JS map from dispatch tags (usually constructor names of DOM classes) to
+/// booleans. Every tag entry of [INTERCEPTORS_BY_TAG] has a corresponding
+/// entry in the leaf-tags map.
+///
+/// A tag-entry is true, when a class can be treated as leaf class in the
+/// hierarchy. That is, even though it might have subclasses, all subclasses
+/// have the same code for the used methods.
+///
+/// This embedded global is used for natives.
+const LEAF_TAGS = 'leafTags';
+
+/// A JS function that returns the isolate tag for a given name.
+///
+/// This function uses the [ISOLATE_TAG] (below) to construct a name that is
+/// unique per isolate.
+///
+/// This embedded global is used for natives.
+// TODO(floitsch): should we rename this variable to avoid confusion with
+//    [INTERCEPTORS_BY_TAG] and [LEAF_TAGS].
+const GET_ISOLATE_TAG = 'getIsolateTag';
+
+/// A string that is different for each running isolate.
+///
+/// When this embedded global is initialized a global variable is used to
+/// ensure that no other running isolate uses the same isolate-tag string.
+///
+/// This embedded global is used for natives.
+// TODO(floitsch): should we rename this variable to avoid confusion with
+//    [INTERCEPTORS_BY_TAG] and [LEAF_TAGS].
+const ISOLATE_TAG = 'isolateTag';
+
+/// This embedded global (a function) returns the isolate-specific dispatch-tag
+/// that is used to accelerate interceptor calls.
+const DISPATCH_PROPERTY_NAME = "dispatchPropertyName";
+
+/// An embedded global that maps a [Type] to the [Interceptor] and constructors
+/// for that type.
+///
+/// More documentation can be found in the interceptors library (close to its
+/// use).
+const TYPE_TO_INTERCEPTOR_MAP = "typeToInterceptorMap";
+
+/// The current script's URI when the program was loaded.
+///
+/// This embedded global is set at startup, just before invoking `main`.
+const CURRENT_SCRIPT = 'currentScript';
+
+/// Contains a map from load-ids to lists of part indexes.
+///
+/// To load the deferred library that is represented by the load-id, the runtime
+/// must load all associated URIs (named in DEFERRED_PART_URIS) and initialize
+/// all the loaded hunks (DEFERRED_PART_HASHES).
+///
+/// This embedded global is only used for deferred loading.
+const DEFERRED_LIBRARY_PARTS = 'deferredLibraryParts';
+
+/// Contains a list of URIs (Strings), indexed by part.
+///
+/// The lists in the DEFERRED_LIBRARY_PARTS map contain indexes into this list.
+///
+/// This embedded global is only used for deferred loading.
+const DEFERRED_PART_URIS = 'deferredPartUris';
+
+/// Contains a list of hashes, indexed by part.
+///
+/// The lists in the DEFERRED_LIBRARY_PARTS map contain indexes into this list.
+///
+/// The hashes are associated with the URIs of the load-ids (see
+/// [DEFERRED_PART_URIS]). They are SHA1 (or similar) hashes of the code that
+/// must be loaded. By using cryptographic hashes we can (1) handle loading in
+/// the same web page the parts from multiple Dart applications (2) avoid
+/// loading similar code multiple times.
+///
+/// This embedded global is only used for deferred loading.
+const DEFERRED_PART_HASHES = 'deferredPartHashes';
+
+/// Initialize a loaded hunk.
+///
+/// Once a hunk (the code from a deferred URI) has been loaded it must be
+/// initialized. Calling this function with the corresponding hash (see
+/// [DEFERRED_LIBRARY_HASHES]) initializes the code.
+///
+/// This embedded global is only used for deferred loading.
+const INITIALIZE_LOADED_HUNK = 'initializeLoadedHunk';
+
+/// Returns, whether a hunk (identified by its hash) has already been loaded.
+///
+/// This embedded global is only used for deferred loading.
+const IS_HUNK_LOADED = 'isHunkLoaded';
+
+/// Returns, whether a hunk (identified by its hash) has already been
+/// initialized.
+///
+/// This embedded global is only used for deferred loading.
+const IS_HUNK_INITIALIZED = 'isHunkInitialized';
+
+/// A set (implemented as map to booleans) of hunks (identified by hashes) that
+/// have already been initialized.
+///
+/// This embedded global is only used for deferred loading.
+///
+/// This global is an emitter-internal embedded global, and not used by the
+/// runtime. The constant remains in this file to make sure that other embedded
+/// globals don't clash with it.
+const DEFERRED_INITIALIZED = 'deferredInitialized';
+
+/// A 'Universe' object used by 'dart:_rti'.
+///
+/// This embedded global is used for --experiment-new-rti.
+const RTI_UNIVERSE = 'typeUniverse';
+
+/// Returns a function that creates all precompiled functions (in particular
+/// constructors).
+///
+/// That is, the function returns the array that the full emitter would
+/// otherwise build dynamically when it finishes all classes.
+///
+/// This constant is only used in CSP mode.
+///
+/// This global is an emitter-internal embedded global, and not used by the
+/// runtime. The constant remains in this file to make sure that other embedded
+/// globals don't clash with it.
+const PRECOMPILED = 'precompiled';
+
+/// An emitter-internal embedded global. This global is not used by the runtime.
+const FINISHED_CLASSES = 'finishedClasses';
+
+/// A JavaScript object literal that maps the (minified) JavaScript constructor
+/// name (as given by [JsBuiltin.rawRtiToJsConstructorName] to the
+/// JavaScript constructor.
+///
+/// This embedded global is only used by reflection.
+const ALL_CLASSES = 'allClasses';
+
+/// A map from element to type information.
+///
+/// This embedded global is only used by reflection.
+const TYPE_INFORMATION = 'typeInformation';
+
+/// A map from statics to their descriptors.
+///
+/// This embedded global is only used by reflection.
+const STATICS = 'statics';
+
+/// An array of library descriptors.
+///
+/// The descriptor contains information such as name, uri, classes, ...
+///
+/// This embedded global is only used by reflection.
+const LIBRARIES = 'libraries';
+
+/// A map from lazy statics to their initializers.
+///
+/// This embedded global is only used by reflection.
+const LAZIES = 'lazies';
+
+/// Names that are supported by [JS_GET_NAME].
+// TODO(herhut): Make entries lower case (as in fields) and find a better name.
+enum JsGetName {
+  GETTER_PREFIX,
+  SETTER_PREFIX,
+  CALL_PREFIX,
+  CALL_PREFIX0,
+  CALL_PREFIX1,
+  CALL_PREFIX2,
+  CALL_PREFIX3,
+  CALL_PREFIX4,
+  CALL_PREFIX5,
+  CALL_CATCH_ALL,
+  REFLECTABLE,
+  CLASS_DESCRIPTOR_PROPERTY,
+  REQUIRED_PARAMETER_PROPERTY,
+  DEFAULT_VALUES_PROPERTY,
+  CALL_NAME_PROPERTY,
+  DEFERRED_ACTION_PROPERTY,
+
+  /// Prefix used for generated type argument substitutions on classes.
+  OPERATOR_AS_PREFIX,
+
+  /// Name used for generated function types on classes and methods.
+  SIGNATURE_NAME,
+
+  /// Name of JavaScript property used to store runtime-type information on
+  /// instances of parameterized classes.
+  RTI_NAME,
+
+  /// Name used to tag typedefs.
+  TYPEDEF_TAG,
+
+  /// Name used to tag a function type.
+  FUNCTION_TYPE_TAG,
+
+  /// Name used to tag bounds of a generic function type. If bounds are present,
+  /// the property value is an Array of bounds (the length gives the number of
+  /// type parameters). If absent, the type is not a generic function type.
+  FUNCTION_TYPE_GENERIC_BOUNDS_TAG,
+
+  /// Name used to tag void return in function type representations in
+  /// JavaScript.
+  FUNCTION_TYPE_VOID_RETURN_TAG,
+
+  /// Name used to tag return types in function type representations in
+  /// JavaScript.
+  FUNCTION_TYPE_RETURN_TYPE_TAG,
+
+  /// Name used to tag required parameters in function type representations
+  /// in JavaScript.
+  FUNCTION_TYPE_REQUIRED_PARAMETERS_TAG,
+
+  /// Name used to tag optional parameters in function type representations
+  /// in JavaScript.
+  FUNCTION_TYPE_OPTIONAL_PARAMETERS_TAG,
+
+  /// Name used to tag named parameters in function type representations in
+  /// JavaScript.
+  FUNCTION_TYPE_NAMED_PARAMETERS_TAG,
+
+  /// Name used to tag a FutureOr type.
+  FUTURE_OR_TAG,
+
+  /// Name used to tag type arguments types in FutureOr type representations in
+  /// JavaScript.
+  FUTURE_OR_TYPE_ARGUMENT_TAG,
+
+  /// String representation of the type of the Future class.
+  FUTURE_CLASS_TYPE_NAME,
+
+  /// Field name used for determining if an object or its interceptor has
+  /// JavaScript indexing behavior.
+  IS_INDEXABLE_FIELD_NAME,
+
+  /// String representation of the type of the null class.
+  NULL_CLASS_TYPE_NAME,
+
+  /// String representation of the type of the object class.
+  OBJECT_CLASS_TYPE_NAME,
+
+  /// String representation of the type of the function class.
+  FUNCTION_CLASS_TYPE_NAME,
+
+  /// String recipe for the [bool] type.
+  BOOL_RECIPE,
+
+  /// String recipe for the [double] type.
+  DOUBLE_RECIPE,
+
+  /// String recipe for the [int] type.
+  INT_RECIPE,
+
+  /// String recipe for the [num] type.
+  NUM_RECIPE,
+
+  /// String recipe for the [String] type.
+  STRING_RECIPE,
+
+  /// Property name for Rti._is field.
+  RTI_FIELD_IS,
+}
+
+enum JsBuiltin {
+  /// Returns the JavaScript constructor function for Dart's Object class.
+  /// This can be used for type tests, as in
+  ///
+  ///     var constructor = JS_BUILTIN('', JsBuiltin.dartObjectConstructor);
+  ///     if (JS('bool', '# instanceof #', obj, constructor))
+  ///       ...
+  dartObjectConstructor,
+
+  /// Returns the JavaScript constructor function for the runtime's Closure
+  /// class, the base class of all closure objects.  This can be used for type
+  /// tests, as in
+  ///
+  ///     var constructor = JS_BUILTIN('', JsBuiltin.dartClosureConstructor);
+  ///     if (JS('bool', '# instanceof #', obj, constructor))
+  ///       ...
+  dartClosureConstructor,
+
+  /// Returns the JavaScript-constructor name given an [isCheckProperty].
+  ///
+  /// This relies on a deterministic encoding of is-check properties (for
+  /// example `$isFoo` for a class `Foo`). In minified code the returned
+  /// classname is the minified name of the class.
+  ///
+  ///     JS_BUILTIN('returns:String;depends:none;effects:none',
+  ///                JsBuiltin.isCheckPropertyToJsConstructorName,
+  ///                isCheckProperty);
+  isCheckPropertyToJsConstructorName,
+
+  /// Returns true if the given type is a function type. Returns false for
+  /// the one `Function` type singleton. (See [isFunctionTypeSingleton]).
+  ///
+  ///     JS_BUILTIN('bool', JsBuiltin.isFunctionType, o)
+  isFunctionType,
+
+  /// Returns true if the given type is a FutureOr type.
+  ///
+  ///     JS_BUILTIN('bool', JsBuiltin.isFutureOrType, o)
+  isFutureOrType,
+
+  /// Returns true if the given type is the `void` type.
+  ///
+  ///     JS_BUILTIN('bool', JsBuiltin.isVoidType, o)
+  isVoidType,
+
+  /// Returns true if the given type is the `dynamic` type.
+  ///
+  ///     JS_BUILTIN('bool', JsBuiltin.isDynamicType, o)
+  isDynamicType,
+
+  /// Returns true if the given type is a type argument of a js-interop class
+  /// or a supertype of a js-interop class.
+  ///
+  ///     JS_BUILTIN('bool', JsBuiltin.isJsInteropTypeArgument, o)
+  isJsInteropTypeArgument,
+
+  /// Returns the JavaScript-constructor name given an rti encoding.
+  ///
+  ///     JS_BUILTIN('String', JsBuiltin.rawRtiToJsConstructorName, rti)
+  rawRtiToJsConstructorName,
+
+  /// Returns the raw runtime type of the given object. The given argument
+  /// [o] should be the interceptor (for non-Dart objects).
+  ///
+  ///     JS_BUILTIN('', JsBuiltin.rawRuntimeType, o)
+  rawRuntimeType,
+
+  /// Returns whether the given type is a subtype of other.
+  ///
+  /// The argument `other` is the name of the potential supertype. It is
+  /// computed by `runtimeTypeToString`;
+  ///
+  /// *The `other` name must be passed in before the `type`.*
+  ///
+  ///     JS_BUILTIN('returns:bool;effects:none;depends:none',
+  ///                JsBuiltin.isSubtype, other, type);
+  isSubtype,
+
+  /// Returns true if the given type equals the type given as second
+  /// argument. Use the JS_GET_NAME helpers to get the type representation
+  /// for various Dart classes.
+  ///
+  ///     JS_BUILTIN('returns:bool;effects:none;depends:none',
+  ///                JsBuiltin.isFunctionTypeLiteral, type, name);
+  isGivenTypeRti,
+
+  /// Returns the metadata of the given [index].
+  ///
+  ///     JS_BUILTIN('returns:var;effects:none;depends:none',
+  ///                JsBuiltin.getMetadata, index);
+  getMetadata,
+
+  /// Returns the type of the given [index].
+  ///
+  ///     JS_BUILTIN('returns:var;effects:none;depends:none',
+  ///                JsBuiltin.getType, index);
+  getType,
+}
+
+/// Names of fields of the Rti Universe object.
+class RtiUniverseFieldNames {
+  static String evalCache = 'eC';
+  static String typeRules = 'tR';
+  static String sharedEmptyArray = 'sEA';
+}
diff --git a/sdk_nnbd/lib/_internal/js_runtime/lib/shared/recipe_syntax.dart b/sdk_nnbd/lib/_internal/js_runtime/lib/shared/recipe_syntax.dart
new file mode 100644
index 0000000..7666379
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_runtime/lib/shared/recipe_syntax.dart
@@ -0,0 +1,230 @@
+// 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.
+
+/// Constants and predicates used for encoding and decoding type recipes.
+///
+/// This library is shared between the compiler and the runtime system.
+library dart2js._recipe_syntax;
+
+abstract class Recipe {
+  Recipe._();
+
+  // Operators.
+
+  static const int separator = _comma;
+  static const String separatorString = _commaString;
+
+  static const int toType = _semicolon;
+  static const String toTypeString = _semicolonString;
+
+  static const int pushDynamic = _at;
+  static const String pushDynamicString = _atString;
+  static const int pushVoid = _tilde;
+  static const String pushVoidString = _tildeString;
+
+  static const int wrapStar = _asterisk;
+  static const String wrapStarString = _asteriskString;
+  static const int wrapQuestion = _question;
+  static const String wrapQuestionString = _questionString;
+  static const int wrapFutureOr = _slash;
+  static const String wrapFutureOrString = _slashString;
+
+  static const int startTypeArguments = _lessThan;
+  static const String startTypeArgumentsString = _lessThanString;
+  static const int endTypeArguments = _greaterThan;
+  static const String endTypeArgumentsString = _greaterThanString;
+
+  static const int startFunctionArguments = _leftParen;
+  static const String startFunctionArgumentsString = _leftParenString;
+  static const int endFunctionArguments = _rightParen;
+  static const String endFunctionArgumentsString = _rightParenString;
+  static const int startOptionalGroup = _leftBracket;
+  static const String startOptionalGroupString = _leftBracketString;
+  static const int endOptionalGroup = _rightBracket;
+  static const String endOptionalGroupString = _rightBracketString;
+  static const int startNamedGroup = _leftBrace;
+  static const String startNamedGroupString = _leftBraceString;
+  static const int endNamedGroup = _rightBrace;
+  static const String endNamedGroupString = _rightBraceString;
+  static const int nameSeparator = _colon;
+  static const String nameSeparatorString = _colonString;
+
+  static const int genericFunctionTypeParameterIndex = _circumflex;
+  static const String genericFunctionTypeParameterIndexString =
+      _circumflexString;
+
+  static const int extensionOp = _ampersand;
+  static const String extensionOpString = _ampersandString;
+  static const int pushNeverExtension = 0;
+  static const String pushNeverExtensionString = '$pushNeverExtension';
+  static const int pushAnyExtension = 1;
+  static const String pushAnyExtensionString = '$pushAnyExtension';
+
+  // Number and name components.
+
+  static bool isDigit(int code) => code >= _digit0 && code <= _digit9;
+  static int digitValue(int code) => code - _digit0;
+
+  static bool isIdentifierStart(int ch) =>
+      (((ch | 32) - _lowercaseA) & 0xffff) < 26 ||
+      (ch == _underscore) ||
+      (ch == _dollar);
+
+  static const int period = _period;
+
+  // Private names.
+
+  static const int _formfeed = 0x0C;
+  static const String _formfeedString = '\f';
+
+  static const int _space = 0x20;
+  static const String _spaceString = ' ';
+  static const int _exclamation = 0x21;
+  static const String _exclamationString = '!';
+  static const int _hash = 0x23;
+  static const String _hashString = '#';
+  static const int _dollar = 0x24;
+  static const String _dollarString = r'$';
+  static const int _percent = 0x25;
+  static const String _percentString = '%';
+  static const int _ampersand = 0x26;
+  static const String _ampersandString = '&';
+  static const int _apostrophe = 0x27;
+  static const String _apostropheString = "'";
+  static const int _leftParen = 0x28;
+  static const String _leftParenString = '(';
+  static const int _rightParen = 0x29;
+  static const String _rightParenString = ')';
+  static const int _asterisk = 0x2A;
+  static const String _asteriskString = '*';
+  static const int _plus = 0x2B;
+  static const String _plusString = '+';
+  static const int _comma = 0x2C;
+  static const String _commaString = ',';
+  static const int _minus = 0x2D;
+  static const String _minusString = '-';
+  static const int _period = 0x2E;
+  static const String _periodString = '.';
+  static const int _slash = 0x2F;
+  static const String _slashString = '/';
+
+  static const int _digit0 = 0x30;
+  static const int _digit9 = 0x39;
+
+  static const int _colon = 0x3A;
+  static const String _colonString = ':';
+  static const int _semicolon = 0x3B;
+  static const String _semicolonString = ';';
+  static const int _lessThan = 0x3C;
+  static const String _lessThanString = '<';
+  static const int _equals = 0x3D;
+  static const String _equalsString = '=';
+  static const int _greaterThan = 0x3E;
+  static const String _greaterThanString = '>';
+  static const int _question = 0x3F;
+  static const String _questionString = '?';
+  static const int _at = 0x40;
+  static const String _atString = '@';
+
+  static const int _uppercaseA = 0x41;
+  static const int _uppercaseZ = 0x5A;
+
+  static const int _leftBracket = 0x5B;
+  static const String _leftBracketString = '[';
+  static const int _backslash = 0x5C;
+  static const String _backslashString = r'\';
+  static const int _rightBracket = 0x5D;
+  static const String _rightBracketString = ']';
+  static const int _circumflex = 0x5E;
+  static const String _circumflexString = '^';
+  static const int _underscore = 0x5F;
+  static const String _underscoreString = '_';
+  static const int _backtick = 0x60;
+  static const String _backtickString = '`';
+
+  static const int _lowercaseA = 0x61;
+  static const int _lowercaseZ = 0x7A;
+
+  static const int _leftBrace = 0x7B;
+  static const String _leftBraceString = '{';
+  static const int _vertical = 0x7C;
+  static const String _verticalString = '|';
+  static const int _rightBrace = 0x7D;
+  static const String _rightBraceString = '}';
+  static const int _tilde = 0x7E;
+  static const String _tildeString = '~';
+
+  static void testEquivalence() {
+    void test(String label, int charCode, String str) {
+      if (String.fromCharCode(charCode) != str) {
+        throw StateError("$label: String.fromCharCode($charCode) != $str");
+      }
+    }
+
+    void testExtension(String label, int op, String str) {
+      if ('$op' != str) {
+        throw StateError("$label: $op.toString() != $str");
+      }
+    }
+
+    test("separator", separator, separatorString);
+    test("toType", toType, toTypeString);
+    test("pushDynamic", pushDynamic, pushDynamicString);
+    test("pushVoid", pushVoid, pushVoidString);
+    test("wrapStar", wrapStar, wrapStarString);
+    test("wrapQuestion", wrapQuestion, wrapQuestionString);
+    test("wrapFutureOr", wrapFutureOr, wrapFutureOrString);
+    test("startTypeArguments", startTypeArguments, startTypeArgumentsString);
+    test("endTypeArguments", endTypeArguments, endTypeArgumentsString);
+    test("startFunctionArguments", startFunctionArguments,
+        startFunctionArgumentsString);
+    test("endFunctionArguments", endFunctionArguments,
+        endFunctionArgumentsString);
+    test("startOptionalGroup", startOptionalGroup, startOptionalGroupString);
+    test("endOptionalGroup", endOptionalGroup, endOptionalGroupString);
+    test("startNamedGroup", startNamedGroup, startNamedGroupString);
+    test("endNamedGroup", endNamedGroup, endNamedGroupString);
+    test("nameSeparator", nameSeparator, nameSeparatorString);
+    test("genericFunctionTypeParameterIndex", genericFunctionTypeParameterIndex,
+        genericFunctionTypeParameterIndexString);
+    test("extensionOp", extensionOp, extensionOpString);
+    testExtension(
+        "pushNeverExtension", pushNeverExtension, pushNeverExtensionString);
+    testExtension("pushAnyExtension", pushAnyExtension, pushAnyExtensionString);
+
+    test("_formfeed", _formfeed, _formfeedString);
+    test("_space", _space, _spaceString);
+    test("_exclamation", _exclamation, _exclamationString);
+    test("_hash", _hash, _hashString);
+    test("_dollar", _dollar, _dollarString);
+    test("_percent", _percent, _percentString);
+    test("_ampersand", _ampersand, _ampersandString);
+    test("_apostrophe", _apostrophe, _apostropheString);
+    test("_leftParen", _leftParen, _leftParenString);
+    test("_rightParen", _rightParen, _rightParenString);
+    test("_asterisk", _asterisk, _asteriskString);
+    test("_plus", _plus, _plusString);
+    test("_comma", _comma, _commaString);
+    test("_minus", _minus, _minusString);
+    test("_period", _period, _periodString);
+    test("_slash", _slash, _slashString);
+    test("_colon", _colon, _colonString);
+    test("_semicolon", _semicolon, _semicolonString);
+    test("_lessThan", _lessThan, _lessThanString);
+    test("_equals", _equals, _equalsString);
+    test("_greaterThan", _greaterThan, _greaterThanString);
+    test("_question", _question, _questionString);
+    test("_at", _at, _atString);
+    test("_leftBracket", _leftBracket, _leftBracketString);
+    test("_backslash", _backslash, _backslashString);
+    test("_rightBracket", _rightBracket, _rightBracketString);
+    test("_circumflex", _circumflex, _circumflexString);
+    test("_underscore", _underscore, _underscoreString);
+    test("_backtick", _backtick, _backtickString);
+    test("_leftBrace", _leftBrace, _leftBraceString);
+    test("_vertical", _vertical, _verticalString);
+    test("_rightBrace", _rightBrace, _rightBraceString);
+    test("_tilde", _tilde, _tildeString);
+  }
+}
diff --git a/sdk_nnbd/lib/_internal/js_runtime/lib/string_helper.dart b/sdk_nnbd/lib/_internal/js_runtime/lib/string_helper.dart
new file mode 100644
index 0000000..ea5374e
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_runtime/lib/string_helper.dart
@@ -0,0 +1,331 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of _js_helper;
+
+stringIndexOfStringUnchecked(receiver, other, startIndex) {
+  return JS('int', '#.indexOf(#, #)', receiver, other, startIndex);
+}
+
+substring1Unchecked(receiver, startIndex) {
+  return JS('String', '#.substring(#)', receiver, startIndex);
+}
+
+substring2Unchecked(receiver, startIndex, endIndex) {
+  return JS('String', '#.substring(#, #)', receiver, startIndex, endIndex);
+}
+
+stringContainsStringUnchecked(receiver, other, startIndex) {
+  return stringIndexOfStringUnchecked(receiver, other, startIndex) >= 0;
+}
+
+List<String> stringSplitUnchecked(String receiver, pattern) {
+  return new JSArray<String>.markGrowable(JS(
+      'returns:JSExtendableArray;new:true', '#.split(#)', receiver, pattern));
+}
+
+class StringMatch implements Match {
+  const StringMatch(int this.start, String this.input, String this.pattern);
+
+  int get end => start + pattern.length;
+  String operator [](int g) => group(g);
+  int get groupCount => 0;
+
+  String group(int group_) {
+    if (group_ != 0) {
+      throw new RangeError.value(group_);
+    }
+    return pattern;
+  }
+
+  List<String> groups(List<int> groups_) {
+    List<String> result = new List<String>();
+    for (int g in groups_) {
+      result.add(group(g));
+    }
+    return result;
+  }
+
+  final int start;
+  final String input;
+  final String pattern;
+}
+
+Iterable<Match> allMatchesInStringUnchecked(
+    String pattern, String string, int startIndex) {
+  return new _StringAllMatchesIterable(string, pattern, startIndex);
+}
+
+class _StringAllMatchesIterable extends Iterable<Match> {
+  final String _input;
+  final String _pattern;
+  final int _index;
+
+  _StringAllMatchesIterable(this._input, this._pattern, this._index);
+
+  Iterator<Match> get iterator =>
+      new _StringAllMatchesIterator(_input, _pattern, _index);
+
+  Match get first {
+    int index = stringIndexOfStringUnchecked(_input, _pattern, _index);
+    if (index >= 0) {
+      return new StringMatch(index, _input, _pattern);
+    }
+    throw IterableElementError.noElement();
+  }
+}
+
+class _StringAllMatchesIterator implements Iterator<Match> {
+  final String _input;
+  final String _pattern;
+  int _index;
+  Match _current;
+
+  _StringAllMatchesIterator(this._input, this._pattern, this._index);
+
+  bool moveNext() {
+    if (_index + _pattern.length > _input.length) {
+      _current = null;
+      return false;
+    }
+    var index = stringIndexOfStringUnchecked(_input, _pattern, _index);
+    if (index < 0) {
+      _index = _input.length + 1;
+      _current = null;
+      return false;
+    }
+    int end = index + _pattern.length;
+    _current = new StringMatch(index, _input, _pattern);
+    // Empty match, don't start at same location again.
+    if (end == _index) end++;
+    _index = end;
+    return true;
+  }
+
+  Match get current => _current;
+}
+
+stringContainsUnchecked(receiver, other, startIndex) {
+  if (other is String) {
+    return stringContainsStringUnchecked(receiver, other, startIndex);
+  } else if (other is JSSyntaxRegExp) {
+    return other.hasMatch(receiver.substring(startIndex));
+  } else {
+    var substr = receiver.substring(startIndex);
+    return other.allMatches(substr).isNotEmpty;
+  }
+}
+
+String stringReplaceJS(String receiver, jsRegExp, String replacement) {
+  return JS('String', r'#.replace(#, #)', receiver, jsRegExp,
+      escapeReplacement(replacement));
+}
+
+String escapeReplacement(String replacement) {
+  // The JavaScript `String.prototype.replace` method recognizes replacement
+  // patterns in the replacement string. Dart does not have that behavior, so
+  // the replacement patterns need to be escaped.
+
+  // `String.prototype.replace` tends to be slower when there are replacement
+  // patterns, and the escaping itself uses replacement patterns, so it is
+  // worthwhile checking for `$` first.
+  if (stringContainsStringUnchecked(replacement, r'$', 0)) {
+    return JS('String', r'#.replace(/\$/g, "$$$$")', replacement);
+  }
+  return replacement;
+}
+
+stringReplaceFirstRE(receiver, regexp, replacement, startIndex) {
+  var match = regexp._execGlobal(receiver, startIndex);
+  if (match == null) return receiver;
+  var start = match.start;
+  var end = match.end;
+  return stringReplaceRangeUnchecked(receiver, start, end, replacement);
+}
+
+/// Returns a string for a RegExp pattern that matches [string]. This is done by
+/// escaping all RegExp metacharacters.
+quoteStringForRegExp(string) {
+  // We test and replace essentially the same RegExp because replacement when
+  // there are replacement patterns is slow enough to be worth avoiding.
+  if (JS('bool', r'/[[\]{}()*+?.\\^$|]/.test(#)', string)) {
+    return JS('String', r'#.replace(/[[\]{}()*+?.\\^$|]/g, "\\$&")', string);
+  }
+  return string;
+}
+
+stringReplaceAllUnchecked(receiver, pattern, replacement) {
+  checkString(replacement);
+  if (pattern is String) {
+    return stringReplaceAllUncheckedString(receiver, pattern, replacement);
+  }
+
+  if (pattern is JSSyntaxRegExp) {
+    var re = regExpGetGlobalNative(pattern);
+    return stringReplaceJS(receiver, re, replacement);
+  }
+
+  checkNull(pattern);
+  // TODO(floitsch): implement generic String.replace (with patterns).
+  throw "String.replaceAll(Pattern) UNIMPLEMENTED";
+}
+
+/// Replaces all non-overlapping occurences of [pattern] in [receiver] with
+/// [replacement].  This should be replace with
+/// (String.prototype.replaceAll)[https://github.com/tc39/proposal-string-replace-all]
+/// when available.
+String stringReplaceAllUncheckedString(
+    String receiver, String pattern, String replacement) {
+  if (pattern == "") {
+    if (receiver == "") {
+      return JS('String', '#', replacement); // help type inference.
+    }
+    StringBuffer result = new StringBuffer('');
+    int length = receiver.length;
+    result.write(replacement);
+    for (int i = 0; i < length; i++) {
+      result.write(receiver[i]);
+      result.write(replacement);
+    }
+    return result.toString();
+  }
+
+  if (!const bool.fromEnvironment(
+      'dart2js.testing.String.replaceAll.force.regexp')) {
+    // First check for no match.
+    int index = stringIndexOfStringUnchecked(receiver, pattern, 0);
+    if (index < 0) return receiver;
+
+    // The fastest approach in general is to replace with a global RegExp, but
+    // this requires the receiver string to be long enough to amortize the cost
+    // of creating the RegExp, and the replacement to have no '$' patterns,
+    // which tend to make `String.prototype.replace` much slower. In these
+    // cases, using split-join usually wins.
+    if (receiver.length < 500 ||
+        stringContainsStringUnchecked(replacement, r'$', 0)) {
+      return stringReplaceAllUsingSplitJoin(receiver, pattern, replacement);
+    }
+  }
+  var quoted = quoteStringForRegExp(pattern);
+  var replacer = JS('', "new RegExp(#, 'g')", quoted);
+  return stringReplaceJS(receiver, replacer, replacement);
+}
+
+String stringReplaceAllUsingSplitJoin(receiver, pattern, replacement) {
+  return JS('String', '#.split(#).join(#)', receiver, pattern, replacement);
+}
+
+String _matchString(Match match) => match[0];
+String _stringIdentity(String string) => string;
+
+stringReplaceAllFuncUnchecked(receiver, pattern, onMatch, onNonMatch) {
+  if (onMatch == null) onMatch = _matchString;
+  if (onNonMatch == null) onNonMatch = _stringIdentity;
+  if (pattern is String) {
+    return stringReplaceAllStringFuncUnchecked(
+        receiver, pattern, onMatch, onNonMatch);
+  }
+  // Placing the Pattern test here is indistinguishable from placing it at the
+  // top of the method but it saves an extra check on the `pattern is String`
+  // path.
+  if (pattern is! Pattern) {
+    throw new ArgumentError.value(pattern, 'pattern', 'is not a Pattern');
+  }
+  StringBuffer buffer = new StringBuffer('');
+  int startIndex = 0;
+  for (Match match in pattern.allMatches(receiver)) {
+    buffer.write(onNonMatch(receiver.substring(startIndex, match.start)));
+    buffer.write(onMatch(match));
+    startIndex = match.end;
+  }
+  buffer.write(onNonMatch(receiver.substring(startIndex)));
+  return buffer.toString();
+}
+
+stringReplaceAllEmptyFuncUnchecked(receiver, onMatch, onNonMatch) {
+  // Pattern is the empty string.
+  StringBuffer buffer = new StringBuffer('');
+  int length = receiver.length;
+  int i = 0;
+  buffer.write(onNonMatch(""));
+  while (i < length) {
+    buffer.write(onMatch(new StringMatch(i, receiver, "")));
+    // Special case to avoid splitting a surrogate pair.
+    int code = receiver.codeUnitAt(i);
+    if ((code & ~0x3FF) == 0xD800 && length > i + 1) {
+      // Leading surrogate;
+      code = receiver.codeUnitAt(i + 1);
+      if ((code & ~0x3FF) == 0xDC00) {
+        // Matching trailing surrogate.
+        buffer.write(onNonMatch(receiver.substring(i, i + 2)));
+        i += 2;
+        continue;
+      }
+    }
+    buffer.write(onNonMatch(receiver[i]));
+    i++;
+  }
+  buffer.write(onMatch(new StringMatch(i, receiver, "")));
+  buffer.write(onNonMatch(""));
+  return buffer.toString();
+}
+
+stringReplaceAllStringFuncUnchecked(receiver, pattern, onMatch, onNonMatch) {
+  int patternLength = pattern.length;
+  if (patternLength == 0) {
+    return stringReplaceAllEmptyFuncUnchecked(receiver, onMatch, onNonMatch);
+  }
+  int length = receiver.length;
+  StringBuffer buffer = new StringBuffer('');
+  int startIndex = 0;
+  while (startIndex < length) {
+    int position = stringIndexOfStringUnchecked(receiver, pattern, startIndex);
+    if (position == -1) {
+      break;
+    }
+    buffer.write(onNonMatch(receiver.substring(startIndex, position)));
+    buffer.write(onMatch(new StringMatch(position, receiver, pattern)));
+    startIndex = position + patternLength;
+  }
+  buffer.write(onNonMatch(receiver.substring(startIndex)));
+  return buffer.toString();
+}
+
+stringReplaceFirstUnchecked(receiver, pattern, replacement, int startIndex) {
+  if (pattern is String) {
+    int index = stringIndexOfStringUnchecked(receiver, pattern, startIndex);
+    if (index < 0) return receiver;
+    int end = index + pattern.length;
+    return stringReplaceRangeUnchecked(receiver, index, end, replacement);
+  }
+  if (pattern is JSSyntaxRegExp) {
+    return startIndex == 0
+        ? stringReplaceJS(receiver, regExpGetNative(pattern), replacement)
+        : stringReplaceFirstRE(receiver, pattern, replacement, startIndex);
+  }
+  checkNull(pattern);
+  Iterator<Match> matches = pattern.allMatches(receiver, startIndex).iterator;
+  if (!matches.moveNext()) return receiver;
+  Match match = matches.current;
+  return receiver.replaceRange(match.start, match.end, replacement);
+}
+
+stringReplaceFirstMappedUnchecked(receiver, pattern, replace, int startIndex) {
+  Iterator<Match> matches = pattern.allMatches(receiver, startIndex).iterator;
+  if (!matches.moveNext()) return receiver;
+  Match match = matches.current;
+  String replacement = "${replace(match)}";
+  return receiver.replaceRange(match.start, match.end, replacement);
+}
+
+stringJoinUnchecked(array, separator) {
+  return JS('String', r'#.join(#)', array, separator);
+}
+
+String stringReplaceRangeUnchecked(
+    String receiver, int start, int end, String replacement) {
+  var prefix = JS('String', '#.substring(0, #)', receiver, start);
+  var suffix = JS('String', '#.substring(#)', receiver, end);
+  return "$prefix$replacement$suffix";
+}
diff --git a/sdk_nnbd/lib/_internal/js_runtime/lib/typed_data_patch.dart b/sdk_nnbd/lib/_internal/js_runtime/lib/typed_data_patch.dart
new file mode 100644
index 0000000..615c9da
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_runtime/lib/typed_data_patch.dart
@@ -0,0 +1,190 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:_js_helper' show patch;
+import 'dart:_native_typed_data';
+
+@patch
+class ByteData {
+  @patch
+  factory ByteData(int length) = NativeByteData;
+}
+
+@patch
+class Float32List {
+  @patch
+  factory Float32List(int length) = NativeFloat32List;
+
+  @patch
+  factory Float32List.fromList(List<double> elements) =
+      NativeFloat32List.fromList;
+}
+
+@patch
+class Float64List {
+  @patch
+  factory Float64List(int length) = NativeFloat64List;
+
+  @patch
+  factory Float64List.fromList(List<double> elements) =
+      NativeFloat64List.fromList;
+}
+
+@patch
+class Int16List {
+  @patch
+  factory Int16List(int length) = NativeInt16List;
+
+  @patch
+  factory Int16List.fromList(List<int> elements) = NativeInt16List.fromList;
+}
+
+@patch
+class Int32List {
+  @patch
+  factory Int32List(int length) = NativeInt32List;
+
+  @patch
+  factory Int32List.fromList(List<int> elements) = NativeInt32List.fromList;
+}
+
+@patch
+class Int8List {
+  @patch
+  factory Int8List(int length) = NativeInt8List;
+
+  @patch
+  factory Int8List.fromList(List<int> elements) = NativeInt8List.fromList;
+}
+
+@patch
+class Uint32List {
+  @patch
+  factory Uint32List(int length) = NativeUint32List;
+
+  @patch
+  factory Uint32List.fromList(List<int> elements) = NativeUint32List.fromList;
+}
+
+@patch
+class Uint16List {
+  @patch
+  factory Uint16List(int length) = NativeUint16List;
+
+  @patch
+  factory Uint16List.fromList(List<int> elements) = NativeUint16List.fromList;
+}
+
+@patch
+class Uint8ClampedList {
+  @patch
+  factory Uint8ClampedList(int length) = NativeUint8ClampedList;
+
+  @patch
+  factory Uint8ClampedList.fromList(List<int> elements) =
+      NativeUint8ClampedList.fromList;
+}
+
+@patch
+class Uint8List {
+  @patch
+  factory Uint8List(int length) = NativeUint8List;
+
+  @patch
+  factory Uint8List.fromList(List<int> elements) = NativeUint8List.fromList;
+}
+
+@patch
+class Int64List {
+  @patch
+  factory Int64List(int length) {
+    throw new UnsupportedError("Int64List not supported by dart2js.");
+  }
+
+  @patch
+  factory Int64List.fromList(List<int> elements) {
+    throw new UnsupportedError("Int64List not supported by dart2js.");
+  }
+}
+
+@patch
+class Uint64List {
+  @patch
+  factory Uint64List(int length) {
+    throw new UnsupportedError("Uint64List not supported by dart2js.");
+  }
+
+  @patch
+  factory Uint64List.fromList(List<int> elements) {
+    throw new UnsupportedError("Uint64List not supported by dart2js.");
+  }
+}
+
+@patch
+class Int32x4List {
+  @patch
+  factory Int32x4List(int length) = NativeInt32x4List;
+
+  @patch
+  factory Int32x4List.fromList(List<Int32x4> elements) =
+      NativeInt32x4List.fromList;
+}
+
+@patch
+class Float32x4List {
+  @patch
+  factory Float32x4List(int length) = NativeFloat32x4List;
+
+  @patch
+  factory Float32x4List.fromList(List<Float32x4> elements) =
+      NativeFloat32x4List.fromList;
+}
+
+@patch
+class Float64x2List {
+  @patch
+  factory Float64x2List(int length) = NativeFloat64x2List;
+
+  @patch
+  factory Float64x2List.fromList(List<Float64x2> elements) =
+      NativeFloat64x2List.fromList;
+}
+
+@patch
+class Float32x4 {
+  @patch
+  factory Float32x4(double x, double y, double z, double w) = NativeFloat32x4;
+  @patch
+  factory Float32x4.splat(double v) = NativeFloat32x4.splat;
+  @patch
+  factory Float32x4.zero() = NativeFloat32x4.zero;
+  @patch
+  factory Float32x4.fromInt32x4Bits(Int32x4 x) =
+      NativeFloat32x4.fromInt32x4Bits;
+  @patch
+  factory Float32x4.fromFloat64x2(Float64x2 v) = NativeFloat32x4.fromFloat64x2;
+}
+
+@patch
+class Int32x4 {
+  @patch
+  factory Int32x4(int x, int y, int z, int w) = NativeInt32x4;
+  @patch
+  factory Int32x4.bool(bool x, bool y, bool z, bool w) = NativeInt32x4.bool;
+  @patch
+  factory Int32x4.fromFloat32x4Bits(Float32x4 x) =
+      NativeInt32x4.fromFloat32x4Bits;
+}
+
+@patch
+class Float64x2 {
+  @patch
+  factory Float64x2(double x, double y) = NativeFloat64x2;
+  @patch
+  factory Float64x2.splat(double v) = NativeFloat64x2.splat;
+  @patch
+  factory Float64x2.zero() = NativeFloat64x2.zero;
+  @patch
+  factory Float64x2.fromFloat32x4(Float32x4 v) = NativeFloat64x2.fromFloat32x4;
+}
diff --git a/sdk_nnbd/lib/_internal/js_runtime/pubspec.yaml b/sdk_nnbd/lib/_internal/js_runtime/pubspec.yaml
new file mode 100644
index 0000000..821aaac
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_runtime/pubspec.yaml
@@ -0,0 +1,6 @@
+# Note: This package is not meant to be uploaded to pub. This file is used to
+# make it easier to develop on dart2js.
+name: js_runtime
+publish_to: none
+environment:
+  sdk: '>=2.0.0 <3.0.0'
diff --git a/sdk_nnbd/lib/_internal/sdk_library_metadata/lib/libraries.dart b/sdk_nnbd/lib/_internal/sdk_library_metadata/lib/libraries.dart
new file mode 100644
index 0000000..ba141fa
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/sdk_library_metadata/lib/libraries.dart
@@ -0,0 +1,329 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library libraries;
+
+/**
+ * A bit flag used by [LibraryInfo] indicating that a library is used by dart2js
+ */
+const int DART2JS_PLATFORM = 1;
+
+/**
+ * A bit flag used by [LibraryInfo] indicating that a library is used by the VM
+ */
+const int VM_PLATFORM = 2;
+
+/// The contexts that a library can be used from.
+enum Category {
+  /// Indicates that a library can be used in a browser context.
+  client,
+
+  /// Indicates that a library can be used in a command line context.
+  server,
+
+  /// Indicates that a library can be used from embedded devices.
+  embedded
+}
+
+Category parseCategory(String name) {
+  switch (name) {
+    case "Client":
+      return Category.client;
+    case "Server":
+      return Category.server;
+    case "Embedded":
+      return Category.embedded;
+  }
+  return null;
+}
+
+/// Mapping of "dart:" library name (e.g. "core") to information about that
+/// library.
+const Map<String, LibraryInfo> libraries = const {
+  "async": const LibraryInfo("async/async.dart",
+      categories: "Client,Server",
+      maturity: Maturity.STABLE,
+      dart2jsPatchPath: "_internal/js_runtime/lib/async_patch.dart"),
+  "_chrome": const LibraryInfo("_chrome/dart2js/chrome_dart2js.dart",
+      categories: "Client", documented: false),
+  "collection": const LibraryInfo("collection/collection.dart",
+      categories: "Client,Server,Embedded",
+      maturity: Maturity.STABLE,
+      dart2jsPatchPath: "_internal/js_runtime/lib/collection_patch.dart"),
+  "convert": const LibraryInfo("convert/convert.dart",
+      categories: "Client,Server",
+      maturity: Maturity.STABLE,
+      dart2jsPatchPath: "_internal/js_runtime/lib/convert_patch.dart"),
+  "core": const LibraryInfo("core/core.dart",
+      categories: "Client,Server,Embedded",
+      maturity: Maturity.STABLE,
+      dart2jsPatchPath: "_internal/js_runtime/lib/core_patch.dart"),
+  "developer": const LibraryInfo("developer/developer.dart",
+      categories: "Client,Server,Embedded",
+      maturity: Maturity.UNSTABLE,
+      dart2jsPatchPath: "_internal/js_runtime/lib/developer_patch.dart"),
+  "ffi": const LibraryInfo("ffi/ffi.dart",
+      categories: "Server",
+      // TODO(dacoharkes): Update maturity when we release dart:ffi.
+      // https://github.com/dart-lang/sdk/issues/34452
+      maturity: Maturity.EXPERIMENTAL),
+  "html": const LibraryInfo("html/dart2js/html_dart2js.dart",
+      categories: "Client",
+      maturity: Maturity.WEB_STABLE,
+      platforms: DART2JS_PLATFORM),
+  "html_common": const LibraryInfo("html/html_common/html_common.dart",
+      categories: "Client",
+      maturity: Maturity.WEB_STABLE,
+      dart2jsPath: "html/html_common/html_common_dart2js.dart",
+      documented: false,
+      implementation: true),
+  "indexed_db": const LibraryInfo("indexed_db/dart2js/indexed_db_dart2js.dart",
+      categories: "Client",
+      maturity: Maturity.WEB_STABLE,
+      platforms: DART2JS_PLATFORM),
+  "_http":
+      const LibraryInfo("_http/http.dart", categories: "", documented: false),
+  "io": const LibraryInfo("io/io.dart",
+      categories: "Server",
+      dart2jsPatchPath: "_internal/js_runtime/lib/io_patch.dart"),
+  "isolate": const LibraryInfo("isolate/isolate.dart",
+      categories: "Client,Server",
+      maturity: Maturity.STABLE,
+      dart2jsPatchPath: "_internal/js_runtime/lib/isolate_patch.dart"),
+  "js": const LibraryInfo("js/dart2js/js_dart2js.dart",
+      categories: "Client",
+      maturity: Maturity.STABLE,
+      platforms: DART2JS_PLATFORM),
+  "_js": const LibraryInfo("js/_js.dart",
+      categories: "Client",
+      dart2jsPatchPath: "js/_js_client.dart",
+      documented: false,
+      platforms: DART2JS_PLATFORM),
+  "js_util": const LibraryInfo("js_util/dart2js/js_util_dart2js.dart",
+      categories: "Client",
+      maturity: Maturity.STABLE,
+      platforms: DART2JS_PLATFORM),
+  "math": const LibraryInfo("math/math.dart",
+      categories: "Client,Server,Embedded",
+      maturity: Maturity.STABLE,
+      dart2jsPatchPath: "_internal/js_runtime/lib/math_patch.dart"),
+  "mirrors": const LibraryInfo("mirrors/mirrors.dart",
+      categories: "Client,Server",
+      maturity: Maturity.UNSTABLE,
+      dart2jsPatchPath: "_internal/js_runtime/lib/mirrors_patch_cfe.dart"),
+  "nativewrappers": const LibraryInfo("html/dartium/nativewrappers.dart",
+      categories: "Client",
+      implementation: true,
+      documented: false,
+      platforms: VM_PLATFORM),
+  "typed_data": const LibraryInfo("typed_data/typed_data.dart",
+      categories: "Client,Server,Embedded",
+      maturity: Maturity.STABLE,
+      dart2jsPatchPath: "_internal/js_runtime/lib/typed_data_patch.dart"),
+  "_native_typed_data": const LibraryInfo(
+      "_internal/js_runtime/lib/native_typed_data.dart",
+      categories: "",
+      implementation: true,
+      documented: false,
+      platforms: DART2JS_PLATFORM),
+  "cli": const LibraryInfo("cli/cli.dart",
+      categories: "Server",
+      dart2jsPatchPath: "_internal/js_runtime/lib/cli_patch.dart"),
+  "svg": const LibraryInfo("svg/dart2js/svg_dart2js.dart",
+      categories: "Client",
+      maturity: Maturity.WEB_STABLE,
+      platforms: DART2JS_PLATFORM),
+  "wasm": const LibraryInfo("wasm/wasm.dart",
+      categories: "Server", maturity: Maturity.EXPERIMENTAL),
+  "web_audio": const LibraryInfo("web_audio/dart2js/web_audio_dart2js.dart",
+      categories: "Client",
+      maturity: Maturity.WEB_STABLE,
+      platforms: DART2JS_PLATFORM),
+  "web_gl": const LibraryInfo("web_gl/dart2js/web_gl_dart2js.dart",
+      categories: "Client",
+      maturity: Maturity.WEB_STABLE,
+      platforms: DART2JS_PLATFORM),
+  "web_sql": const LibraryInfo("web_sql/dart2js/web_sql_dart2js.dart",
+      categories: "Client",
+      maturity: Maturity.WEB_STABLE,
+      platforms: DART2JS_PLATFORM),
+  "_internal": const LibraryInfo("internal/internal.dart",
+      categories: "",
+      documented: false,
+      dart2jsPatchPath: "_internal/js_runtime/lib/internal_patch.dart"),
+  "_js_helper": const LibraryInfo("_internal/js_runtime/lib/js_helper.dart",
+      categories: "", documented: false, platforms: DART2JS_PLATFORM),
+  "_rti": const LibraryInfo("_internal/js_runtime/lib/rti.dart",
+      categories: "", documented: false, platforms: DART2JS_PLATFORM),
+  "_interceptors": const LibraryInfo(
+      "_internal/js_runtime/lib/interceptors.dart",
+      categories: "",
+      documented: false,
+      platforms: DART2JS_PLATFORM),
+  "_foreign_helper": const LibraryInfo(
+      "_internal/js_runtime/lib/foreign_helper.dart",
+      categories: "",
+      documented: false,
+      platforms: DART2JS_PLATFORM),
+  "_js_names": const LibraryInfo("_internal/js_runtime/lib/js_names.dart",
+      categories: "", documented: false, platforms: DART2JS_PLATFORM),
+  "_js_primitives": const LibraryInfo(
+      "_internal/js_runtime/lib/js_primitives.dart",
+      categories: "",
+      documented: false,
+      platforms: DART2JS_PLATFORM),
+  "_js_embedded_names": const LibraryInfo(
+      "_internal/js_runtime/lib/shared/embedded_names.dart",
+      categories: "",
+      documented: false,
+      platforms: DART2JS_PLATFORM),
+  "_async_await_error_codes": const LibraryInfo(
+      "_internal/js_runtime/lib/shared/async_await_error_codes.dart",
+      categories: "",
+      documented: false,
+      platforms: DART2JS_PLATFORM),
+  "_recipe_syntax": const LibraryInfo(
+      "_internal/js_runtime/lib/shared/recipe_syntax.dart",
+      categories: "",
+      documented: false,
+      platforms: DART2JS_PLATFORM),
+  "_metadata": const LibraryInfo("html/html_common/metadata.dart",
+      categories: "", documented: false, platforms: DART2JS_PLATFORM),
+};
+
+/**
+ * Information about a "dart:" library.
+ */
+class LibraryInfo {
+  /**
+   * Path to the library's *.dart file relative to this file.
+   */
+  final String path;
+
+  /**
+   * The categories in which the library can be used encoded as a
+   * comma-separated String.
+   */
+  final String _categories;
+
+  /**
+   * Path to the dart2js library's *.dart file relative to this file
+   * or null if dart2js uses the common library path defined above.
+   * Access using the [#getDart2JsPath()] method.
+   */
+  final String dart2jsPath;
+
+  /**
+   * Path to the dart2js library's patch file relative to this file
+   * or null if no dart2js patch file associated with this library.
+   * Access using the [#getDart2JsPatchPath()] method.
+   */
+  final String dart2jsPatchPath;
+
+  /**
+   * True if this library is documented and should be shown to the user.
+   */
+  final bool documented;
+
+  /**
+   * Bit flags indicating which platforms consume this library.
+   * See [DART2JS_LIBRARY] and [VM_LIBRARY].
+   */
+  final int platforms;
+
+  /**
+   * True if the library contains implementation details for another library.
+   * The implication is that these libraries are less commonly used
+   * and that tools like Dart Editor should not show these libraries
+   * in a list of all libraries unless the user specifically asks the tool to
+   * do so.
+   */
+  final bool implementation;
+
+  /**
+   * States the current maturity of this library.
+   */
+  final Maturity maturity;
+
+  const LibraryInfo(this.path,
+      {String categories: "",
+      this.dart2jsPath,
+      this.dart2jsPatchPath,
+      this.implementation: false,
+      this.documented: true,
+      this.maturity: Maturity.UNSPECIFIED,
+      this.platforms: DART2JS_PLATFORM | VM_PLATFORM})
+      : _categories = categories;
+
+  bool get isDart2jsLibrary => (platforms & DART2JS_PLATFORM) != 0;
+  bool get isVmLibrary => (platforms & VM_PLATFORM) != 0;
+
+  /**
+   * The categories in which the library can be used.
+   *
+   * If no categories are specified, the library is internal and can not be
+   * loaded by user code.
+   */
+  List<Category> get categories {
+    // `"".split(,)` returns [""] not [], so we handle that case separately.
+    if (_categories == "") return const <Category>[];
+    return _categories.split(",").map(parseCategory).toList();
+  }
+
+  bool get isInternal => categories.isEmpty;
+
+  /// The original "categories" String that was passed to the constructor.
+  ///
+  /// Can be used to construct a slightly modified copy of this LibraryInfo.
+  String get categoriesString {
+    return _categories;
+  }
+}
+
+/**
+ * Abstraction to capture the maturity of a library.
+ */
+class Maturity {
+  final int level;
+  final String name;
+  final String description;
+
+  const Maturity(this.level, this.name, this.description);
+
+  String toString() => "$name: $level\n$description\n";
+
+  static const Maturity DEPRECATED = const Maturity(0, "Deprecated",
+      "This library will be remove before next major release.");
+
+  static const Maturity EXPERIMENTAL = const Maturity(
+      1,
+      "Experimental",
+      "This library is experimental and will likely change or be removed\n"
+          "in future versions.");
+
+  static const Maturity UNSTABLE = const Maturity(
+      2,
+      "Unstable",
+      "This library is in still changing and have not yet endured\n"
+          "sufficient real-world testing.\n"
+          "Backwards-compatibility is NOT guaranteed.");
+
+  static const Maturity WEB_STABLE = const Maturity(
+      3,
+      "Web Stable",
+      "This library is tracking the DOM evolution as defined by WC3.\n"
+          "Backwards-compatibility is NOT guaranteed.");
+
+  static const Maturity STABLE = const Maturity(
+      4,
+      "Stable",
+      "The library is stable. API backwards-compatibility is guaranteed.\n"
+          "However implementation details might change.");
+
+  static const Maturity LOCKED = const Maturity(5, "Locked",
+      "This library will not change except when serious bugs are encountered.");
+
+  static const Maturity UNSPECIFIED = const Maturity(-1, "Unspecified",
+      "The maturity for this library has not been specified.");
+}
diff --git a/sdk_nnbd/lib/_internal/sdk_library_metadata/pubspec.yaml b/sdk_nnbd/lib/_internal/sdk_library_metadata/pubspec.yaml
new file mode 100644
index 0000000..08b5518
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/sdk_library_metadata/pubspec.yaml
@@ -0,0 +1,6 @@
+# Note: This package is not meant to be uploaded to pub. This file is used to
+# make it easer to depend on libraries.dart from sdk packages like dart2js.
+name: sdk_library_metadata
+publish_to: none
+environment:
+  sdk: '>=2.0.0 <3.0.0'
diff --git a/sdk_nnbd/lib/async/async.dart b/sdk_nnbd/lib/async/async.dart
new file mode 100644
index 0000000..b3a5dbd
--- /dev/null
+++ b/sdk_nnbd/lib/async/async.dart
@@ -0,0 +1,119 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/**
+ * Support for asynchronous programming,
+ * with classes such as Future and Stream.
+ *
+ * Understanding [Future]s and [Stream]s is a prerequisite for
+ * writing just about any Dart program.
+ *
+ * To use this library in your code:
+ *
+ *     import 'dart:async';
+ *
+ * ## Future
+ *
+ * A Future object represents a computation whose return value
+ * might not yet be available.
+ * The Future returns the value of the computation
+ * when it completes at some time in the future.
+ * Futures are often used for potentially lengthy computations
+ * such as I/O and interaction with users.
+ *
+ * Many methods in the Dart libraries return Futures when
+ * performing tasks. For example, when binding an HttpServer
+ * to a host and port, the `bind()` method returns a Future.
+ *
+ *      HttpServer.bind('127.0.0.1', 4444)
+ *          .then((server) => print('${server.isBroadcast}'))
+ *          .catchError(print);
+ *
+ * [Future.then] registers a callback function that runs
+ * when the Future's operation, in this case the `bind()` method,
+ * completes successfully.
+ * The value returned by the operation
+ * is passed into the callback function.
+ * In this example, the `bind()` method returns the HttpServer
+ * object. The callback function prints one of its properties.
+ * [Future.catchError] registers a callback function that
+ * runs if an error occurs within the Future.
+ *
+ * ## Stream
+ *
+ * A Stream provides an asynchronous sequence of data.
+ * Examples of data sequences include individual events, like mouse clicks,
+ * or sequential chunks of larger data, like multiple byte lists with the
+ * contents of a file
+ * such as mouse clicks, and a stream of byte lists read from a file.
+ * The following example opens a file for reading.
+ * [Stream.listen] registers a callback function that runs
+ * each time more data is available.
+ *
+ *     Stream<List<int>> stream = new File('quotes.txt').openRead();
+ *     stream.transform(utf8.decoder).listen(print);
+ *
+ * The stream emits a sequence of a list of bytes.
+ * The program must interpret the bytes or handle the raw byte data.
+ * Here, the code uses a UTF-8 decoder (provided in the `dart:convert` library)
+ * to convert the sequence of bytes into a sequence
+ * of Dart strings.
+ *
+ * Another common use of streams is for user-generated events
+ * in a web app: The following code listens for mouse clicks on a button.
+ *
+ *     querySelector('#myButton').onClick.listen((_) => print('Click.'));
+ *
+ * ## Other resources
+ *
+ * * The [dart:async section of the library tour][asynchronous-programming]:
+ *   A brief overview of asynchronous programming.
+ *
+ * * [Use Future-Based APIs][futures-tutorial]: A closer look at Futures and
+ *   how to use them to write asynchronous Dart code.
+ *
+ * * [Futures and Error Handling][futures-error-handling]: Everything you
+ *   wanted to know about handling errors and exceptions when working with
+ *   Futures (but were afraid to ask).
+ *
+ * * [The Event Loop and Dart](https://www.dartlang.org/articles/event-loop/):
+ *   Learn how Dart handles the event queue and microtask queue, so you can
+ *   write better asynchronous code with fewer surprises.
+ *
+ * * [test package: Asynchronous Tests][test-readme]: How to test asynchronous
+ *   code.
+ *
+ * [asynchronous-programming]: https://www.dartlang.org/docs/dart-up-and-running/ch03.html#dartasync---asynchronous-programming
+ * [futures-tutorial]: https://www.dartlang.org/docs/tutorials/futures/
+ * [futures-error-handling]: https://www.dartlang.org/articles/futures-and-error-handling/
+ * [test-readme]: https://pub.dartlang.org/packages/test
+ *
+ * {@category Core}
+ */
+library dart.async;
+
+import "dart:collection" show HashMap, IterableBase;
+import "dart:_internal"
+    show
+        CastStream,
+        CastStreamTransformer,
+        EmptyIterator,
+        IterableElementError,
+        printToZone,
+        printToConsole,
+        Since;
+
+part 'async_error.dart';
+part 'broadcast_stream_controller.dart';
+part 'deferred_load.dart';
+part 'future.dart';
+part 'future_impl.dart';
+part 'schedule_microtask.dart';
+part 'stream.dart';
+part 'stream_controller.dart';
+part 'stream_impl.dart';
+part 'stream_pipe.dart';
+part 'stream_transformers.dart';
+part 'timer.dart';
+part 'zone.dart';
diff --git a/sdk_nnbd/lib/async/async_error.dart b/sdk_nnbd/lib/async/async_error.dart
new file mode 100644
index 0000000..1520c54
--- /dev/null
+++ b/sdk_nnbd/lib/async/async_error.dart
@@ -0,0 +1,19 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.async;
+
+_invokeErrorHandler(
+    Function errorHandler, Object error, StackTrace stackTrace) {
+  if (errorHandler is ZoneBinaryCallback<dynamic, Null, Null>) {
+    // Dynamic invocation because we don't know the actual type of the
+    // first argument or the error object, but we should successfully call
+    // the handler if they match up.
+    // TODO(lrn): Should we? Why not the same below for the unary case?
+    return (errorHandler as dynamic)(error, stackTrace);
+  } else {
+    ZoneUnaryCallback unaryErrorHandler = errorHandler;
+    return unaryErrorHandler(error);
+  }
+}
diff --git a/sdk_nnbd/lib/async/async_sources.gni b/sdk_nnbd/lib/async/async_sources.gni
new file mode 100644
index 0000000..3299cd4
--- /dev/null
+++ b/sdk_nnbd/lib/async/async_sources.gni
@@ -0,0 +1,23 @@
+# 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.
+
+# This file contains all sources for the dart:async library.
+async_sdk_sources = [
+  "async.dart",
+
+  # The above file needs to be first as it lists the parts below.
+  "async_error.dart",
+  "broadcast_stream_controller.dart",
+  "deferred_load.dart",
+  "future.dart",
+  "future_impl.dart",
+  "schedule_microtask.dart",
+  "stream.dart",
+  "stream_controller.dart",
+  "stream_impl.dart",
+  "stream_pipe.dart",
+  "stream_transformers.dart",
+  "timer.dart",
+  "zone.dart",
+]
diff --git a/sdk_nnbd/lib/async/broadcast_stream_controller.dart b/sdk_nnbd/lib/async/broadcast_stream_controller.dart
new file mode 100644
index 0000000..32e4582
--- /dev/null
+++ b/sdk_nnbd/lib/async/broadcast_stream_controller.dart
@@ -0,0 +1,510 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.async;
+
+class _BroadcastStream<T> extends _ControllerStream<T> {
+  _BroadcastStream(_StreamControllerLifecycle<T> controller)
+      : super(controller);
+
+  bool get isBroadcast => true;
+}
+
+class _BroadcastSubscription<T> extends _ControllerSubscription<T> {
+  static const int _STATE_EVENT_ID = 1;
+  static const int _STATE_FIRING = 2;
+  static const int _STATE_REMOVE_AFTER_FIRING = 4;
+  // TODO(lrn): Use the _state field on _ControllerSubscription to
+  // also store this state. Requires that the subscription implementation
+  // does not assume that it's use of the state integer is the only use.
+  int _eventState = 0; // Initialized to help dart2js type inference.
+
+  _BroadcastSubscription<T> _next;
+  _BroadcastSubscription<T> _previous;
+
+  _BroadcastSubscription(_StreamControllerLifecycle<T> controller,
+      void onData(T data), Function onError, void onDone(), bool cancelOnError)
+      : super(controller, onData, onError, onDone, cancelOnError) {
+    _next = _previous = this;
+  }
+
+  bool _expectsEvent(int eventId) => (_eventState & _STATE_EVENT_ID) == eventId;
+
+  void _toggleEventId() {
+    _eventState ^= _STATE_EVENT_ID;
+  }
+
+  bool get _isFiring => (_eventState & _STATE_FIRING) != 0;
+
+  void _setRemoveAfterFiring() {
+    assert(_isFiring);
+    _eventState |= _STATE_REMOVE_AFTER_FIRING;
+  }
+
+  bool get _removeAfterFiring =>
+      (_eventState & _STATE_REMOVE_AFTER_FIRING) != 0;
+
+  // The controller._recordPause doesn't do anything for a broadcast controller,
+  // so we don't bother calling it.
+  void _onPause() {}
+
+  // The controller._recordResume doesn't do anything for a broadcast
+  // controller, so we don't bother calling it.
+  void _onResume() {}
+
+  // _onCancel is inherited.
+}
+
+abstract class _BroadcastStreamController<T>
+    implements _StreamControllerBase<T> {
+  static const int _STATE_INITIAL = 0;
+  static const int _STATE_EVENT_ID = 1;
+  static const int _STATE_FIRING = 2;
+  static const int _STATE_CLOSED = 4;
+  static const int _STATE_ADDSTREAM = 8;
+
+  ControllerCallback onListen;
+  ControllerCancelCallback onCancel;
+
+  // State of the controller.
+  int _state;
+
+  // Double-linked list of active listeners.
+  _BroadcastSubscription<T> _firstSubscription;
+  _BroadcastSubscription<T> _lastSubscription;
+
+  // Extra state used during an [addStream] call.
+  _AddStreamState<T> _addStreamState;
+
+  /**
+   * Future returned by [close] and [done].
+   *
+   * The future is completed whenever the done event has been sent to all
+   * relevant listeners.
+   * The relevant listeners are the ones that were listening when [close] was
+   * called. When all of these have been canceled (sending the done event makes
+   * them cancel, but they can also be canceled before sending the event),
+   * this future completes.
+   *
+   * Any attempt to listen after calling [close] will throw, so there won't
+   * be any further listeners.
+   */
+  _Future _doneFuture;
+
+  _BroadcastStreamController(this.onListen, this.onCancel)
+      : _state = _STATE_INITIAL;
+
+  ControllerCallback get onPause {
+    throw new UnsupportedError(
+        "Broadcast stream controllers do not support pause callbacks");
+  }
+
+  void set onPause(void onPauseHandler()) {
+    throw new UnsupportedError(
+        "Broadcast stream controllers do not support pause callbacks");
+  }
+
+  ControllerCallback get onResume {
+    throw new UnsupportedError(
+        "Broadcast stream controllers do not support pause callbacks");
+  }
+
+  void set onResume(void onResumeHandler()) {
+    throw new UnsupportedError(
+        "Broadcast stream controllers do not support pause callbacks");
+  }
+
+  // StreamController interface.
+
+  Stream<T> get stream => new _BroadcastStream<T>(this);
+
+  StreamSink<T> get sink => new _StreamSinkWrapper<T>(this);
+
+  bool get isClosed => (_state & _STATE_CLOSED) != 0;
+
+  /**
+   * A broadcast controller is never paused.
+   *
+   * Each receiving stream may be paused individually, and they handle their
+   * own buffering.
+   */
+  bool get isPaused => false;
+
+  /** Whether there are currently one or more subscribers. */
+  bool get hasListener => !_isEmpty;
+
+  /**
+   * Test whether the stream has exactly one listener.
+   *
+   * Assumes that the stream has a listener (not [_isEmpty]).
+   */
+  bool get _hasOneListener {
+    assert(!_isEmpty);
+    return identical(_firstSubscription, _lastSubscription);
+  }
+
+  /** Whether an event is being fired (sent to some, but not all, listeners). */
+  bool get _isFiring => (_state & _STATE_FIRING) != 0;
+
+  bool get _isAddingStream => (_state & _STATE_ADDSTREAM) != 0;
+
+  bool get _mayAddEvent => (_state < _STATE_CLOSED);
+
+  _Future _ensureDoneFuture() {
+    if (_doneFuture != null) return _doneFuture;
+    return _doneFuture = new _Future();
+  }
+
+  // Linked list helpers
+
+  bool get _isEmpty => _firstSubscription == null;
+
+  /** Adds subscription to linked list of active listeners. */
+  void _addListener(_BroadcastSubscription<T> subscription) {
+    assert(identical(subscription._next, subscription));
+    subscription._eventState = (_state & _STATE_EVENT_ID);
+    // Insert in linked list as last subscription.
+    _BroadcastSubscription<T> oldLast = _lastSubscription;
+    _lastSubscription = subscription;
+    subscription._next = null;
+    subscription._previous = oldLast;
+    if (oldLast == null) {
+      _firstSubscription = subscription;
+    } else {
+      oldLast._next = subscription;
+    }
+  }
+
+  void _removeListener(_BroadcastSubscription<T> subscription) {
+    assert(identical(subscription._controller, this));
+    assert(!identical(subscription._next, subscription));
+    _BroadcastSubscription<T> previous = subscription._previous;
+    _BroadcastSubscription<T> next = subscription._next;
+    if (previous == null) {
+      // This was the first subscription.
+      _firstSubscription = next;
+    } else {
+      previous._next = next;
+    }
+    if (next == null) {
+      // This was the last subscription.
+      _lastSubscription = previous;
+    } else {
+      next._previous = previous;
+    }
+
+    subscription._next = subscription._previous = subscription;
+  }
+
+  // _StreamControllerLifecycle interface.
+
+  StreamSubscription<T> _subscribe(void onData(T data), Function onError,
+      void onDone(), bool cancelOnError) {
+    if (isClosed) {
+      onDone ??= _nullDoneHandler;
+      return new _DoneStreamSubscription<T>(onDone);
+    }
+    StreamSubscription<T> subscription = new _BroadcastSubscription<T>(
+        this, onData, onError, onDone, cancelOnError);
+    _addListener(subscription);
+    if (identical(_firstSubscription, _lastSubscription)) {
+      // Only one listener, so it must be the first listener.
+      _runGuarded(onListen);
+    }
+    return subscription;
+  }
+
+  Future _recordCancel(StreamSubscription<T> sub) {
+    _BroadcastSubscription<T> subscription = sub;
+    // If already removed by the stream, don't remove it again.
+    if (identical(subscription._next, subscription)) return null;
+    if (subscription._isFiring) {
+      subscription._setRemoveAfterFiring();
+    } else {
+      _removeListener(subscription);
+      // If we are currently firing an event, the empty-check is performed at
+      // the end of the listener loop instead of here.
+      if (!_isFiring && _isEmpty) {
+        _callOnCancel();
+      }
+    }
+    return null;
+  }
+
+  void _recordPause(StreamSubscription<T> subscription) {}
+  void _recordResume(StreamSubscription<T> subscription) {}
+
+  // EventSink interface.
+
+  Error _addEventError() {
+    if (isClosed) {
+      return new StateError("Cannot add new events after calling close");
+    }
+    assert(_isAddingStream);
+    return new StateError("Cannot add new events while doing an addStream");
+  }
+
+  void add(T data) {
+    if (!_mayAddEvent) throw _addEventError();
+    _sendData(data);
+  }
+
+  void addError(Object error, [StackTrace stackTrace]) {
+    error = _nonNullError(error);
+    if (!_mayAddEvent) throw _addEventError();
+    AsyncError replacement = Zone.current.errorCallback(error, stackTrace);
+    if (replacement != null) {
+      error = _nonNullError(replacement.error);
+      stackTrace = replacement.stackTrace;
+    }
+    _sendError(error, stackTrace);
+  }
+
+  Future close() {
+    if (isClosed) {
+      assert(_doneFuture != null);
+      return _doneFuture;
+    }
+    if (!_mayAddEvent) throw _addEventError();
+    _state |= _STATE_CLOSED;
+    Future doneFuture = _ensureDoneFuture();
+    _sendDone();
+    return doneFuture;
+  }
+
+  Future get done => _ensureDoneFuture();
+
+  Future addStream(Stream<T> stream, {bool cancelOnError}) {
+    if (!_mayAddEvent) throw _addEventError();
+    _state |= _STATE_ADDSTREAM;
+    _addStreamState = new _AddStreamState(this, stream, cancelOnError ?? false);
+    return _addStreamState.addStreamFuture;
+  }
+
+  // _EventSink interface, called from AddStreamState.
+  void _add(T data) {
+    _sendData(data);
+  }
+
+  void _addError(Object error, StackTrace stackTrace) {
+    _sendError(error, stackTrace);
+  }
+
+  void _close() {
+    assert(_isAddingStream);
+    _AddStreamState addState = _addStreamState;
+    _addStreamState = null;
+    _state &= ~_STATE_ADDSTREAM;
+    addState.complete();
+  }
+
+  // Event handling.
+  void _forEachListener(
+      void action(_BufferingStreamSubscription<T> subscription)) {
+    if (_isFiring) {
+      throw new StateError(
+          "Cannot fire new event. Controller is already firing an event");
+    }
+    if (_isEmpty) return;
+
+    // Get event id of this event.
+    int id = (_state & _STATE_EVENT_ID);
+    // Start firing (set the _STATE_FIRING bit). We don't do [onCancel]
+    // callbacks while firing, and we prevent reentrancy of this function.
+    //
+    // Set [_state]'s event id to the next event's id.
+    // Any listeners added while firing this event will expect the next event,
+    // not this one, and won't get notified.
+    _state ^= _STATE_EVENT_ID | _STATE_FIRING;
+    _BroadcastSubscription<T> subscription = _firstSubscription;
+    while (subscription != null) {
+      if (subscription._expectsEvent(id)) {
+        subscription._eventState |= _BroadcastSubscription._STATE_FIRING;
+        action(subscription);
+        subscription._toggleEventId();
+        _BroadcastSubscription<T> next = subscription._next;
+        if (subscription._removeAfterFiring) {
+          _removeListener(subscription);
+        }
+        subscription._eventState &= ~_BroadcastSubscription._STATE_FIRING;
+        subscription = next;
+      } else {
+        subscription = subscription._next;
+      }
+    }
+    _state &= ~_STATE_FIRING;
+
+    if (_isEmpty) {
+      _callOnCancel();
+    }
+  }
+
+  void _callOnCancel() {
+    assert(_isEmpty);
+    if (isClosed && _doneFuture._mayComplete) {
+      // When closed, _doneFuture is not null.
+      _doneFuture._asyncComplete(null);
+    }
+    _runGuarded(onCancel);
+  }
+}
+
+class _SyncBroadcastStreamController<T> extends _BroadcastStreamController<T>
+    implements SynchronousStreamController<T> {
+  _SyncBroadcastStreamController(void onListen(), void onCancel())
+      : super(onListen, onCancel);
+
+  // EventDispatch interface.
+
+  bool get _mayAddEvent => super._mayAddEvent && !_isFiring;
+
+  _addEventError() {
+    if (_isFiring) {
+      return new StateError(
+          "Cannot fire new event. Controller is already firing an event");
+    }
+    return super._addEventError();
+  }
+
+  void _sendData(T data) {
+    if (_isEmpty) return;
+    if (_hasOneListener) {
+      _state |= _BroadcastStreamController._STATE_FIRING;
+      _BroadcastSubscription<T> subscription = _firstSubscription;
+      subscription._add(data);
+      _state &= ~_BroadcastStreamController._STATE_FIRING;
+      if (_isEmpty) {
+        _callOnCancel();
+      }
+      return;
+    }
+    _forEachListener((_BufferingStreamSubscription<T> subscription) {
+      subscription._add(data);
+    });
+  }
+
+  void _sendError(Object error, StackTrace stackTrace) {
+    if (_isEmpty) return;
+    _forEachListener((_BufferingStreamSubscription<T> subscription) {
+      subscription._addError(error, stackTrace);
+    });
+  }
+
+  void _sendDone() {
+    if (!_isEmpty) {
+      _forEachListener((_BufferingStreamSubscription<T> subscription) {
+        subscription._close();
+      });
+    } else {
+      assert(_doneFuture != null);
+      assert(_doneFuture._mayComplete);
+      _doneFuture._asyncComplete(null);
+    }
+  }
+}
+
+class _AsyncBroadcastStreamController<T> extends _BroadcastStreamController<T> {
+  _AsyncBroadcastStreamController(void onListen(), void onCancel())
+      : super(onListen, onCancel);
+
+  // EventDispatch interface.
+
+  void _sendData(T data) {
+    for (_BroadcastSubscription<T> subscription = _firstSubscription;
+        subscription != null;
+        subscription = subscription._next) {
+      subscription._addPending(new _DelayedData<T>(data));
+    }
+  }
+
+  void _sendError(Object error, StackTrace stackTrace) {
+    for (_BroadcastSubscription<T> subscription = _firstSubscription;
+        subscription != null;
+        subscription = subscription._next) {
+      subscription._addPending(new _DelayedError(error, stackTrace));
+    }
+  }
+
+  void _sendDone() {
+    if (!_isEmpty) {
+      for (_BroadcastSubscription<T> subscription = _firstSubscription;
+          subscription != null;
+          subscription = subscription._next) {
+        subscription._addPending(const _DelayedDone());
+      }
+    } else {
+      assert(_doneFuture != null);
+      assert(_doneFuture._mayComplete);
+      _doneFuture._asyncComplete(null);
+    }
+  }
+}
+
+/**
+ * Stream controller that is used by [Stream.asBroadcastStream].
+ *
+ * This stream controller allows incoming events while it is firing
+ * other events. This is handled by delaying the events until the
+ * current event is done firing, and then fire the pending events.
+ *
+ * This class extends [_SyncBroadcastStreamController]. Events of
+ * an "asBroadcastStream" stream are always initiated by events
+ * on another stream, and it is fine to forward them synchronously.
+ */
+class _AsBroadcastStreamController<T> extends _SyncBroadcastStreamController<T>
+    implements _EventDispatch<T> {
+  _StreamImplEvents<T> _pending;
+
+  _AsBroadcastStreamController(void onListen(), void onCancel())
+      : super(onListen, onCancel);
+
+  bool get _hasPending => _pending != null && !_pending.isEmpty;
+
+  void _addPendingEvent(_DelayedEvent event) {
+    _pending ??= new _StreamImplEvents<T>();
+    _pending.add(event);
+  }
+
+  void add(T data) {
+    if (!isClosed && _isFiring) {
+      _addPendingEvent(new _DelayedData<T>(data));
+      return;
+    }
+    super.add(data);
+    while (_hasPending) {
+      _pending.handleNext(this);
+    }
+  }
+
+  void addError(Object error, [StackTrace stackTrace]) {
+    if (!isClosed && _isFiring) {
+      _addPendingEvent(new _DelayedError(error, stackTrace));
+      return;
+    }
+    if (!_mayAddEvent) throw _addEventError();
+    _sendError(error, stackTrace);
+    while (_hasPending) {
+      _pending.handleNext(this);
+    }
+  }
+
+  Future close() {
+    if (!isClosed && _isFiring) {
+      _addPendingEvent(const _DelayedDone());
+      _state |= _BroadcastStreamController._STATE_CLOSED;
+      return super.done;
+    }
+    Future result = super.close();
+    assert(!_hasPending);
+    return result;
+  }
+
+  void _callOnCancel() {
+    if (_hasPending) {
+      _pending.clear();
+      _pending = null;
+    }
+    super._callOnCancel();
+  }
+}
diff --git a/sdk_nnbd/lib/async/deferred_load.dart b/sdk_nnbd/lib/async/deferred_load.dart
new file mode 100644
index 0000000..f83d4b8
--- /dev/null
+++ b/sdk_nnbd/lib/async/deferred_load.dart
@@ -0,0 +1,36 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.async;
+
+/**
+ * Indicates that loading of [libraryName] is deferred.
+ *
+ * This class is obsolete. Instead use the syntax:
+ * import "library.dart" deferred as prefix;
+ */
+@Deprecated("Dart sdk v. 1.8")
+class DeferredLibrary {
+  final String libraryName;
+  final String uri;
+
+  const DeferredLibrary(this.libraryName, {this.uri});
+
+  /**
+   * Ensure that [libraryName] has been loaded.
+   *
+   * If the library fails to load, the Future will complete with a
+   * DeferredLoadException.
+   */
+  external Future<Null> load();
+}
+
+/**
+ * Thrown when a deferred library fails to load.
+ */
+class DeferredLoadException implements Exception {
+  DeferredLoadException(this._s);
+  String toString() => "DeferredLoadException: '$_s'";
+  final String _s;
+}
diff --git a/sdk_nnbd/lib/async/future.dart b/sdk_nnbd/lib/async/future.dart
new file mode 100644
index 0000000..b9d22c1
--- /dev/null
+++ b/sdk_nnbd/lib/async/future.dart
@@ -0,0 +1,931 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.async;
+
+/// A type representing values that are either `Future<T>` or `T`.
+///
+/// This class declaration is a public stand-in for an internal
+/// future-or-value generic type. References to this class are resolved to the
+/// internal type.
+///
+/// It is a compile-time error for any class to extend, mix in or implement
+/// `FutureOr`.
+///
+/// Note: the `FutureOr<T>` type is interpreted as `dynamic` in non strong-mode.
+///
+/// # Examples
+/// ``` dart
+/// // The `Future<T>.then` function takes a callback [f] that returns either
+/// // an `S` or a `Future<S>`.
+/// Future<S> then<S>(FutureOr<S> f(T x), ...);
+///
+/// // `Completer<T>.complete` takes either a `T` or `Future<T>`.
+/// void complete(FutureOr<T> value);
+/// ```
+///
+/// # Advanced
+/// The `FutureOr<int>` type is actually the "type union" of the types `int` and
+/// `Future<int>`. This type union is defined in such a way that
+/// `FutureOr<Object>` is both a super- and sub-type of `Object` (sub-type
+/// because `Object` is one of the types of the union, super-type because
+/// `Object` is a super-type of both of the types of the union). Together it
+/// means that `FutureOr<Object>` is equivalent to `Object`.
+///
+/// As a corollary, `FutureOr<Object>` is equivalent to
+/// `FutureOr<FutureOr<Object>>`, `FutureOr<Future<Object>>` is equivalent to
+/// `Future<Object>`.
+abstract class FutureOr<T> {
+  // Private generative constructor, so that it is not subclassable, mixable, or
+  // instantiable.
+  FutureOr._() {
+    throw new UnsupportedError("FutureOr can't be instantiated");
+  }
+}
+
+/**
+ * An object representing a delayed computation.
+ *
+ * A [Future] is used to represent a potential value, or error,
+ * that will be available at some time in the future.
+ * Receivers of a [Future] can register callbacks
+ * that handle the value or error once it is available.
+ * For example:
+ *
+ *     Future<int> future = getFuture();
+ *     future.then((value) => handleValue(value))
+ *           .catchError((error) => handleError(error));
+ *
+ * A [Future] can be completed in two ways:
+ * with a value ("the future succeeds")
+ * or with an error ("the future fails").
+ * Users can install callbacks for each case.
+ *
+ * In some cases we say that a future is completed with another future.
+ * This is a short way of stating that the future is completed in the same way,
+ * with the same value or error,
+ * as the other future once that completes.
+ * Whenever a function in the core library may complete a future
+ * (for example [Completer.complete] or [new Future.value]),
+ * then it also accepts another future and does this work for the developer.
+ *
+ * The result of registering a pair of callbacks is a new Future (the
+ * "successor") which in turn is completed with the result of invoking the
+ * corresponding callback.
+ * The successor is completed with an error if the invoked callback throws.
+ * For example:
+ * ```
+ * Future<int> successor = future.then((int value) {
+ *     // Invoked when the future is completed with a value.
+ *     return 42;  // The successor is completed with the value 42.
+ *   },
+ *   onError: (e) {
+ *     // Invoked when the future is completed with an error.
+ *     if (canHandle(e)) {
+ *       return 499;  // The successor is completed with the value 499.
+ *     } else {
+ *       throw e;  // The successor is completed with the error e.
+ *     }
+ *   });
+ * ```
+ *
+ * If a future does not have a successor when it completes with an error,
+ * it forwards the error message to the global error-handler.
+ * This behavior makes sure that no error is silently dropped.
+ * However, it also means that error handlers should be installed early,
+ * so that they are present as soon as a future is completed with an error.
+ * The following example demonstrates this potential bug:
+ * ```
+ * var future = getFuture();
+ * new Timer(new Duration(milliseconds: 5), () {
+ *   // The error-handler is not attached until 5 ms after the future has
+ *   // been received. If the future fails before that, the error is
+ *   // forwarded to the global error-handler, even though there is code
+ *   // (just below) to eventually handle the error.
+ *   future.then((value) { useValue(value); },
+ *               onError: (e) { handleError(e); });
+ * });
+ * ```
+ *
+ * When registering callbacks, it's often more readable to register the two
+ * callbacks separately, by first using [then] with one argument
+ * (the value handler) and using a second [catchError] for handling errors.
+ * Each of these will forward the result that they don't handle
+ * to their successors, and together they handle both value and error result.
+ * It also has the additional benefit of the [catchError] handling errors in the
+ * [then] value callback too.
+ * Using sequential handlers instead of parallel ones often leads to code that
+ * is easier to reason about.
+ * It also makes asynchronous code very similar to synchronous code:
+ * ```
+ * // Synchronous code.
+ * try {
+ *   int value = foo();
+ *   return bar(value);
+ * } catch (e) {
+ *   return 499;
+ * }
+ * ```
+ *
+ * Equivalent asynchronous code, based on futures:
+ * ```
+ * Future<int> future = new Future(foo);  // Result of foo() as a future.
+ * future.then((int value) => bar(value))
+ *       .catchError((e) => 499);
+ * ```
+ *
+ * Similar to the synchronous code, the error handler (registered with
+ * [catchError]) is handling any errors thrown by either `foo` or `bar`.
+ * If the error-handler had been registered as the `onError` parameter of
+ * the `then` call, it would not catch errors from the `bar` call.
+ *
+ * Futures can have more than one callback-pair registered. Each successor is
+ * treated independently and is handled as if it was the only successor.
+ *
+ * A future may also fail to ever complete. In that case, no callbacks are
+ * called.
+ */
+abstract class Future<T> {
+  /// A `Future<Null>` completed with `null`.
+  static final _Future<Null> _nullFuture =
+      new _Future<Null>.zoneValue(null, Zone.root);
+
+  /// A `Future<bool>` completed with `false`.
+  static final _Future<bool> _falseFuture =
+      new _Future<bool>.zoneValue(false, Zone.root);
+
+  /**
+   * Creates a future containing the result of calling [computation]
+   * asynchronously with [Timer.run].
+   *
+   * If the result of executing [computation] throws, the returned future is
+   * completed with the error.
+   *
+   * If the returned value is itself a [Future], completion of
+   * the created future will wait until the returned future completes,
+   * and will then complete with the same result.
+   *
+   * If a non-future value is returned, the returned future is completed
+   * with that value.
+   */
+  factory Future(FutureOr<T> computation()) {
+    _Future<T> result = new _Future<T>();
+    Timer.run(() {
+      try {
+        result._complete(computation());
+      } catch (e, s) {
+        _completeWithErrorCallback(result, e, s);
+      }
+    });
+    return result;
+  }
+
+  /**
+   * Creates a future containing the result of calling [computation]
+   * asynchronously with [scheduleMicrotask].
+   *
+   * If executing [computation] throws,
+   * the returned future is completed with the thrown error.
+   *
+   * If calling [computation] returns a [Future], completion of
+   * the created future will wait until the returned future completes,
+   * and will then complete with the same result.
+   *
+   * If calling [computation] returns a non-future value,
+   * the returned future is completed with that value.
+   */
+  factory Future.microtask(FutureOr<T> computation()) {
+    _Future<T> result = new _Future<T>();
+    scheduleMicrotask(() {
+      try {
+        result._complete(computation());
+      } catch (e, s) {
+        _completeWithErrorCallback(result, e, s);
+      }
+    });
+    return result;
+  }
+
+  /**
+   * Returns a future containing the result of immediately calling
+   * [computation].
+   *
+   * If calling [computation] throws, the returned future is completed with the
+   * error.
+   *
+   * If calling [computation] returns a `Future<T>`, that future is returned.
+   *
+   * If calling [computation] returns a non-future value,
+   * a future is returned which has been completed with that value.
+   */
+  factory Future.sync(FutureOr<T> computation()) {
+    try {
+      var result = computation();
+      if (result is Future<T>) {
+        return result;
+      } else {
+        return new _Future<T>.value(result);
+      }
+    } catch (error, stackTrace) {
+      var future = new _Future<T>();
+      AsyncError replacement = Zone.current.errorCallback(error, stackTrace);
+      if (replacement != null) {
+        future._asyncCompleteError(
+            _nonNullError(replacement.error), replacement.stackTrace);
+      } else {
+        future._asyncCompleteError(error, stackTrace);
+      }
+      return future;
+    }
+  }
+
+  /**
+   * Creates a future completed with [value].
+   *
+   * If [value] is a future, the created future waits for the
+   * [value] future to complete, and then completes with the same result.
+   * Since a [value] future can complete with an error, so can the future
+   * created by [Future.value], even if the name suggests otherwise.
+   *
+   * If [value] is not a [Future], the created future is completed
+   * with the [value] value,
+   * equivalently to `new Future<T>.sync(() => value)`.
+   *
+   * Use [Completer] to create a future and complete it later.
+   */
+  factory Future.value([FutureOr<T> value]) {
+    return new _Future<T>.immediate(value);
+  }
+
+  /**
+   * Creates a future that completes with an error.
+   *
+   * The created future will be completed with an error in a future microtask.
+   * This allows enough time for someone to add an error handler on the future.
+   * If an error handler isn't added before the future completes, the error
+   * will be considered unhandled.
+   *
+   * If [error] is `null`, it is replaced by a [NullThrownError].
+   *
+   * Use [Completer] to create a future and complete it later.
+   */
+  factory Future.error(Object error, [StackTrace stackTrace]) {
+    error = _nonNullError(error);
+    if (!identical(Zone.current, _rootZone)) {
+      AsyncError replacement = Zone.current.errorCallback(error, stackTrace);
+      if (replacement != null) {
+        error = _nonNullError(replacement.error);
+        stackTrace = replacement.stackTrace;
+      }
+    }
+    return new _Future<T>.immediateError(error, stackTrace);
+  }
+
+  /**
+   * Creates a future that runs its computation after a delay.
+   *
+   * The [computation] will be executed after the given [duration] has passed,
+   * and the future is completed with the result of the computation.
+   *
+   * If [computation] returns a future,
+   * the future returned by this constructor will complete with the value or
+   * error of that future.
+   *
+   * If the duration is 0 or less,
+   * it completes no sooner than in the next event-loop iteration,
+   * after all microtasks have run.
+   *
+   * If [computation] is omitted,
+   * it will be treated as if [computation] was `() => null`,
+   * and the future will eventually complete with the `null` value.
+   *
+   * If calling [computation] throws, the created future will complete with the
+   * error.
+   *
+   * See also [Completer] for a way to create and complete a future at a
+   * later time that isn't necessarily after a known fixed duration.
+   */
+  factory Future.delayed(Duration duration, [FutureOr<T> computation()]) {
+    _Future<T> result = new _Future<T>();
+    new Timer(duration, () {
+      if (computation == null) {
+        result._complete(null);
+      } else {
+        try {
+          result._complete(computation());
+        } catch (e, s) {
+          _completeWithErrorCallback(result, e, s);
+        }
+      }
+    });
+    return result;
+  }
+
+  /**
+   * Waits for multiple futures to complete and collects their results.
+   *
+   * Returns a future which will complete once all the provided futures
+   * have completed, either with their results, or with an error if any
+   * of the provided futures fail.
+   *
+   * The value of the returned future will be a list of all the values that
+   * were produced in the order that the futures are provided by iterating
+   * [futures].
+   *
+   * If any future completes with an error,
+   * then the returned future completes with that error.
+   * If further futures also complete with errors, those errors are discarded.
+   *
+   * If `eagerError` is true, the returned future completes with an error
+   * immediately on the first error from one of the futures. Otherwise all
+   * futures must complete before the returned future is completed (still with
+   * the first error; the remaining errors are silently dropped).
+   *
+   * In the case of an error, [cleanUp] (if provided), is invoked on any
+   * non-null result of successful futures.
+   * This makes it possible to `cleanUp` resources that would otherwise be
+   * lost (since the returned future does not provide access to these values).
+   * The [cleanUp] function is unused if there is no error.
+   *
+   * The call to [cleanUp] should not throw. If it does, the error will be an
+   * uncaught asynchronous error.
+   */
+  static Future<List<T>> wait<T>(Iterable<Future<T>> futures,
+      {bool eagerError: false, void cleanUp(T successValue)}) {
+    final _Future<List<T>> result = new _Future<List<T>>();
+    List<T> values; // Collects the values. Set to null on error.
+    int remaining = 0; // How many futures are we waiting for.
+    var error; // The first error from a future.
+    StackTrace stackTrace; // The stackTrace that came with the error.
+
+    // Handle an error from any of the futures.
+    // TODO(jmesserly): use `void` return type once it can be inferred for the
+    // `then` call below.
+    handleError(theError, StackTrace theStackTrace) {
+      remaining--;
+      if (values != null) {
+        if (cleanUp != null) {
+          for (var value in values) {
+            if (value != null) {
+              // Ensure errors from cleanUp are uncaught.
+              new Future.sync(() {
+                cleanUp(value);
+              });
+            }
+          }
+        }
+        values = null;
+        if (remaining == 0 || eagerError) {
+          result._completeError(theError, theStackTrace);
+        } else {
+          error = theError;
+          stackTrace = theStackTrace;
+        }
+      } else if (remaining == 0 && !eagerError) {
+        result._completeError(error, stackTrace);
+      }
+    }
+
+    try {
+      // As each future completes, put its value into the corresponding
+      // position in the list of values.
+      for (var future in futures) {
+        int pos = remaining;
+        future.then((T value) {
+          remaining--;
+          if (values != null) {
+            values[pos] = value;
+            if (remaining == 0) {
+              result._completeWithValue(values);
+            }
+          } else {
+            if (cleanUp != null && value != null) {
+              // Ensure errors from cleanUp are uncaught.
+              new Future.sync(() {
+                cleanUp(value);
+              });
+            }
+            if (remaining == 0 && !eagerError) {
+              result._completeError(error, stackTrace);
+            }
+          }
+        }, onError: handleError);
+        // Increment the 'remaining' after the call to 'then'.
+        // If that call throws, we don't expect any future callback from
+        // the future, and we also don't increment remaining.
+        remaining++;
+      }
+      if (remaining == 0) {
+        return new Future.value(const []);
+      }
+      values = new List<T>(remaining);
+    } catch (e, st) {
+      // The error must have been thrown while iterating over the futures
+      // list, or while installing a callback handler on the future.
+      if (remaining == 0 || eagerError) {
+        // Throw a new Future.error.
+        // Don't just call `result._completeError` since that would propagate
+        // the error too eagerly, not giving the callers time to install
+        // error handlers.
+        // Also, don't use `_asyncCompleteError` since that one doesn't give
+        // zones the chance to intercept the error.
+        return new Future.error(e, st);
+      } else {
+        // Don't allocate a list for values, thus indicating that there was an
+        // error.
+        // Set error to the caught exception.
+        error = e;
+        stackTrace = st;
+      }
+    }
+    return result;
+  }
+
+  /**
+   * Returns the result of the first future in [futures] to complete.
+   *
+   * The returned future is completed with the result of the first
+   * future in [futures] to report that it is complete,
+   * whether it's with a value or an error.
+   * The results of all the other futures are discarded.
+   *
+   * If [futures] is empty, or if none of its futures complete,
+   * the returned future never completes.
+   */
+  static Future<T> any<T>(Iterable<Future<T>> futures) {
+    var completer = new Completer<T>.sync();
+    var onValue = (T value) {
+      if (!completer.isCompleted) completer.complete(value);
+    };
+    var onError = (error, StackTrace stack) {
+      if (!completer.isCompleted) completer.completeError(error, stack);
+    };
+    for (var future in futures) {
+      future.then(onValue, onError: onError);
+    }
+    return completer.future;
+  }
+
+  /**
+   * Performs an action for each element of the iterable, in turn.
+   *
+   * The [action] may be either synchronous or asynchronous.
+   *
+   * Calls [action] with each element in [elements] in order.
+   * If the call to [action] returns a `Future<T>`, the iteration waits
+   * until the future is completed before continuing with the next element.
+   *
+   * Returns a [Future] that completes with `null` when all elements have been
+   * processed.
+   *
+   * Non-[Future] return values, and completion-values of returned [Future]s,
+   * are discarded.
+   *
+   * Any error from [action], synchronous or asynchronous,
+   * will stop the iteration and be reported in the returned [Future].
+   */
+  static Future forEach<T>(Iterable<T> elements, FutureOr action(T element)) {
+    var iterator = elements.iterator;
+    return doWhile(() {
+      if (!iterator.moveNext()) return false;
+      var result = action(iterator.current);
+      if (result is Future) return result.then(_kTrue);
+      return true;
+    });
+  }
+
+  // Constant `true` function, used as callback by [forEach].
+  static bool _kTrue(_) => true;
+
+  /**
+   * Performs an operation repeatedly until it returns `false`.
+   *
+   * The operation, [action], may be either synchronous or asynchronous.
+   *
+   * The operation is called repeatedly as long as it returns either the [bool]
+   * value `true` or a `Future<bool>` which completes with the value `true`.
+   *
+   * If a call to [action] returns `false` or a [Future] that completes to
+   * `false`, iteration ends and the future returned by [doWhile] is completed
+   * with a `null` value.
+   *
+   * If a call to [action] throws or a future returned by [action] completes
+   * with an error, iteration ends and the future returned by [doWhile]
+   * completes with the same error.
+   *
+   * Calls to [action] may happen at any time,
+   * including immediately after calling `doWhile`.
+   * The only restriction is a new call to [action] won't happen before
+   * the previous call has returned, and if it returned a `Future<bool>`, not
+   * until that future has completed.
+   */
+  static Future doWhile(FutureOr<bool> action()) {
+    _Future doneSignal = new _Future();
+    void Function(bool) nextIteration;
+    // Bind this callback explicitly so that each iteration isn't bound in the
+    // context of all the previous iterations' callbacks.
+    // This avoids, e.g., deeply nested stack traces from the stack trace
+    // package.
+    nextIteration = Zone.current.bindUnaryCallbackGuarded((bool keepGoing) {
+      while (keepGoing) {
+        FutureOr<bool> result;
+        try {
+          result = action();
+        } catch (error, stackTrace) {
+          // Cannot use _completeWithErrorCallback because it completes
+          // the future synchronously.
+          _asyncCompleteWithErrorCallback(doneSignal, error, stackTrace);
+          return;
+        }
+        if (result is Future<bool>) {
+          result.then(nextIteration, onError: doneSignal._completeError);
+          return;
+        }
+        keepGoing = result;
+      }
+      doneSignal._complete(null);
+    });
+    nextIteration(true);
+    return doneSignal;
+  }
+
+  /**
+   * Register callbacks to be called when this future completes.
+   *
+   * When this future completes with a value,
+   * the [onValue] callback will be called with that value.
+   * If this future is already completed, the callback will not be called
+   * immediately, but will be scheduled in a later microtask.
+   *
+   * If [onError] is provided, and this future completes with an error,
+   * the `onError` callback is called with that error and its stack trace.
+   * The `onError` callback must accept either one argument or two arguments
+   * where the latter is a [StackTrace].
+   * If `onError` accepts two arguments,
+   * it is called with both the error and the stack trace,
+   * otherwise it is called with just the error object.
+   * The `onError` callback must return a value or future that can be used
+   * to complete the returned future, so it must be something assignable to
+   * `FutureOr<R>`.
+   *
+   * Returns a new [Future]
+   * which is completed with the result of the call to `onValue`
+   * (if this future completes with a value)
+   * or to `onError` (if this future completes with an error).
+   *
+   * If the invoked callback throws,
+   * the returned future is completed with the thrown error
+   * and a stack trace for the error.
+   * In the case of `onError`,
+   * if the exception thrown is `identical` to the error argument to `onError`,
+   * the throw is considered a rethrow,
+   * and the original stack trace is used instead.
+   *
+   * If the callback returns a [Future],
+   * the future returned by `then` will be completed with
+   * the same result as the future returned by the callback.
+   *
+   * If [onError] is not given, and this future completes with an error,
+   * the error is forwarded directly to the returned future.
+   *
+   * In most cases, it is more readable to use [catchError] separately, possibly
+   * with a `test` parameter, instead of handling both value and error in a
+   * single [then] call.
+   *
+   * Note that futures don't delay reporting of errors until listeners are
+   * added. If the first `then` or `catchError` call happens after this future
+   * has completed with an error then the error is reported as unhandled error.
+   * See the description on [Future].
+   */
+  Future<R> then<R>(FutureOr<R> onValue(T value), {Function onError});
+
+  /**
+   * Handles errors emitted by this [Future].
+   *
+   * This is the asynchronous equivalent of a "catch" block.
+   *
+   * Returns a new [Future] that will be completed with either the result of
+   * this future or the result of calling the `onError` callback.
+   *
+   * If this future completes with a value,
+   * the returned future completes with the same value.
+   *
+   * If this future completes with an error,
+   * then [test] is first called with the error value.
+   *
+   * If `test` returns false, the exception is not handled by this `catchError`,
+   * and the returned future completes with the same error and stack trace
+   * as this future.
+   *
+   * If `test` returns `true`,
+   * [onError] is called with the error and possibly stack trace,
+   * and the returned future is completed with the result of this call
+   * in exactly the same way as for [then]'s `onError`.
+   *
+   * If `test` is omitted, it defaults to a function that always returns true.
+   * The `test` function should not throw, but if it does, it is handled as
+   * if the `onError` function had thrown.
+   *
+   * Note that futures don't delay reporting of errors until listeners are
+   * added. If the first `catchError` (or `then`) call happens after this future
+   * has completed with an error then the error is reported as unhandled error.
+   * See the description on [Future].
+   */
+  // The `Function` below stands for one of two types:
+  // - (dynamic) -> FutureOr<T>
+  // - (dynamic, StackTrace) -> FutureOr<T>
+  // Given that there is a `test` function that is usually used to do an
+  // `isCheck` we should also expect functions that take a specific argument.
+  // Note: making `catchError` return a `Future<T>` in non-strong mode could be
+  // a breaking change.
+  Future<T> catchError(Function onError, {bool test(Object error)});
+
+  /**
+   * Registers a function to be called when this future completes.
+   *
+   * The [action] function is called when this future completes, whether it
+   * does so with a value or with an error.
+   *
+   * This is the asynchronous equivalent of a "finally" block.
+   *
+   * The future returned by this call, `f`, will complete the same way
+   * as this future unless an error occurs in the [action] call, or in
+   * a [Future] returned by the [action] call. If the call to [action]
+   * does not return a future, its return value is ignored.
+   *
+   * If the call to [action] throws, then `f` is completed with the
+   * thrown error.
+   *
+   * If the call to [action] returns a [Future], `f2`, then completion of
+   * `f` is delayed until `f2` completes. If `f2` completes with
+   * an error, that will be the result of `f` too. The value of `f2` is always
+   * ignored.
+   *
+   * This method is equivalent to:
+   *
+   *     Future<T> whenComplete(action()) {
+   *       return this.then((v) {
+   *         var f2 = action();
+   *         if (f2 is Future) return f2.then((_) => v);
+   *         return v
+   *       }, onError: (e) {
+   *         var f2 = action();
+   *         if (f2 is Future) return f2.then((_) { throw e; });
+   *         throw e;
+   *       });
+   *     }
+   */
+  Future<T> whenComplete(FutureOr action());
+
+  /**
+   * Creates a [Stream] containing the result of this future.
+   *
+   * The stream will produce single data or error event containing the
+   * completion result of this future, and then it will close with a
+   * done event.
+   *
+   * If the future never completes, the stream will not produce any events.
+   */
+  Stream<T> asStream();
+
+  /**
+   * Time-out the future computation after [timeLimit] has passed.
+   *
+   * Returns a new future that completes with the same value as this future,
+   * if this future completes in time.
+   *
+   * If this future does not complete before `timeLimit` has passed,
+   * the [onTimeout] action is executed instead, and its result (whether it
+   * returns or throws) is used as the result of the returned future.
+   * The [onTimeout] function must return a [T] or a `Future<T>`.
+   *
+   * If `onTimeout` is omitted, a timeout will cause the returned future to
+   * complete with a [TimeoutException].
+   */
+  Future<T> timeout(Duration timeLimit, {FutureOr<T> onTimeout()});
+}
+
+/**
+ * Thrown when a scheduled timeout happens while waiting for an async result.
+ */
+class TimeoutException implements Exception {
+  /** Description of the cause of the timeout. */
+  final String message;
+  /** The duration that was exceeded. */
+  final Duration duration;
+
+  TimeoutException(this.message, [this.duration]);
+
+  String toString() {
+    String result = "TimeoutException";
+    if (duration != null) result = "TimeoutException after $duration";
+    if (message != null) result = "$result: $message";
+    return result;
+  }
+}
+
+/**
+ * A way to produce Future objects and to complete them later
+ * with a value or error.
+ *
+ * Most of the time, the simplest way to create a future is to just use
+ * one of the [Future] constructors to capture the result of a single
+ * asynchronous computation:
+ * ```
+ * new Future(() { doSomething(); return result; });
+ * ```
+ * or, if the future represents the result of a sequence of asynchronous
+ * computations, they can be chained using [Future.then] or similar functions
+ * on [Future]:
+ * ```
+ * Future doStuff(){
+ *   return someAsyncOperation().then((result) {
+ *     return someOtherAsyncOperation(result);
+ *   });
+ * }
+ * ```
+ * If you do need to create a Future from scratch — for example,
+ * when you're converting a callback-based API into a Future-based
+ * one — you can use a Completer as follows:
+ * ```
+ * class AsyncOperation {
+ *   Completer _completer = new Completer();
+ *
+ *   Future<T> doOperation() {
+ *     _startOperation();
+ *     return _completer.future; // Send future object back to client.
+ *   }
+ *
+ *   // Something calls this when the value is ready.
+ *   void _finishOperation(T result) {
+ *     _completer.complete(result);
+ *   }
+ *
+ *   // If something goes wrong, call this.
+ *   void _errorHappened(error) {
+ *     _completer.completeError(error);
+ *   }
+ * }
+ * ```
+ */
+abstract class Completer<T> {
+  /**
+   * Creates a new completer.
+   *
+   * The general workflow for creating a new future is to 1) create a
+   * new completer, 2) hand out its future, and, at a later point, 3) invoke
+   * either [complete] or [completeError].
+   *
+   * The completer completes the future asynchronously. That means that
+   * callbacks registered on the future are not called immediately when
+   * [complete] or [completeError] is called. Instead the callbacks are
+   * delayed until a later microtask.
+   *
+   * Example:
+   * ```
+   * var completer = new Completer();
+   * handOut(completer.future);
+   * later: {
+   *   completer.complete('completion value');
+   * }
+   * ```
+   */
+  factory Completer() => new _AsyncCompleter<T>();
+
+  /**
+   * Completes the future synchronously.
+   *
+   * This constructor should be avoided unless the completion of the future is
+   * known to be the final result of another asynchronous operation. If in doubt
+   * use the default [Completer] constructor.
+   *
+   * Using an normal, asynchronous, completer will never give the wrong
+   * behavior, but using a synchronous completer incorrectly can cause
+   * otherwise correct programs to break.
+   *
+   * A synchronous completer is only intended for optimizing event
+   * propagation when one asynchronous event immediately triggers another.
+   * It should not be used unless the calls to [complete] and [completeError]
+   * are guaranteed to occur in places where it won't break `Future` invariants.
+   *
+   * Completing synchronously means that the completer's future will be
+   * completed immediately when calling the [complete] or [completeError]
+   * method on a synchronous completer, which also calls any callbacks
+   * registered on that future.
+   *
+   * Completing synchronously must not break the rule that when you add a
+   * callback on a future, that callback must not be called until the code
+   * that added the callback has completed.
+   * For that reason, a synchronous completion must only occur at the very end
+   * (in "tail position") of another synchronous event,
+   * because at that point, completing the future immediately is be equivalent
+   * to returning to the event loop and completing the future in the next
+   * microtask.
+   *
+   * Example:
+   *
+   *     var completer = new Completer.sync();
+   *     // The completion is the result of the asynchronous onDone event.
+   *     // No other operation is performed after the completion. It is safe
+   *     // to use the Completer.sync constructor.
+   *     stream.listen(print, onDone: () { completer.complete("done"); });
+   *
+   * Bad example. Do not use this code. Only for illustrative purposes:
+   *
+   *     var completer = new Completer.sync();
+   *     completer.future.then((_) { bar(); });
+   *     // The completion is the result of the asynchronous onDone event.
+   *     // However, there is still code executed after the completion. This
+   *     // operation is *not* safe.
+   *     stream.listen(print, onDone: () {
+   *       completer.complete("done");
+   *       foo();  // In this case, foo() runs after bar().
+   *     });
+   */
+  factory Completer.sync() => new _SyncCompleter<T>();
+
+  /**
+   * The future that is completed by this completer.
+   *
+   * The future that is completed when [complete] or [completeError] is called.
+   */
+  Future<T> get future;
+
+  /**
+   * Completes [future] with the supplied values.
+   *
+   * The value must be either a value of type [T]
+   * or a future of type `Future<T>`.
+   *
+   * If the value is itself a future, the completer will wait for that future
+   * to complete, and complete with the same result, whether it is a success
+   * or an error.
+   *
+   * Calling [complete] or [completeError] must be done at most once.
+   *
+   * All listeners on the future are informed about the value.
+   */
+  void complete([FutureOr<T> value]);
+
+  /**
+   * Complete [future] with an error.
+   *
+   * Calling [complete] or [completeError] must be done at most once.
+   *
+   * Completing a future with an error indicates that an exception was thrown
+   * while trying to produce a value.
+   *
+   * If [error] is `null`, it is replaced by a [NullThrownError].
+   *
+   * If `error` is a `Future`, the future itself is used as the error value.
+   * If you want to complete with the result of the future, you can use:
+   * ```
+   * thisCompleter.complete(theFuture)
+   * ```
+   * or if you only want to handle an error from the future:
+   * ```
+   * theFuture.catchError(thisCompleter.completeError);
+   * ```
+   */
+  void completeError(Object error, [StackTrace stackTrace]);
+
+  /**
+   * Whether the [future] has been completed.
+   *
+   * Reflects whether [complete] or [completeError] has been called.
+   * A `true` value doesn't necessarily mean that listeners of this future
+   * have been invoked yet, either because the completer usually waits until
+   * a later microtask to propagate the result, or because [complete]
+   * was called with a future that hasn't completed yet.
+   *
+   * When this value is `true`, [complete] and [completeError] must not be
+   * called again.
+   */
+  bool get isCompleted;
+}
+
+// Helper function completing a _Future with error, but checking the zone
+// for error replacement first.
+void _completeWithErrorCallback(_Future result, error, StackTrace stackTrace) {
+  AsyncError replacement = Zone.current.errorCallback(error, stackTrace);
+  if (replacement != null) {
+    error = _nonNullError(replacement.error);
+    stackTrace = replacement.stackTrace;
+  }
+  result._completeError(error, stackTrace);
+}
+
+// Like [_completeWithErrorCallback] but completes asynchronously.
+void _asyncCompleteWithErrorCallback(
+    _Future result, error, StackTrace stackTrace) {
+  AsyncError replacement = Zone.current.errorCallback(error, stackTrace);
+  if (replacement != null) {
+    error = _nonNullError(replacement.error);
+    stackTrace = replacement.stackTrace;
+  }
+  result._asyncCompleteError(error, stackTrace);
+}
+
+/** Helper function that converts `null` to a [NullThrownError]. */
+Object _nonNullError(Object error) => error ?? new NullThrownError();
diff --git a/sdk_nnbd/lib/async/future_impl.dart b/sdk_nnbd/lib/async/future_impl.dart
new file mode 100644
index 0000000..1ec0791
--- /dev/null
+++ b/sdk_nnbd/lib/async/future_impl.dart
@@ -0,0 +1,812 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.async;
+
+/** The onValue and onError handlers return either a value or a future */
+typedef FutureOr<T> _FutureOnValue<S, T>(S value);
+/** Test used by [Future.catchError] to handle skip some errors. */
+typedef bool _FutureErrorTest(Object error);
+/** Used by [WhenFuture]. */
+typedef dynamic _FutureAction();
+
+abstract class _Completer<T> implements Completer<T> {
+  final _Future<T> future = new _Future<T>();
+
+  void complete([FutureOr<T> value]);
+
+  void completeError(Object error, [StackTrace stackTrace]) {
+    error = _nonNullError(error);
+    if (!future._mayComplete) throw new StateError("Future already completed");
+    AsyncError replacement = Zone.current.errorCallback(error, stackTrace);
+    if (replacement != null) {
+      error = _nonNullError(replacement.error);
+      stackTrace = replacement.stackTrace;
+    }
+    _completeError(error, stackTrace);
+  }
+
+  void _completeError(Object error, StackTrace stackTrace);
+
+  // The future's _isComplete doesn't take into account pending completions.
+  // We therefore use _mayComplete.
+  bool get isCompleted => !future._mayComplete;
+}
+
+class _AsyncCompleter<T> extends _Completer<T> {
+  void complete([FutureOr<T> value]) {
+    if (!future._mayComplete) throw new StateError("Future already completed");
+    future._asyncComplete(value);
+  }
+
+  void _completeError(Object error, StackTrace stackTrace) {
+    future._asyncCompleteError(error, stackTrace);
+  }
+}
+
+class _SyncCompleter<T> extends _Completer<T> {
+  void complete([FutureOr<T> value]) {
+    if (!future._mayComplete) throw new StateError("Future already completed");
+    future._complete(value);
+  }
+
+  void _completeError(Object error, StackTrace stackTrace) {
+    future._completeError(error, stackTrace);
+  }
+}
+
+class _FutureListener<S, T> {
+  static const int maskValue = 1;
+  static const int maskError = 2;
+  static const int maskTestError = 4;
+  static const int maskWhencomplete = 8;
+  static const int stateChain = 0;
+  static const int stateThen = maskValue;
+  static const int stateThenOnerror = maskValue | maskError;
+  static const int stateCatcherror = maskError;
+  static const int stateCatcherrorTest = maskError | maskTestError;
+  static const int stateWhencomplete = maskWhencomplete;
+  static const int maskType =
+      maskValue | maskError | maskTestError | maskWhencomplete;
+  static const int stateIsAwait = 16;
+  // Listeners on the same future are linked through this link.
+  _FutureListener _nextListener;
+  // The future to complete when this listener is activated.
+  final _Future<T> result;
+  // Which fields means what.
+  final int state;
+  // Used for then/whenDone callback and error test
+  final Function callback;
+  // Used for error callbacks.
+  final Function errorCallback;
+
+  _FutureListener.then(
+      this.result, _FutureOnValue<S, T> onValue, Function errorCallback)
+      : callback = onValue,
+        errorCallback = errorCallback,
+        state = (errorCallback == null) ? stateThen : stateThenOnerror;
+
+  _FutureListener.thenAwait(
+      this.result, _FutureOnValue<S, T> onValue, Function errorCallback)
+      : callback = onValue,
+        errorCallback = errorCallback,
+        state = ((errorCallback == null) ? stateThen : stateThenOnerror)
+              | stateIsAwait ;
+
+  _FutureListener.catchError(this.result, this.errorCallback, this.callback)
+      : state = (callback == null) ? stateCatcherror : stateCatcherrorTest;
+
+  _FutureListener.whenComplete(this.result, this.callback)
+      : errorCallback = null,
+        state = stateWhencomplete;
+
+  Zone get _zone => result._zone;
+
+  bool get handlesValue => (state & maskValue != 0);
+  bool get handlesError => (state & maskError != 0);
+  bool get hasErrorTest => (state & maskType == stateCatcherrorTest);
+  bool get handlesComplete => (state & maskType == stateWhencomplete);
+  bool get isAwait => (state & stateIsAwait != 0);
+
+  _FutureOnValue<S, T> get _onValue {
+    assert(handlesValue);
+    return callback;
+  }
+
+  Function get _onError => errorCallback;
+  _FutureErrorTest get _errorTest {
+    assert(hasErrorTest);
+    return callback;
+  }
+
+  _FutureAction get _whenCompleteAction {
+    assert(handlesComplete);
+    return callback;
+  }
+
+  /// Whether this listener has an error callback.
+  ///
+  /// This function must only be called if the listener [handlesError].
+  bool get hasErrorCallback {
+    assert(handlesError);
+    return _onError != null;
+  }
+
+  FutureOr<T> handleValue(S sourceResult) {
+    return _zone.runUnary<FutureOr<T>, S>(_onValue, sourceResult);
+  }
+
+  bool matchesErrorTest(AsyncError asyncError) {
+    if (!hasErrorTest) return true;
+    return _zone.runUnary<bool, Object>(_errorTest, asyncError.error);
+  }
+
+  FutureOr<T> handleError(AsyncError asyncError) {
+    assert(handlesError && hasErrorCallback);
+    var errorCallback = this.errorCallback; // To enable promotion.
+    // If the errorCallback returns something which is not a FutureOr<T>,
+    // this return statement throws, and the caller handles the error.
+    if (errorCallback is dynamic Function(Object, StackTrace)) {
+      return _zone.runBinary<dynamic, Object, StackTrace>(
+          errorCallback, asyncError.error, asyncError.stackTrace);
+    } else {
+      assert(errorCallback is dynamic Function(Object));
+      return _zone.runUnary<dynamic, Object>(errorCallback, asyncError.error);
+    }
+  }
+
+  dynamic handleWhenComplete() {
+    assert(!handlesError);
+    return _zone.run(_whenCompleteAction);
+  }
+}
+
+class _Future<T> implements Future<T> {
+  /// Initial state, waiting for a result. In this state, the
+  /// [resultOrListeners] field holds a single-linked list of
+  /// [_FutureListener] listeners.
+  static const int _stateIncomplete = 0;
+
+  /// Pending completion. Set when completed using [_asyncComplete] or
+  /// [_asyncCompleteError]. It is an error to try to complete it again.
+  /// [resultOrListeners] holds listeners.
+  static const int _statePendingComplete = 1;
+
+  /// The future has been chained to another future. The result of that
+  /// other future becomes the result of this future as well.
+  /// [resultOrListeners] contains the source future.
+  static const int _stateChained = 2;
+
+  /// The future has been completed with a value result.
+  static const int _stateValue = 4;
+
+  /// The future has been completed with an error result.
+  static const int _stateError = 8;
+
+  /** Whether the future is complete, and as what. */
+  int _state = _stateIncomplete;
+
+  /**
+   * Zone that the future was completed from.
+   * This is the zone that an error result belongs to.
+   *
+   * Until the future is completed, the field may hold the zone that
+   * listener callbacks used to create this future should be run in.
+   */
+  final Zone _zone;
+
+  /**
+   * Either the result, a list of listeners or another future.
+   *
+   * The result of the future is either a value or an error.
+   * A result is only stored when the future has completed.
+   *
+   * The listeners is an internally linked list of [_FutureListener]s.
+   * Listeners are only remembered while the future is not yet complete,
+   * and it is not chained to another future.
+   *
+   * The future is another future that his future is chained to. This future
+   * is waiting for the other future to complete, and when it does, this future
+   * will complete with the same result.
+   * All listeners are forwarded to the other future.
+   */
+  var _resultOrListeners;
+
+  // This constructor is used by async/await.
+  _Future() : _zone = Zone.current;
+
+  _Future.immediate(FutureOr<T> result) : _zone = Zone.current {
+    _asyncComplete(result);
+  }
+
+  /** Creates a future with the value and the specified zone. */
+  _Future.zoneValue(T value, this._zone) {
+    _setValue(value);
+  }
+
+  _Future.immediateError(var error, [StackTrace stackTrace])
+      : _zone = Zone.current {
+    _asyncCompleteError(error, stackTrace);
+  }
+
+  /** Creates a future that is already completed with the value. */
+  _Future.value(T value) : this.zoneValue(value, Zone.current);
+
+  bool get _mayComplete => _state == _stateIncomplete;
+  bool get _isPendingComplete => _state == _statePendingComplete;
+  bool get _mayAddListener => _state <= _statePendingComplete;
+  bool get _isChained => _state == _stateChained;
+  bool get _isComplete => _state >= _stateValue;
+  bool get _hasError => _state == _stateError;
+
+  static List<Function> _continuationFunctions(_Future<Object> future) {
+    List<Function> result = null;
+    while (true) {
+      if (future._mayAddListener) return result;
+      assert(!future._isComplete);
+      assert(!future._isChained);
+      // So _resultOrListeners contains listeners.
+      _FutureListener<Object, Object> listener = future._resultOrListeners;
+      if (listener != null &&
+          listener._nextListener == null &&
+          listener.isAwait) {
+        (result ??= <Function>[]).add(listener.handleValue);
+        future = listener.result;
+        assert(!future._isComplete);
+      } else {
+        break;
+      }
+    }
+    return result;
+  }
+
+  void _setChained(_Future source) {
+    assert(_mayAddListener);
+    _state = _stateChained;
+    _resultOrListeners = source;
+  }
+
+  Future<R> then<R>(FutureOr<R> f(T value), {Function onError}) {
+    Zone currentZone = Zone.current;
+    if (!identical(currentZone, _rootZone)) {
+      f = currentZone.registerUnaryCallback<FutureOr<R>, T>(f);
+      if (onError != null) {
+        // In checked mode, this checks that onError is assignable to one of:
+        //   dynamic Function(Object)
+        //   dynamic Function(Object, StackTrace)
+        onError = _registerErrorHandler(onError, currentZone);
+      }
+    }
+    _Future<R> result = new _Future<R>();
+    _addListener(new _FutureListener<T, R>.then(result, f, onError));
+    return result;
+  }
+
+  /// Registers a system created result and error continuation.
+  ///
+  /// Used by the implementation of `await` to listen to a future.
+  /// The system created liseners are not registered in the zone,
+  /// and the listener is marked as being from an `await`.
+  /// This marker is used in [_continuationFunctions].
+  Future<E> _thenAwait<E>(
+      FutureOr<E> f(T value), Function onError) {
+    _Future<E> result = new _Future<E>();
+    _addListener(new _FutureListener<T, E>.thenAwait(result, f, onError));
+    return result;
+  }
+
+  Future<T> catchError(Function onError, {bool test(error)}) {
+    _Future<T> result = new _Future<T>();
+    if (!identical(result._zone, _rootZone)) {
+      onError = _registerErrorHandler(onError, result._zone);
+      if (test != null) test = result._zone.registerUnaryCallback(test);
+    }
+    _addListener(new _FutureListener<T, T>.catchError(result, onError, test));
+    return result;
+  }
+
+  Future<T> whenComplete(dynamic action()) {
+    _Future<T> result = new _Future<T>();
+    if (!identical(result._zone, _rootZone)) {
+      action = result._zone.registerCallback<dynamic>(action);
+    }
+    _addListener(new _FutureListener<T, T>.whenComplete(result, action));
+    return result;
+  }
+
+  Stream<T> asStream() => new Stream<T>.fromFuture(this);
+
+  void _setPendingComplete() {
+    assert(_mayComplete);
+    _state = _statePendingComplete;
+  }
+
+  void _clearPendingComplete() {
+    assert(_isPendingComplete);
+    _state = _stateIncomplete;
+  }
+
+  AsyncError get _error {
+    assert(_hasError);
+    return _resultOrListeners;
+  }
+
+  _Future get _chainSource {
+    assert(_isChained);
+    return _resultOrListeners;
+  }
+
+  // This method is used by async/await.
+  void _setValue(T value) {
+    assert(!_isComplete); // But may have a completion pending.
+    _state = _stateValue;
+    _resultOrListeners = value;
+  }
+
+  void _setErrorObject(AsyncError error) {
+    assert(!_isComplete); // But may have a completion pending.
+    _state = _stateError;
+    _resultOrListeners = error;
+  }
+
+  void _setError(Object error, StackTrace stackTrace) {
+    _setErrorObject(new AsyncError(error, stackTrace));
+  }
+
+  /// Copy the completion result of [source] into this future.
+  ///
+  /// Used when a chained future notices that its source is completed.
+  void _cloneResult(_Future source) {
+    assert(!_isComplete);
+    assert(source._isComplete);
+    _state = source._state;
+    _resultOrListeners = source._resultOrListeners;
+  }
+
+  void _addListener(_FutureListener listener) {
+    assert(listener._nextListener == null);
+    if (_mayAddListener) {
+      listener._nextListener = _resultOrListeners;
+      _resultOrListeners = listener;
+    } else {
+      if (_isChained) {
+        // Delegate listeners to chained source future.
+        // If the source is complete, instead copy its values and
+        // drop the chaining.
+        _Future source = _chainSource;
+        if (!source._isComplete) {
+          source._addListener(listener);
+          return;
+        }
+        _cloneResult(source);
+      }
+      assert(_isComplete);
+      // Handle late listeners asynchronously.
+      _zone.scheduleMicrotask(() {
+        _propagateToListeners(this, listener);
+      });
+    }
+  }
+
+  void _prependListeners(_FutureListener listeners) {
+    if (listeners == null) return;
+    if (_mayAddListener) {
+      _FutureListener existingListeners = _resultOrListeners;
+      _resultOrListeners = listeners;
+      if (existingListeners != null) {
+        _FutureListener cursor = listeners;
+        while (cursor._nextListener != null) {
+          cursor = cursor._nextListener;
+        }
+        cursor._nextListener = existingListeners;
+      }
+    } else {
+      if (_isChained) {
+        // Delegate listeners to chained source future.
+        // If the source is complete, instead copy its values and
+        // drop the chaining.
+        _Future source = _chainSource;
+        if (!source._isComplete) {
+          source._prependListeners(listeners);
+          return;
+        }
+        _cloneResult(source);
+      }
+      assert(_isComplete);
+      listeners = _reverseListeners(listeners);
+      _zone.scheduleMicrotask(() {
+        _propagateToListeners(this, listeners);
+      });
+    }
+  }
+
+  _FutureListener _removeListeners() {
+    // Reverse listeners before returning them, so the resulting list is in
+    // subscription order.
+    assert(!_isComplete);
+    _FutureListener current = _resultOrListeners;
+    _resultOrListeners = null;
+    return _reverseListeners(current);
+  }
+
+  _FutureListener _reverseListeners(_FutureListener listeners) {
+    _FutureListener prev;
+    _FutureListener current = listeners;
+    while (current != null) {
+      _FutureListener next = current._nextListener;
+      current._nextListener = prev;
+      prev = current;
+      current = next;
+    }
+    return prev;
+  }
+
+  // Take the value (when completed) of source and complete target with that
+  // value (or error). This function could chain all Futures, but is slower
+  // for _Future than _chainCoreFuture, so you must use _chainCoreFuture
+  // in that case.
+  static void _chainForeignFuture(Future source, _Future target) {
+    assert(!target._isComplete);
+    assert(source is! _Future);
+
+    // Mark the target as chained (and as such half-completed).
+    target._setPendingComplete();
+    try {
+      source.then((value) {
+        assert(target._isPendingComplete);
+        // The "value" may be another future if the foreign future
+        // implementation is mis-behaving,
+        // so use _complete instead of _completeWithValue.
+        target._clearPendingComplete(); // Clear this first, it's set again.
+        target._complete(value);
+      },
+          // TODO(floitsch): eventually we would like to make this non-optional
+          // and dependent on the listeners of the target future. If none of
+          // the target future's listeners want to have the stack trace we don't
+          // need a trace.
+          onError: (error, [StackTrace stackTrace]) {
+        assert(target._isPendingComplete);
+        target._completeError(error, stackTrace);
+      });
+    } catch (e, s) {
+      // This only happens if the `then` call threw synchronously when given
+      // valid arguments.
+      // That requires a non-conforming implementation of the Future interface,
+      // which should, hopefully, never happen.
+      scheduleMicrotask(() {
+        target._completeError(e, s);
+      });
+    }
+  }
+
+  // Take the value (when completed) of source and complete target with that
+  // value (or error). This function expects that source is a _Future.
+  static void _chainCoreFuture(_Future source, _Future target) {
+    assert(target._mayAddListener); // Not completed, not already chained.
+    while (source._isChained) {
+      source = source._chainSource;
+    }
+    if (source._isComplete) {
+      _FutureListener listeners = target._removeListeners();
+      target._cloneResult(source);
+      _propagateToListeners(target, listeners);
+    } else {
+      _FutureListener listeners = target._resultOrListeners;
+      target._setChained(source);
+      source._prependListeners(listeners);
+    }
+  }
+
+  void _complete(FutureOr<T> value) {
+    assert(!_isComplete);
+    if (value is Future<T>) {
+      if (value is _Future<T>) {
+        _chainCoreFuture(value, this);
+      } else {
+        _chainForeignFuture(value, this);
+      }
+    } else {
+      _FutureListener listeners = _removeListeners();
+      _setValue(value);
+      _propagateToListeners(this, listeners);
+    }
+  }
+
+  void _completeWithValue(T value) {
+    assert(!_isComplete);
+    assert(value is! Future<T>);
+
+    _FutureListener listeners = _removeListeners();
+    _setValue(value);
+    _propagateToListeners(this, listeners);
+  }
+
+  void _completeError(Object error, [StackTrace stackTrace]) {
+    assert(!_isComplete);
+
+    _FutureListener listeners = _removeListeners();
+    _setError(error, stackTrace);
+    _propagateToListeners(this, listeners);
+  }
+
+  void _asyncComplete(FutureOr<T> value) {
+    assert(!_isComplete);
+    // Two corner cases if the value is a future:
+    //   1. the future is already completed and an error.
+    //   2. the future is not yet completed but might become an error.
+    // The first case means that we must not immediately complete the Future,
+    // as our code would immediately start propagating the error without
+    // giving the time to install error-handlers.
+    // However the second case requires us to deal with the value immediately.
+    // Otherwise the value could complete with an error and report an
+    // unhandled error, even though we know we are already going to listen to
+    // it.
+
+    if (value is Future<T>) {
+      _chainFuture(value);
+      return;
+    }
+    _setPendingComplete();
+    _zone.scheduleMicrotask(() {
+      _completeWithValue(value);
+    });
+  }
+
+  void _chainFuture(Future<T> value) {
+    if (value is _Future<T>) {
+      if (value._hasError) {
+        // Delay completion to allow the user to register callbacks.
+        _setPendingComplete();
+        _zone.scheduleMicrotask(() {
+          _chainCoreFuture(value, this);
+        });
+      } else {
+        _chainCoreFuture(value, this);
+      }
+      return;
+    }
+    // Just listen on the foreign future. This guarantees an async delay.
+    _chainForeignFuture(value, this);
+  }
+
+  void _asyncCompleteError(error, StackTrace stackTrace) {
+    assert(!_isComplete);
+
+    _setPendingComplete();
+    _zone.scheduleMicrotask(() {
+      _completeError(error, stackTrace);
+    });
+  }
+
+  /**
+   * Propagates the value/error of [source] to its [listeners], executing the
+   * listeners' callbacks.
+   */
+  static void _propagateToListeners(_Future source, _FutureListener listeners) {
+    while (true) {
+      assert(source._isComplete);
+      bool hasError = source._hasError;
+      if (listeners == null) {
+        if (hasError) {
+          AsyncError asyncError = source._error;
+          source._zone
+              .handleUncaughtError(asyncError.error, asyncError.stackTrace);
+        }
+        return;
+      }
+      // Usually futures only have one listener. If they have several, we
+      // call handle them separately in recursive calls, continuing
+      // here only when there is only one listener left.
+      while (listeners._nextListener != null) {
+        _FutureListener listener = listeners;
+        listeners = listener._nextListener;
+        listener._nextListener = null;
+        _propagateToListeners(source, listener);
+      }
+      _FutureListener listener = listeners;
+      final sourceResult = source._resultOrListeners;
+      // Do the actual propagation.
+      // Set initial state of listenerHasError and listenerValueOrError. These
+      // variables are updated with the outcome of potential callbacks.
+      // Non-error results, including futures, are stored in
+      // listenerValueOrError and listenerHasError is set to false. Errors
+      // are stored in listenerValueOrError as an [AsyncError] and
+      // listenerHasError is set to true.
+      bool listenerHasError = hasError;
+      var listenerValueOrError = sourceResult;
+
+      // Only if we either have an error or callbacks, go into this, somewhat
+      // expensive, branch. Here we'll enter/leave the zone. Many futures
+      // don't have callbacks, so this is a significant optimization.
+      if (hasError || listener.handlesValue || listener.handlesComplete) {
+        Zone zone = listener._zone;
+        if (hasError && !source._zone.inSameErrorZone(zone)) {
+          // Don't cross zone boundaries with errors.
+          AsyncError asyncError = source._error;
+          source._zone
+              .handleUncaughtError(asyncError.error, asyncError.stackTrace);
+          return;
+        }
+
+        Zone oldZone;
+        if (!identical(Zone.current, zone)) {
+          // Change zone if it's not current.
+          oldZone = Zone._enter(zone);
+        }
+
+        // These callbacks are abstracted to isolate the try/catch blocks
+        // from the rest of the code to work around a V8 glass jaw.
+        void handleWhenCompleteCallback() {
+          // The whenComplete-handler is not combined with normal value/error
+          // handling. This means at most one handleX method is called per
+          // listener.
+          assert(!listener.handlesValue);
+          assert(!listener.handlesError);
+          var completeResult;
+          try {
+            completeResult = listener.handleWhenComplete();
+          } catch (e, s) {
+            if (hasError && identical(source._error.error, e)) {
+              listenerValueOrError = source._error;
+            } else {
+              listenerValueOrError = new AsyncError(e, s);
+            }
+            listenerHasError = true;
+            return;
+          }
+          if (completeResult is Future) {
+            if (completeResult is _Future && completeResult._isComplete) {
+              if (completeResult._hasError) {
+                listenerValueOrError = completeResult._error;
+                listenerHasError = true;
+              }
+              // Otherwise use the existing result of source.
+              return;
+            }
+            // We have to wait for the completeResult future to complete
+            // before knowing if it's an error or we should use the result
+            // of source.
+            var originalSource = source;
+            listenerValueOrError = completeResult.then((_) => originalSource);
+            listenerHasError = false;
+          }
+        }
+
+        void handleValueCallback() {
+          try {
+            listenerValueOrError = listener.handleValue(sourceResult);
+          } catch (e, s) {
+            listenerValueOrError = new AsyncError(e, s);
+            listenerHasError = true;
+          }
+        }
+
+        void handleError() {
+          try {
+            AsyncError asyncError = source._error;
+            if (listener.matchesErrorTest(asyncError) &&
+                listener.hasErrorCallback) {
+              listenerValueOrError = listener.handleError(asyncError);
+              listenerHasError = false;
+            }
+          } catch (e, s) {
+            if (identical(source._error.error, e)) {
+              listenerValueOrError = source._error;
+            } else {
+              listenerValueOrError = new AsyncError(e, s);
+            }
+            listenerHasError = true;
+          }
+        }
+
+        if (listener.handlesComplete) {
+          handleWhenCompleteCallback();
+        } else if (!hasError) {
+          if (listener.handlesValue) {
+            handleValueCallback();
+          }
+        } else {
+          if (listener.handlesError) {
+            handleError();
+          }
+        }
+
+        // If we changed zone, oldZone will not be null.
+        if (oldZone != null) Zone._leave(oldZone);
+
+        // If the listener's value is a future we need to chain it. Note that
+        // this can only happen if there is a callback.
+        if (listenerValueOrError is Future) {
+          Future chainSource = listenerValueOrError;
+          // Shortcut if the chain-source is already completed. Just continue
+          // the loop.
+          _Future result = listener.result;
+          if (chainSource is _Future) {
+            if (chainSource._isComplete) {
+              listeners = result._removeListeners();
+              result._cloneResult(chainSource);
+              source = chainSource;
+              continue;
+            } else {
+              _chainCoreFuture(chainSource, result);
+            }
+          } else {
+            _chainForeignFuture(chainSource, result);
+          }
+          return;
+        }
+      }
+      _Future result = listener.result;
+      listeners = result._removeListeners();
+      if (!listenerHasError) {
+        result._setValue(listenerValueOrError);
+      } else {
+        AsyncError asyncError = listenerValueOrError;
+        result._setErrorObject(asyncError);
+      }
+      // Prepare for next round.
+      source = result;
+    }
+  }
+
+  Future<T> timeout(Duration timeLimit, {FutureOr<T> onTimeout()}) {
+    if (_isComplete) return new _Future.immediate(this);
+    _Future<T> result = new _Future<T>();
+    Timer timer;
+    if (onTimeout == null) {
+      timer = new Timer(timeLimit, () {
+        result._completeError(
+            new TimeoutException("Future not completed", timeLimit));
+      });
+    } else {
+      Zone zone = Zone.current;
+      onTimeout = zone.registerCallback(onTimeout);
+      timer = new Timer(timeLimit, () {
+        try {
+          result._complete(zone.run(onTimeout));
+        } catch (e, s) {
+          result._completeError(e, s);
+        }
+      });
+    }
+    this.then((T v) {
+      if (timer.isActive) {
+        timer.cancel();
+        result._completeWithValue(v);
+      }
+    }, onError: (e, StackTrace s) {
+      if (timer.isActive) {
+        timer.cancel();
+        result._completeError(e, s);
+      }
+    });
+    return result;
+  }
+}
+
+/// Registers errorHandler in zone if it has the correct type.
+///
+/// Checks that the function accepts either an [Object] and a [StackTrace]
+/// or just one [Object]. Does not check the return type.
+/// The actually returned value must be `FutureOr<R>` where `R` is the
+/// value type of the future that the call will complete (either returned
+/// by [Future.then] or [Future.catchError]). We check the returned value
+/// dynamically because the functions are passed as arguments in positions
+/// without inference, so a function expression won't infer the return type.
+///
+/// Throws if the type is not valid.
+Function _registerErrorHandler(Function errorHandler, Zone zone) {
+  if (errorHandler is dynamic Function(Object, StackTrace)) {
+    return zone
+        .registerBinaryCallback<dynamic, Object, StackTrace>(errorHandler);
+  }
+  if (errorHandler is dynamic Function(Object)) {
+    return zone.registerUnaryCallback<dynamic, Object>(errorHandler);
+  }
+  throw new ArgumentError.value(
+      errorHandler,
+      "onError",
+      "Error handler must accept one Object or one Object and a StackTrace"
+      " as arguments, and return a a valid result");
+}
diff --git a/sdk_nnbd/lib/async/schedule_microtask.dart b/sdk_nnbd/lib/async/schedule_microtask.dart
new file mode 100644
index 0000000..801490a
--- /dev/null
+++ b/sdk_nnbd/lib/async/schedule_microtask.dart
@@ -0,0 +1,153 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.async;
+
+typedef void _AsyncCallback();
+
+class _AsyncCallbackEntry {
+  final _AsyncCallback callback;
+  _AsyncCallbackEntry next;
+  _AsyncCallbackEntry(this.callback);
+}
+
+/** Head of single linked list of pending callbacks. */
+_AsyncCallbackEntry _nextCallback;
+/** Tail of single linked list of pending callbacks. */
+_AsyncCallbackEntry _lastCallback;
+/**
+ * Tail of priority callbacks added by the currently executing callback.
+ *
+ * Priority callbacks are put at the beginning of the
+ * callback queue, so that if one callback schedules more than one
+ * priority callback, they are still enqueued in scheduling order.
+ */
+_AsyncCallbackEntry _lastPriorityCallback;
+/**
+ * Whether we are currently inside the callback loop.
+ *
+ * If we are inside the loop, we never need to schedule the loop,
+ * even if adding a first element.
+ */
+bool _isInCallbackLoop = false;
+
+void _microtaskLoop() {
+  while (_nextCallback != null) {
+    _lastPriorityCallback = null;
+    _AsyncCallbackEntry entry = _nextCallback;
+    _nextCallback = entry.next;
+    if (_nextCallback == null) _lastCallback = null;
+    (entry.callback)();
+  }
+}
+
+void _startMicrotaskLoop() {
+  _isInCallbackLoop = true;
+  try {
+    // Moved to separate function because try-finally prevents
+    // good optimization.
+    _microtaskLoop();
+  } finally {
+    _lastPriorityCallback = null;
+    _isInCallbackLoop = false;
+    if (_nextCallback != null) {
+      _AsyncRun._scheduleImmediate(_startMicrotaskLoop);
+    }
+  }
+}
+
+/**
+ * Schedules a callback to be called as a microtask.
+ *
+ * The microtask is called after all other currently scheduled
+ * microtasks, but as part of the current system event.
+ */
+void _scheduleAsyncCallback(_AsyncCallback callback) {
+  _AsyncCallbackEntry newEntry = new _AsyncCallbackEntry(callback);
+  if (_nextCallback == null) {
+    _nextCallback = _lastCallback = newEntry;
+    if (!_isInCallbackLoop) {
+      _AsyncRun._scheduleImmediate(_startMicrotaskLoop);
+    }
+  } else {
+    _lastCallback.next = newEntry;
+    _lastCallback = newEntry;
+  }
+}
+
+/**
+ * Schedules a callback to be called before all other currently scheduled ones.
+ *
+ * This callback takes priority over existing scheduled callbacks.
+ * It is only used internally to give higher priority to error reporting.
+ *
+ * Is always run in the root zone.
+ */
+void _schedulePriorityAsyncCallback(_AsyncCallback callback) {
+  if (_nextCallback == null) {
+    _scheduleAsyncCallback(callback);
+    _lastPriorityCallback = _lastCallback;
+    return;
+  }
+  _AsyncCallbackEntry entry = new _AsyncCallbackEntry(callback);
+  if (_lastPriorityCallback == null) {
+    entry.next = _nextCallback;
+    _nextCallback = _lastPriorityCallback = entry;
+  } else {
+    entry.next = _lastPriorityCallback.next;
+    _lastPriorityCallback.next = entry;
+    _lastPriorityCallback = entry;
+    if (entry.next == null) {
+      _lastCallback = entry;
+    }
+  }
+}
+
+/**
+ * Runs a function asynchronously.
+ *
+ * Callbacks registered through this function are always executed in order and
+ * are guaranteed to run before other asynchronous events (like [Timer] events,
+ * or DOM events).
+ *
+ * **Warning:** it is possible to starve the DOM by registering asynchronous
+ * callbacks through this method. For example the following program runs
+ * the callbacks without ever giving the Timer callback a chance to execute:
+ *
+ *     main() {
+ *       Timer.run(() { print("executed"); });  // Will never be executed.
+ *       foo() {
+ *         scheduleMicrotask(foo);  // Schedules [foo] in front of other events.
+ *       }
+ *       foo();
+ *     }
+ *
+ * ## Other resources
+ *
+ * * [The Event Loop and Dart](https://www.dartlang.org/articles/event-loop/):
+ * Learn how Dart handles the event queue and microtask queue, so you can write
+ * better asynchronous code with fewer surprises.
+ */
+void scheduleMicrotask(void callback()) {
+  _Zone currentZone = Zone.current;
+  if (identical(_rootZone, currentZone)) {
+    // No need to bind the callback. We know that the root's scheduleMicrotask
+    // will be invoked in the root zone.
+    _rootScheduleMicrotask(null, null, _rootZone, callback);
+    return;
+  }
+  _ZoneFunction implementation = currentZone._scheduleMicrotask;
+  if (identical(_rootZone, implementation.zone) &&
+      _rootZone.inSameErrorZone(currentZone)) {
+    _rootScheduleMicrotask(
+        null, null, currentZone, currentZone.registerCallback(callback));
+    return;
+  }
+  Zone.current.scheduleMicrotask(Zone.current.bindCallbackGuarded(callback));
+}
+
+class _AsyncRun {
+  /** Schedule the given callback before any other event in the event-loop. */
+  external static void _scheduleImmediate(void callback());
+}
diff --git a/sdk_nnbd/lib/async/stream.dart b/sdk_nnbd/lib/async/stream.dart
new file mode 100644
index 0000000..95a8b97
--- /dev/null
+++ b/sdk_nnbd/lib/async/stream.dart
@@ -0,0 +1,2267 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.async;
+
+// -------------------------------------------------------------------
+// Core Stream types
+// -------------------------------------------------------------------
+
+typedef void _TimerCallback();
+
+/**
+ * A source of asynchronous data events.
+ *
+ * A Stream provides a way to receive a sequence of events.
+ * Each event is either a data event, also called an *element* of the stream,
+ * or an error event, which is a notification that something has failed.
+ * When a stream has emitted all its event,
+ * a single "done" event will notify the listener that the end has been reached.
+ *
+ * You [listen] on a stream to make it start generating events,
+ * and to set up listeners that receive the events.
+ * When you listen, you receive a [StreamSubscription] object
+ * which is the active object providing the events,
+ * and which can be used to stop listening again,
+ * or to temporarily pause events from the subscription.
+ *
+ * There are two kinds of streams: "Single-subscription" streams and
+ * "broadcast" streams.
+ *
+ * *A single-subscription stream* allows only a single listener during the whole
+ * lifetime of the stream.
+ * It doesn't start generating events until it has a listener,
+ * and it stops sending events when the listener is unsubscribed,
+ * even if the source of events could still provide more.
+ *
+ * Listening twice on a single-subscription stream is not allowed, even after
+ * the first subscription has been canceled.
+ *
+ * Single-subscription streams are generally used for streaming chunks of
+ * larger contiguous data like file I/O.
+ *
+ * *A broadcast stream* allows any number of listeners, and it fires
+ * its events when they are ready, whether there are listeners or not.
+ *
+ * Broadcast streams are used for independent events/observers.
+ *
+ * If several listeners want to listen to a single subscription stream,
+ * use [asBroadcastStream] to create a broadcast stream on top of the
+ * non-broadcast stream.
+ *
+ * On either kind of stream, stream transformations, such as [where] and
+ * [skip], return the same type of stream as the one the method was called on,
+ * unless otherwise noted.
+ *
+ * When an event is fired, the listener(s) at that time will receive the event.
+ * If a listener is added to a broadcast stream while an event is being fired,
+ * that listener will not receive the event currently being fired.
+ * If a listener is canceled, it immediately stops receiving events.
+ * Listening on a broadcast stream can be treated as listening on a new stream
+ * containing only the events that have not yet been emitted when the [listen]
+ * call occurs.
+ * For example, the [first] getter listens to the stream, then returns the first
+ * event that listener receives.
+ * This is not necessarily the first even emitted by the stream, but the first
+ * of the *remaining* events of the broadcast stream.
+ *
+ * When the "done" event is fired, subscribers are unsubscribed before
+ * receiving the event. After the event has been sent, the stream has no
+ * subscribers. Adding new subscribers to a broadcast stream after this point
+ * is allowed, but they will just receive a new "done" event as soon
+ * as possible.
+ *
+ * Stream subscriptions always respect "pause" requests. If necessary they need
+ * to buffer their input, but often, and preferably, they can simply request
+ * their input to pause too.
+ *
+ * The default implementation of [isBroadcast] returns false.
+ * A broadcast stream inheriting from [Stream] must override [isBroadcast]
+ * to return `true`.
+ */
+abstract class Stream<T> {
+  Stream();
+
+  /**
+   * Internal use only. We do not want to promise that Stream stays const.
+   *
+   * If mixins become compatible with const constructors, we may use a
+   * stream mixin instead of extending Stream from a const class.
+   */
+  const Stream._internal();
+
+  /**
+   * Creates an empty broadcast stream.
+   *
+   * This is a stream which does nothing except sending a done event
+   * when it's listened to.
+   */
+  const factory Stream.empty() = _EmptyStream<T>;
+
+  /**
+   * Creates a stream which emits a single data event before completing.
+   *
+   * This stream emits a single data event of [value]
+   * and then completes with a done event.
+   *
+   * Example:
+   * ```dart
+   * Future<void> printThings(Stream<String> data) async {
+   *   await for (var x in data) {
+   *     print(x);
+   *   }
+   * }
+   * printThings(Stream<String>.value("ok")); // prints "ok".
+   * ```
+   *
+   * The returned stream is effectively equivalent to one created by
+   * `(() async* { yield value; } ())` or `Future<T>.value(value).asStream()`.
+   */
+  @Since("2.5")
+  factory Stream.value(T value) =>
+      (_AsyncStreamController<T>(null, null, null, null)
+            .._add(value)
+            .._closeUnchecked())
+          .stream;
+
+  /**
+   * Creates a stream which emits a single error event before completing.
+   *
+   * This stream emits a single error event of [error] and [stackTrace]
+   * and then completes with a done event.
+   *
+   * Example:
+   * ```dart
+   * Future<void> tryThings(Stream<int> data) async {
+   *   try {
+   *     await for (var x in data) {
+   *       print("Data: $x");
+   *     }
+   *   } catch (e) {
+   *     print(e);
+   *   }
+   * }
+   * tryThings(Stream<int>.error("Error")); // prints "Error".
+   * ```
+   * The returned stream is effectively equivalent to one created by
+   * `Future<T>.error(error, stackTrace).asStream()`, by or
+   * `(() async* { throw error; } ())`, except that you can control the
+   * stack trace as well.
+   */
+  @Since("2.5")
+  factory Stream.error(Object error, [StackTrace stackTrace]) =>
+      (_AsyncStreamController<T>(null, null, null, null)
+            .._addError(error, stackTrace)
+            .._closeUnchecked())
+          .stream;
+
+  /**
+   * Creates a new single-subscription stream from the future.
+   *
+   * When the future completes, the stream will fire one event, either
+   * data or error, and then close with a done-event.
+   */
+  factory Stream.fromFuture(Future<T> future) {
+    // Use the controller's buffering to fill in the value even before
+    // the stream has a listener. For a single value, it's not worth it
+    // to wait for a listener before doing the `then` on the future.
+    _StreamController<T> controller =
+        new _SyncStreamController<T>(null, null, null, null);
+    future.then((value) {
+      controller._add(value);
+      controller._closeUnchecked();
+    }, onError: (error, stackTrace) {
+      controller._addError(error, stackTrace);
+      controller._closeUnchecked();
+    });
+    return controller.stream;
+  }
+
+  /**
+   * Create a stream from a group of futures.
+   *
+   * The stream reports the results of the futures on the stream in the order
+   * in which the futures complete.
+   * Each future provides either a data event or an error event,
+   * depending on how the future completes.
+   *
+   * If some futures have already completed when `Stream.fromFutures` is called,
+   * their results will be emitted in some unspecified order.
+   *
+   * When all futures have completed, the stream is closed.
+   *
+   * If [futures] is empty, the stream closes as soon as possible.
+   */
+  factory Stream.fromFutures(Iterable<Future<T>> futures) {
+    _StreamController<T> controller =
+        new _SyncStreamController<T>(null, null, null, null);
+    int count = 0;
+    // Declare these as variables holding closures instead of as
+    // function declarations.
+    // This avoids creating a new closure from the functions for each future.
+    var onValue = (T value) {
+      if (!controller.isClosed) {
+        controller._add(value);
+        if (--count == 0) controller._closeUnchecked();
+      }
+    };
+    var onError = (error, StackTrace stack) {
+      if (!controller.isClosed) {
+        controller._addError(error, stack);
+        if (--count == 0) controller._closeUnchecked();
+      }
+    };
+    // The futures are already running, so start listening to them immediately
+    // (instead of waiting for the stream to be listened on).
+    // If we wait, we might not catch errors in the futures in time.
+    for (var future in futures) {
+      count++;
+      future.then(onValue, onError: onError);
+    }
+    // Use schedule microtask since controller is sync.
+    if (count == 0) scheduleMicrotask(controller.close);
+    return controller.stream;
+  }
+
+  /**
+   * Creates a single-subscription stream that gets its data from [elements].
+   *
+   * The iterable is iterated when the stream receives a listener, and stops
+   * iterating if the listener cancels the subscription, or if the
+   * [Iterator.moveNext] method returns `false` or throws.
+   * Iteration is suspended while the stream subscription is paused.
+   *
+   * If calling [Iterator.moveNext] on `elements.iterator` throws,
+   * the stream emits that error and then it closes.
+   * If reading [Iterator.current] on `elements.iterator` throws,
+   * the stream emits that error, but keeps iterating.
+   */
+  factory Stream.fromIterable(Iterable<T> elements) {
+    return new _GeneratedStreamImpl<T>(
+        () => new _IterablePendingEvents<T>(elements));
+  }
+
+  /**
+   * Creates a stream that repeatedly emits events at [period] intervals.
+   *
+   * The event values are computed by invoking [computation]. The argument to
+   * this callback is an integer that starts with 0 and is incremented for
+   * every event.
+   *
+   * If [computation] is omitted the event values will all be `null`.
+   */
+  factory Stream.periodic(Duration period,
+      [T computation(int computationCount)]) {
+    Timer timer;
+    int computationCount = 0;
+    StreamController<T> controller;
+    // Counts the time that the Stream was running (and not paused).
+    Stopwatch watch = new Stopwatch();
+
+    void sendEvent() {
+      watch.reset();
+      T data;
+      if (computation != null) {
+        try {
+          data = computation(computationCount++);
+        } catch (e, s) {
+          controller.addError(e, s);
+          return;
+        }
+      }
+      controller.add(data);
+    }
+
+    void startPeriodicTimer() {
+      assert(timer == null);
+      timer = new Timer.periodic(period, (Timer timer) {
+        sendEvent();
+      });
+    }
+
+    controller = new StreamController<T>(
+        sync: true,
+        onListen: () {
+          watch.start();
+          startPeriodicTimer();
+        },
+        onPause: () {
+          timer.cancel();
+          timer = null;
+          watch.stop();
+        },
+        onResume: () {
+          assert(timer == null);
+          Duration elapsed = watch.elapsed;
+          watch.start();
+          timer = new Timer(period - elapsed, () {
+            timer = null;
+            startPeriodicTimer();
+            sendEvent();
+          });
+        },
+        onCancel: () {
+          if (timer != null) timer.cancel();
+          timer = null;
+          return Future._nullFuture;
+        });
+    return controller.stream;
+  }
+
+  /**
+   * Creates a stream where all events of an existing stream are piped through
+   * a sink-transformation.
+   *
+   * The given [mapSink] closure is invoked when the returned stream is
+   * listened to. All events from the [source] are added into the event sink
+   * that is returned from the invocation. The transformation puts all
+   * transformed events into the sink the [mapSink] closure received during
+   * its invocation. Conceptually the [mapSink] creates a transformation pipe
+   * with the input sink being the returned [EventSink] and the output sink
+   * being the sink it received.
+   *
+   * This constructor is frequently used to build transformers.
+   *
+   * Example use for a duplicating transformer:
+   *
+   *     class DuplicationSink implements EventSink<String> {
+   *       final EventSink<String> _outputSink;
+   *       DuplicationSink(this._outputSink);
+   *
+   *       void add(String data) {
+   *         _outputSink.add(data);
+   *         _outputSink.add(data);
+   *       }
+   *
+   *       void addError(e, [st]) { _outputSink.addError(e, st); }
+   *       void close() { _outputSink.close(); }
+   *     }
+   *
+   *     class DuplicationTransformer extends StreamTransformerBase<String, String> {
+   *       // Some generic types omitted for brevity.
+   *       Stream bind(Stream stream) => new Stream<String>.eventTransformed(
+   *           stream,
+   *           (EventSink sink) => new DuplicationSink(sink));
+   *     }
+   *
+   *     stringStream.transform(new DuplicationTransformer());
+   *
+   * The resulting stream is a broadcast stream if [source] is.
+   */
+  factory Stream.eventTransformed(
+      Stream source, EventSink mapSink(EventSink<T> sink)) {
+    return new _BoundSinkStream(source, mapSink);
+  }
+
+  /**
+   * Adapts [source] to be a `Stream<T>`.
+   *
+   * This allows [source] to be used at the new type, but at run-time it
+   * must satisfy the requirements of both the new type and its original type.
+   *
+   * Data events created by the source stream must also be instances of [T].
+   */
+  static Stream<T> castFrom<S, T>(Stream<S> source) =>
+      new CastStream<S, T>(source);
+
+  /**
+   * Whether this stream is a broadcast stream.
+   */
+  bool get isBroadcast => false;
+
+  /**
+   * Returns a multi-subscription stream that produces the same events as this.
+   *
+   * The returned stream will subscribe to this stream when its first
+   * subscriber is added, and will stay subscribed until this stream ends,
+   * or a callback cancels the subscription.
+   *
+   * If [onListen] is provided, it is called with a subscription-like object
+   * that represents the underlying subscription to this stream. It is
+   * possible to pause, resume or cancel the subscription during the call
+   * to [onListen]. It is not possible to change the event handlers, including
+   * using [StreamSubscription.asFuture].
+   *
+   * If [onCancel] is provided, it is called in a similar way to [onListen]
+   * when the returned stream stops having listener. If it later gets
+   * a new listener, the [onListen] function is called again.
+   *
+   * Use the callbacks, for example, for pausing the underlying subscription
+   * while having no subscribers to prevent losing events, or canceling the
+   * subscription when there are no listeners.
+   */
+  Stream<T> asBroadcastStream(
+      {void onListen(StreamSubscription<T> subscription),
+      void onCancel(StreamSubscription<T> subscription)}) {
+    return new _AsBroadcastStream<T>(this, onListen, onCancel);
+  }
+
+  /**
+   * Adds a subscription to this stream.
+   *
+   * Returns a [StreamSubscription] which handles events from this stream using
+   * the provided [onData], [onError] and [onDone] handlers.
+   * The handlers can be changed on the subscription, but they start out
+   * as the provided functions.
+   *
+   * On each data event from this stream, the subscriber's [onData] handler
+   * is called. If [onData] is `null`, nothing happens.
+   *
+   * On errors from this stream, the [onError] handler is called with the
+   * error object and possibly a stack trace.
+   *
+   * The [onError] callback must be of type `void onError(error)` or
+   * `void onError(error, StackTrace stackTrace)`. If [onError] accepts
+   * two arguments it is called with the error object and the stack trace
+   * (which could be `null` if this stream itself received an error without
+   * stack trace).
+   * Otherwise it is called with just the error object.
+   * If [onError] is omitted, any errors on this stream are considered unhandled,
+   * and will be passed to the current [Zone]'s error handler.
+   * By default unhandled async errors are treated
+   * as if they were uncaught top-level errors.
+   *
+   * If this stream closes and sends a done event, the [onDone] handler is
+   * called. If [onDone] is `null`, nothing happens.
+   *
+   * If [cancelOnError] is true, the subscription is automatically canceled
+   * when the first error event is delivered. The default is `false`.
+   *
+   * While a subscription is paused, or when it has been canceled,
+   * the subscription doesn't receive events and none of the
+   * event handler functions are called.
+   */
+  StreamSubscription<T> listen(void onData(T event),
+      {Function onError, void onDone(), bool cancelOnError});
+
+  /**
+   * Creates a new stream from this stream that discards some elements.
+   *
+   * The new stream sends the same error and done events as this stream,
+   * but it only sends the data events that satisfy the [test].
+   *
+   * If the [test] function throws, the data event is dropped and the
+   * error is emitted on the returned stream instead.
+   *
+   * The returned stream is a broadcast stream if this stream is.
+   * If a broadcast stream is listened to more than once, each subscription
+   * will individually perform the `test`.
+   */
+  Stream<T> where(bool test(T event)) {
+    return new _WhereStream<T>(this, test);
+  }
+
+  /**
+   * Transforms each element of this stream into a new stream event.
+   *
+   * Creates a new stream that converts each element of this stream
+   * to a new value using the [convert] function, and emits the result.
+   *
+   * For each data event, `o`, in this stream, the returned stream
+   * provides a data event with the value `convert(o)`.
+   * If [convert] throws, the returned stream reports it as an error
+   * event instead.
+   *
+   * Error and done events are passed through unchanged to the returned stream.
+   *
+   * The returned stream is a broadcast stream if this stream is.
+   * The [convert] function is called once per data event per listener.
+   * If a broadcast stream is listened to more than once, each subscription
+   * will individually call [convert] on each data event.
+   *
+   * Unlike [transform], this method does not treat the stream as
+   * chunks of a single value. Instead each event is converted independently
+   * of the previous and following events, which may not always be correct.
+   * For example, UTF-8 encoding, or decoding, will give wrong results
+   * if a surrogate pair, or a multibyte UTF-8 encoding, is split into
+   * separate events, and those events are attempted encoded or decoded
+   * independently.
+   */
+  Stream<S> map<S>(S convert(T event)) {
+    return new _MapStream<T, S>(this, convert);
+  }
+
+  /**
+   * Creates a new stream with each data event of this stream asynchronously
+   * mapped to a new event.
+   *
+   * This acts like [map], except that [convert] may return a [Future],
+   * and in that case, this stream waits for that future to complete before
+   * continuing with its result.
+   *
+   * The returned stream is a broadcast stream if this stream is.
+   */
+  Stream<E> asyncMap<E>(FutureOr<E> convert(T event)) {
+    _StreamControllerBase<E> controller;
+    StreamSubscription<T> subscription;
+
+    void onListen() {
+      final add = controller.add;
+      assert(controller is _StreamController<E> ||
+          controller is _BroadcastStreamController);
+      final addError = controller._addError;
+      subscription = this.listen((T event) {
+        FutureOr<E> newValue;
+        try {
+          newValue = convert(event);
+        } catch (e, s) {
+          controller.addError(e, s);
+          return;
+        }
+        if (newValue is Future<E>) {
+          subscription.pause();
+          newValue
+              .then(add, onError: addError)
+              .whenComplete(subscription.resume);
+        } else {
+          controller.add(newValue);
+        }
+      }, onError: addError, onDone: controller.close);
+    }
+
+    if (this.isBroadcast) {
+      controller = new StreamController<E>.broadcast(
+          onListen: onListen,
+          onCancel: () {
+            subscription.cancel();
+          },
+          sync: true);
+    } else {
+      controller = new StreamController<E>(
+          onListen: onListen,
+          onPause: () {
+            subscription.pause();
+          },
+          onResume: () {
+            subscription.resume();
+          },
+          onCancel: () => subscription.cancel(),
+          sync: true);
+    }
+    return controller.stream;
+  }
+
+  /**
+   * Transforms each element into a sequence of asynchronous events.
+   *
+   * Returns a new stream and for each event of this stream, do the following:
+   *
+   * * If the event is an error event or a done event, it is emitted directly
+   * by the returned stream.
+   * * Otherwise it is an element. Then the [convert] function is called
+   * with the element as argument to produce a convert-stream for the element.
+   * * If that call throws, the error is emitted on the returned stream.
+   * * If the call returns `null`, no further action is taken for the elements.
+   * * Otherwise, this stream is paused and convert-stream is listened to.
+   * Every data and error event of the convert-stream is emitted on the returned
+   * stream in the order it is produced.
+   * When the convert-stream ends, this stream is resumed.
+   *
+   * The returned stream is a broadcast stream if this stream is.
+   */
+  Stream<E> asyncExpand<E>(Stream<E> convert(T event)) {
+    _StreamControllerBase<E> controller;
+    StreamSubscription<T> subscription;
+    void onListen() {
+      assert(controller is _StreamController ||
+          controller is _BroadcastStreamController);
+      subscription = this.listen((T event) {
+        Stream<E> newStream;
+        try {
+          newStream = convert(event);
+        } catch (e, s) {
+          controller.addError(e, s);
+          return;
+        }
+        if (newStream != null) {
+          subscription.pause();
+          controller.addStream(newStream).whenComplete(subscription.resume);
+        }
+      },
+          onError: controller._addError, // Avoid Zone error replacement.
+          onDone: controller.close);
+    }
+
+    if (this.isBroadcast) {
+      controller = new StreamController<E>.broadcast(
+          onListen: onListen,
+          onCancel: () {
+            subscription.cancel();
+          },
+          sync: true);
+    } else {
+      controller = new StreamController<E>(
+          onListen: onListen,
+          onPause: () {
+            subscription.pause();
+          },
+          onResume: () {
+            subscription.resume();
+          },
+          onCancel: () => subscription.cancel(),
+          sync: true);
+    }
+    return controller.stream;
+  }
+
+  /**
+   * Creates a wrapper Stream that intercepts some errors from this stream.
+   *
+   * If this stream sends an error that matches [test], then it is intercepted
+   * by the [onError] function.
+   *
+   * The [onError] callback must be of type `void onError(error)` or
+   * `void onError(error, StackTrace stackTrace)`.
+   * The function type determines whether [onError] is invoked with a stack
+   * trace argument.
+   * The stack trace argument may be `null` if this stream received an error
+   * without a stack trace.
+   *
+   * An asynchronous error `error` is matched by a test function if
+   *`test(error)` returns true. If [test] is omitted, every error is considered
+   * matching.
+   *
+   * If the error is intercepted, the [onError] function can decide what to do
+   * with it. It can throw if it wants to raise a new (or the same) error,
+   * or simply return to make this stream forget the error.
+   * If the received `error` value is thrown again by the [onError] function,
+   * it acts like a `rethrow` and it is emitted along with its original
+   * stack trace, not the stack trace of the `throw` inside [onError].
+   *
+   * If you need to transform an error into a data event, use the more generic
+   * [Stream.transform] to handle the event by writing a data event to
+   * the output sink.
+   *
+   * The returned stream is a broadcast stream if this stream is.
+   * If a broadcast stream is listened to more than once, each subscription
+   * will individually perform the `test` and handle the error.
+   */
+  Stream<T> handleError(Function onError, {bool test(error)}) {
+    return new _HandleErrorStream<T>(this, onError, test);
+  }
+
+  /**
+   * Transforms each element of this stream into a sequence of elements.
+   *
+   * Returns a new stream where each element of this stream is replaced
+   * by zero or more data events.
+   * The event values are provided as an [Iterable] by a call to [convert]
+   * with the element as argument, and the elements of that iterable is
+   * emitted in iteration order.
+   * If calling [convert] throws, or if the iteration of the returned values
+   * throws, the error is emitted on the returned stream and iteration ends
+   * for that element of this stream.
+   *
+   * Error events and the done event of this stream are forwarded directly
+   * to the returned stream.
+   *
+   * The returned stream is a broadcast stream if this stream is.
+   * If a broadcast stream is listened to more than once, each subscription
+   * will individually call `convert` and expand the events.
+   */
+  Stream<S> expand<S>(Iterable<S> convert(T element)) {
+    return new _ExpandStream<T, S>(this, convert);
+  }
+
+  /**
+   * Pipes the events of this stream into [streamConsumer].
+   *
+   * All events of this stream are added to `streamConsumer` using
+   * [StreamConsumer.addStream].
+   * The `streamConsumer` is closed when this stream has been successfully added
+   * to it - when the future returned by `addStream` completes without an error.
+   *
+   * Returns a future which completes when this stream has been consumed
+   * and the consumer has been closed.
+   *
+   * The returned future completes with the same result as the future returned
+   * by [StreamConsumer.close].
+   * If the call to [StreamConsumer.addStream] fails in some way, this
+   * method fails in the same way.
+   */
+  Future pipe(StreamConsumer<T> streamConsumer) {
+    return streamConsumer.addStream(this).then((_) => streamConsumer.close());
+  }
+
+  /**
+   * Applies  [streamTransformer] to this stream.
+   *
+   * Returns the transformed stream,
+   * that is, the result of `streamTransformer.bind(this)`.
+   * This method simply allows writing the call to `streamTransformer.bind`
+   * in a chained fashion, like
+   * ```
+   * stream.map(mapping).transform(transformation).toList()
+   * ```
+   * which can be more convenient than calling `bind` directly.
+   *
+   * The [streamTransformer] can return any stream.
+   * Whether the returned stream is a broadcast stream or not,
+   * and which elements it will contain,
+   * is entirely up to the transformation.
+   *
+   * This method should always be used for transformations which treat
+   * the entire stream as representing a single value
+   * which has perhaps been split into several parts for transport,
+   * like a file being read from disk or being fetched over a network.
+   * The transformation will then produce a new stream which
+   * transforms the stream's value incrementally (perhaps using
+   * [Converter.startChunkedConversion]). The resulting stream
+   * may again be chunks of the result, but does not have to
+   * correspond to specific events from the source string.
+   */
+  Stream<S> transform<S>(StreamTransformer<T, S> streamTransformer) {
+    return streamTransformer.bind(this);
+  }
+
+  /**
+   * Combines a sequence of values by repeatedly applying [combine].
+   *
+   * Similar to [Iterable.reduce], this function maintains a value,
+   * starting with the first element of this stream
+   * and updated for each further element of this stream.
+   * For each element after the first,
+   * the value is updated to the result of calling [combine]
+   * with the previous value and the element.
+   *
+   * When this stream is done, the returned future is completed with
+   * the value at that time.
+   *
+   * If this stream is empty, the returned future is completed with
+   * an error.
+   * If this stream emits an error, or the call to [combine] throws,
+   * the returned future is completed with that error,
+   * and processing is stopped.
+   */
+  Future<T> reduce(T combine(T previous, T element)) {
+    _Future<T> result = new _Future<T>();
+    bool seenFirst = false;
+    T value;
+    StreamSubscription subscription;
+    subscription = this.listen(
+        (T element) {
+          if (seenFirst) {
+            _runUserCode(() => combine(value, element), (T newValue) {
+              value = newValue;
+            }, _cancelAndErrorClosure(subscription, result));
+          } else {
+            value = element;
+            seenFirst = true;
+          }
+        },
+        onError: result._completeError,
+        onDone: () {
+          if (!seenFirst) {
+            try {
+              // Throw and recatch, instead of just doing
+              //  _completeWithErrorCallback, e, theError, StackTrace.current),
+              // to ensure that the stackTrace is set on the error.
+              throw IterableElementError.noElement();
+            } catch (e, s) {
+              _completeWithErrorCallback(result, e, s);
+            }
+          } else {
+            result._complete(value);
+          }
+        },
+        cancelOnError: true);
+    return result;
+  }
+
+  /**
+   * Combines a sequence of values by repeatedly applying [combine].
+   *
+   * Similar to [Iterable.fold], this function maintains a value,
+   * starting with [initialValue] and updated for each element of
+   * this stream.
+   * For each element, the value is updated to the result of calling
+   * [combine] with the previous value and the element.
+   *
+   * When this stream is done, the returned future is completed with
+   * the value at that time.
+   * For an empty stream, the future is completed with [initialValue].
+   *
+   * If this stream emits an error, or the call to [combine] throws,
+   * the returned future is completed with that error,
+   * and processing is stopped.
+   */
+  Future<S> fold<S>(S initialValue, S combine(S previous, T element)) {
+    _Future<S> result = new _Future<S>();
+    S value = initialValue;
+    StreamSubscription subscription;
+    subscription = this.listen(
+        (T element) {
+          _runUserCode(() => combine(value, element), (S newValue) {
+            value = newValue;
+          }, _cancelAndErrorClosure(subscription, result));
+        },
+        onError: result._completeError,
+        onDone: () {
+          result._complete(value);
+        },
+        cancelOnError: true);
+    return result;
+  }
+
+  /**
+   * Combines the string representation of elements into a single string.
+   *
+   * Each element is converted to a string using its [Object.toString] method.
+   * If [separator] is provided, it is inserted between element string
+   * representations.
+   *
+   * The returned future is completed with the combined string when this stream
+   * is done.
+   *
+   * If this stream emits an error, or the call to [Object.toString] throws,
+   * the returned future is completed with that error,
+   * and processing stops.
+   */
+  Future<String> join([String separator = ""]) {
+    _Future<String> result = new _Future<String>();
+    StringBuffer buffer = new StringBuffer();
+    StreamSubscription subscription;
+    bool first = true;
+    subscription = this.listen(
+        (T element) {
+          if (!first) {
+            buffer.write(separator);
+          }
+          first = false;
+          try {
+            buffer.write(element);
+          } catch (e, s) {
+            _cancelAndErrorWithReplacement(subscription, result, e, s);
+          }
+        },
+        onError: result._completeError,
+        onDone: () {
+          result._complete(buffer.toString());
+        },
+        cancelOnError: true);
+    return result;
+  }
+
+  /**
+   * Returns whether [needle] occurs in the elements provided by this stream.
+   *
+   * Compares each element of this stream to [needle] using [Object.==].
+   * If an equal element is found, the returned future is completed with `true`.
+   * If this stream ends without finding a match, the future is completed with
+   * `false`.
+   *
+   * If this stream emits an error, or the call to [Object.==] throws,
+   * the returned future is completed with that error,
+   * and processing stops.
+   */
+  Future<bool> contains(Object needle) {
+    _Future<bool> future = new _Future<bool>();
+    StreamSubscription subscription;
+    subscription = this.listen(
+        (T element) {
+          _runUserCode(() => (element == needle), (bool isMatch) {
+            if (isMatch) {
+              _cancelAndValue(subscription, future, true);
+            }
+          }, _cancelAndErrorClosure(subscription, future));
+        },
+        onError: future._completeError,
+        onDone: () {
+          future._complete(false);
+        },
+        cancelOnError: true);
+    return future;
+  }
+
+  /**
+   * Executes [action] on each element of this stream.
+   *
+   * Completes the returned [Future] when all elements of this stream
+   * have been processed.
+   *
+   * If this stream emits an error, or if the call to [action] throws,
+   * the returned future completes with that error,
+   * and processing stops.
+   */
+  Future forEach(void action(T element)) {
+    _Future future = new _Future();
+    StreamSubscription subscription;
+    subscription = this.listen(
+        (T element) {
+          // TODO(floitsch): the type should be 'void' and inferred.
+          _runUserCode<dynamic>(() => action(element), (_) {},
+              _cancelAndErrorClosure(subscription, future));
+        },
+        onError: future._completeError,
+        onDone: () {
+          future._complete(null);
+        },
+        cancelOnError: true);
+    return future;
+  }
+
+  /**
+   * Checks whether [test] accepts all elements provided by this stream.
+   *
+   * Calls [test] on each element of this stream.
+   * If the call returns `false`, the returned future is completed with `false`
+   * and processing stops.
+   *
+   * If this stream ends without finding an element that [test] rejects,
+   * the returned future is completed with `true`.
+   *
+   * If this stream emits an error, or if the call to [test] throws,
+   * the returned future is completed with that error,
+   * and processing stops.
+   */
+  Future<bool> every(bool test(T element)) {
+    _Future<bool> future = new _Future<bool>();
+    StreamSubscription subscription;
+    subscription = this.listen(
+        (T element) {
+          _runUserCode(() => test(element), (bool isMatch) {
+            if (!isMatch) {
+              _cancelAndValue(subscription, future, false);
+            }
+          }, _cancelAndErrorClosure(subscription, future));
+        },
+        onError: future._completeError,
+        onDone: () {
+          future._complete(true);
+        },
+        cancelOnError: true);
+    return future;
+  }
+
+  /**
+   * Checks whether [test] accepts any element provided by this stream.
+   *
+   * Calls [test] on each element of this stream.
+   * If the call returns `true`, the returned future is completed with `true`
+   * and processing stops.
+   *
+   * If this stream ends without finding an element that [test] accepts,
+   * the returned future is completed with `false`.
+   *
+   * If this stream emits an error, or if the call to [test] throws,
+   * the returned future is completed with that error,
+   * and processing stops.
+   */
+  Future<bool> any(bool test(T element)) {
+    _Future<bool> future = new _Future<bool>();
+    StreamSubscription subscription;
+    subscription = this.listen(
+        (T element) {
+          _runUserCode(() => test(element), (bool isMatch) {
+            if (isMatch) {
+              _cancelAndValue(subscription, future, true);
+            }
+          }, _cancelAndErrorClosure(subscription, future));
+        },
+        onError: future._completeError,
+        onDone: () {
+          future._complete(false);
+        },
+        cancelOnError: true);
+    return future;
+  }
+
+  /**
+   * The number of elements in this stream.
+   *
+   * Waits for all elements of this stream. When this stream ends,
+   * the returned future is completed with the number of elements.
+   *
+   * If this stream emits an error,
+   * the returned future is completed with that error,
+   * and processing stops.
+   *
+   * This operation listens to this stream, and a non-broadcast stream cannot
+   * be reused after finding its length.
+   */
+  Future<int> get length {
+    _Future<int> future = new _Future<int>();
+    int count = 0;
+    this.listen(
+        (_) {
+          count++;
+        },
+        onError: future._completeError,
+        onDone: () {
+          future._complete(count);
+        },
+        cancelOnError: true);
+    return future;
+  }
+
+  /**
+   * Whether this stream contains any elements.
+   *
+   * Waits for the first element of this stream, then completes the returned
+   * future with `true`.
+   * If this stream ends without emitting any elements, the returned future is
+   * completed with `false`.
+   *
+   * If the first event is an error, the returned future is completed with that
+   * error.
+   *
+   * This operation listens to this stream, and a non-broadcast stream cannot
+   * be reused after checking whether it is empty.
+   */
+  Future<bool> get isEmpty {
+    _Future<bool> future = new _Future<bool>();
+    StreamSubscription subscription;
+    subscription = this.listen(
+        (_) {
+          _cancelAndValue(subscription, future, false);
+        },
+        onError: future._completeError,
+        onDone: () {
+          future._complete(true);
+        },
+        cancelOnError: true);
+    return future;
+  }
+
+  /**
+   * Adapt this stream to be a `Stream<R>`.
+   *
+   * This stream is wrapped as a `Stream<R>` which checks at run-time that
+   * each data event emitted by this stream is also an instance of [R].
+   */
+  Stream<R> cast<R>() => Stream.castFrom<T, R>(this);
+  /**
+   * Collects all elements of this stream in a [List].
+   *
+   * Creates a `List<T>` and adds all elements of this stream to the list
+   * in the order they arrive.
+   * When this stream ends, the returned future is completed with that list.
+   *
+   * If this stream emits an error,
+   * the returned future is completed with that error,
+   * and processing stops.
+   */
+  Future<List<T>> toList() {
+    List<T> result = <T>[];
+    _Future<List<T>> future = new _Future<List<T>>();
+    this.listen(
+        (T data) {
+          result.add(data);
+        },
+        onError: future._completeError,
+        onDone: () {
+          future._complete(result);
+        },
+        cancelOnError: true);
+    return future;
+  }
+
+  /**
+   * Collects the data of this stream in a [Set].
+   *
+   * Creates a `Set<T>` and adds all elements of this stream to the set.
+   * in the order they arrive.
+   * When this stream ends, the returned future is completed with that set.
+   *
+   * The returned set is the same type as returned by `new Set<T>()`.
+   * If another type of set is needed, either use [forEach] to add each
+   * element to the set, or use
+   * `toList().then((list) => new SomeOtherSet.from(list))`
+   * to create the set.
+   *
+   * If this stream emits an error,
+   * the returned future is completed with that error,
+   * and processing stops.
+   */
+  Future<Set<T>> toSet() {
+    Set<T> result = new Set<T>();
+    _Future<Set<T>> future = new _Future<Set<T>>();
+    this.listen(
+        (T data) {
+          result.add(data);
+        },
+        onError: future._completeError,
+        onDone: () {
+          future._complete(result);
+        },
+        cancelOnError: true);
+    return future;
+  }
+
+  /**
+   * Discards all data on this stream, but signals when it is done or an error
+   * occurred.
+   *
+   * When subscribing using [drain], cancelOnError will be true. This means
+   * that the future will complete with the first error on this stream and then
+   * cancel the subscription.
+   * If this stream emits an error, or the call to [combine] throws,
+   * the returned future is completed with that error,
+   * and processing is stopped.
+   *
+   * In case of a `done` event the future completes with the given
+   * [futureValue].
+   */
+  Future<E> drain<E>([E futureValue]) =>
+      listen(null, cancelOnError: true).asFuture<E>(futureValue);
+
+  /**
+   * Provides at most the first [count] data events of this stream.
+   *
+   * Returns a stream that emits the same events that this stream would
+   * if listened to at the same time,
+   * until either this stream ends or it has emitted [count] data events,
+   * at which point the returned stream is done.
+   *
+   * If this stream produces fewer than [count] data events before it's done,
+   * so will the returned stream.
+   *
+   * Starts listening to this stream when the returned stream is listened to
+   * and stops listening when the first [count] data events have been received.
+   *
+   * This means that if this is a single-subscription (non-broadcast) streams
+   * it cannot be reused after the returned stream has been listened to.
+   *
+   * If this is a broadcast stream, the returned stream is a broadcast stream.
+   * In that case, the events are only counted from the time
+   * the returned stream is listened to.
+   */
+  Stream<T> take(int count) {
+    return new _TakeStream<T>(this, count);
+  }
+
+  /**
+   * Forwards data events while [test] is successful.
+   *
+   * Returns a stream that provides the same events as this stream
+   * until [test] fails for a data event.
+   * The returned stream is done when either this stream is done,
+   * or when this stream first emits a data event that fails [test].
+   *
+   * The `test` call is considered failing if it returns a non-`true` value
+   * or if it throws. If the `test` call throws, the error is emitted as the
+   * last event on the returned streams.
+   *
+   * Stops listening to this stream after the accepted elements.
+   *
+   * Internally the method cancels its subscription after these elements. This
+   * means that single-subscription (non-broadcast) streams are closed and
+   * cannot be reused after a call to this method.
+   *
+   * The returned stream is a broadcast stream if this stream is.
+   * For a broadcast stream, the events are only tested from the time
+   * the returned stream is listened to.
+   */
+  Stream<T> takeWhile(bool test(T element)) {
+    return new _TakeWhileStream<T>(this, test);
+  }
+
+  /**
+   * Skips the first [count] data events from this stream.
+   *
+   * Returns a stream that emits the same events as this stream would
+   * if listened to at the same time, except that the first [count]
+   * data events are not emitted.
+   * The returned stream is done when this stream is.
+   *
+   * If this stream emits fewer than [count] data events
+   * before being done, the returned stream emits no data events.
+   *
+   * The returned stream is a broadcast stream if this stream is.
+   * For a broadcast stream, the events are only counted from the time
+   * the returned stream is listened to.
+   */
+  Stream<T> skip(int count) {
+    return new _SkipStream<T>(this, count);
+  }
+
+  /**
+   * Skip data events from this stream while they are matched by [test].
+   *
+   * Returns a stream that emits the same events as this stream,
+   * except that data events are not emitted until a data event fails `test`.
+   * The test fails when called with a data event
+   * if it returns a non-`true` value or if the call to `test` throws.
+   * If the call throws, the error is emitted as an error event
+   * on the returned stream instead of the data event,
+   * otherwise the event that made `test` return non-true is emitted as the
+   * first data event.
+   *
+   * Error and done events are provided by the returned stream unmodified.
+   *
+   * The returned stream is a broadcast stream if this stream is.
+   * For a broadcast stream, the events are only tested from the time
+   * the returned stream is listened to.
+   */
+  Stream<T> skipWhile(bool test(T element)) {
+    return new _SkipWhileStream<T>(this, test);
+  }
+
+  /**
+   * Skips data events if they are equal to the previous data event.
+   *
+   * The returned stream provides the same events as this stream, except
+   * that it never provides two consecutive data events that are equal.
+   * That is, errors are passed through to the returned stream, and
+   * data events are passed through if they are distinct from the most
+   * recently emitted data event.
+   *
+   * Equality is determined by the provided [equals] method. If that is
+   * omitted, the '==' operator on the last provided data element is used.
+   *
+   * If [equals] throws, the data event is replaced by an error event
+   * containing the thrown error. The behavior is equivalent to the
+   * original stream emitting the error event, and it doesn't change
+   * the what the most recently emitted data event is.
+   *
+   * The returned stream is a broadcast stream if this stream is.
+   * If a broadcast stream is listened to more than once, each subscription
+   * will individually perform the `equals` test.
+   */
+  Stream<T> distinct([bool equals(T previous, T next)]) {
+    return new _DistinctStream<T>(this, equals);
+  }
+
+  /**
+   * The first element of this stream.
+   *
+   * Stops listening to this stream after the first element has been received.
+   *
+   * Internally the method cancels its subscription after the first element.
+   * This means that single-subscription (non-broadcast) streams are closed
+   * and cannot be reused after a call to this getter.
+   *
+   * If an error event occurs before the first data event, the returned future
+   * is completed with that error.
+   *
+   * If this stream is empty (a done event occurs before the first data event),
+   * the returned future completes with an error.
+   *
+   * Except for the type of the error, this method is equivalent to
+   * `this.elementAt(0)`.
+   */
+  Future<T> get first {
+    _Future<T> future = new _Future<T>();
+    StreamSubscription subscription;
+    subscription = this.listen(
+        (T value) {
+          _cancelAndValue(subscription, future, value);
+        },
+        onError: future._completeError,
+        onDone: () {
+          try {
+            throw IterableElementError.noElement();
+          } catch (e, s) {
+            _completeWithErrorCallback(future, e, s);
+          }
+        },
+        cancelOnError: true);
+    return future;
+  }
+
+  /**
+   * The last element of this stream.
+   *
+   * If this stream emits an error event,
+   * the returned future is completed with that error
+   * and processing stops.
+   *
+   * If this stream is empty (the done event is the first event),
+   * the returned future completes with an error.
+   */
+  Future<T> get last {
+    _Future<T> future = new _Future<T>();
+    T result;
+    bool foundResult = false;
+    listen(
+        (T value) {
+          foundResult = true;
+          result = value;
+        },
+        onError: future._completeError,
+        onDone: () {
+          if (foundResult) {
+            future._complete(result);
+            return;
+          }
+          try {
+            throw IterableElementError.noElement();
+          } catch (e, s) {
+            _completeWithErrorCallback(future, e, s);
+          }
+        },
+        cancelOnError: true);
+    return future;
+  }
+
+  /**
+   * The single element of this stream.
+   *
+   * If this stream emits an error event,
+   * the returned future is completed with that error
+   * and processing stops.
+   *
+   * If [this] is empty or has more than one element,
+   * the returned future completes with an error.
+   */
+  Future<T> get single {
+    _Future<T> future = new _Future<T>();
+    T result;
+    bool foundResult = false;
+    StreamSubscription subscription;
+    subscription = this.listen(
+        (T value) {
+          if (foundResult) {
+            // This is the second element we get.
+            try {
+              throw IterableElementError.tooMany();
+            } catch (e, s) {
+              _cancelAndErrorWithReplacement(subscription, future, e, s);
+            }
+            return;
+          }
+          foundResult = true;
+          result = value;
+        },
+        onError: future._completeError,
+        onDone: () {
+          if (foundResult) {
+            future._complete(result);
+            return;
+          }
+          try {
+            throw IterableElementError.noElement();
+          } catch (e, s) {
+            _completeWithErrorCallback(future, e, s);
+          }
+        },
+        cancelOnError: true);
+    return future;
+  }
+
+  /**
+   * Finds the first element of this stream matching [test].
+   *
+   * Returns a future that is completed with the first element of this stream
+   * that [test] returns `true` for.
+   *
+   * If no such element is found before this stream is done, and a
+   * [orElse] function is provided, the result of calling [orElse]
+   * becomes the value of the future. If [orElse] throws, the returned
+   * future is completed with that error.
+   *
+   * If this stream emits an error before the first matching element,
+   * the returned future is completed with that error, and processing stops.
+   *
+   * Stops listening to this stream after the first matching element or error
+   * has been received.
+   *
+   * Internally the method cancels its subscription after the first element that
+   * matches the predicate. This means that single-subscription (non-broadcast)
+   * streams are closed and cannot be reused after a call to this method.
+   *
+   * If an error occurs, or if this stream ends without finding a match and
+   * with no [orElse] function provided,
+   * the returned future is completed with an error.
+   */
+  Future<T> firstWhere(bool test(T element), {T orElse()}) {
+    _Future<T> future = new _Future();
+    StreamSubscription subscription;
+    subscription = this.listen(
+        (T value) {
+          _runUserCode(() => test(value), (bool isMatch) {
+            if (isMatch) {
+              _cancelAndValue(subscription, future, value);
+            }
+          }, _cancelAndErrorClosure(subscription, future));
+        },
+        onError: future._completeError,
+        onDone: () {
+          if (orElse != null) {
+            _runUserCode(orElse, future._complete, future._completeError);
+            return;
+          }
+          try {
+            throw IterableElementError.noElement();
+          } catch (e, s) {
+            _completeWithErrorCallback(future, e, s);
+          }
+        },
+        cancelOnError: true);
+    return future;
+  }
+
+  /**
+   * Finds the last element in this stream matching [test].
+   *
+   * If this stream emits an error, the returned future is completed with that
+   * error, and processing stops.
+   *
+   * Otherwise as [firstWhere], except that the last matching element is found
+   * instead of the first.
+   * That means that a non-error result cannot be provided before this stream
+   * is done.
+   */
+  Future<T> lastWhere(bool test(T element), {T orElse()}) {
+    _Future<T> future = new _Future();
+    T result;
+    bool foundResult = false;
+    StreamSubscription subscription;
+    subscription = this.listen(
+        (T value) {
+          _runUserCode(() => true == test(value), (bool isMatch) {
+            if (isMatch) {
+              foundResult = true;
+              result = value;
+            }
+          }, _cancelAndErrorClosure(subscription, future));
+        },
+        onError: future._completeError,
+        onDone: () {
+          if (foundResult) {
+            future._complete(result);
+            return;
+          }
+          if (orElse != null) {
+            _runUserCode(orElse, future._complete, future._completeError);
+            return;
+          }
+          try {
+            throw IterableElementError.noElement();
+          } catch (e, s) {
+            _completeWithErrorCallback(future, e, s);
+          }
+        },
+        cancelOnError: true);
+    return future;
+  }
+
+  /**
+   * Finds the single element in this stream matching [test].
+   *
+   * Like [lastWhere], except that it is an error if more than one
+   * matching element occurs in this stream.
+   */
+  Future<T> singleWhere(bool test(T element), {T orElse()}) {
+    _Future<T> future = new _Future<T>();
+    T result;
+    bool foundResult = false;
+    StreamSubscription subscription;
+    subscription = this.listen(
+        (T value) {
+          _runUserCode(() => true == test(value), (bool isMatch) {
+            if (isMatch) {
+              if (foundResult) {
+                try {
+                  throw IterableElementError.tooMany();
+                } catch (e, s) {
+                  _cancelAndErrorWithReplacement(subscription, future, e, s);
+                }
+                return;
+              }
+              foundResult = true;
+              result = value;
+            }
+          }, _cancelAndErrorClosure(subscription, future));
+        },
+        onError: future._completeError,
+        onDone: () {
+          if (foundResult) {
+            future._complete(result);
+            return;
+          }
+          try {
+            if (orElse != null) {
+              _runUserCode(orElse, future._complete, future._completeError);
+              return;
+            }
+            throw IterableElementError.noElement();
+          } catch (e, s) {
+            _completeWithErrorCallback(future, e, s);
+          }
+        },
+        cancelOnError: true);
+    return future;
+  }
+
+  /**
+   * Returns the value of the [index]th data event of this stream.
+   *
+   * Stops listening to this stream after the [index]th data event has been
+   * received.
+   *
+   * Internally the method cancels its subscription after these elements. This
+   * means that single-subscription (non-broadcast) streams are closed and
+   * cannot be reused after a call to this method.
+   *
+   * If an error event occurs before the value is found, the future completes
+   * with this error.
+   *
+   * If a done event occurs before the value is found, the future completes
+   * with a [RangeError].
+   */
+  Future<T> elementAt(int index) {
+    ArgumentError.checkNotNull(index, "index");
+    RangeError.checkNotNegative(index, "index");
+    _Future<T> future = new _Future<T>();
+    StreamSubscription subscription;
+    int elementIndex = 0;
+    subscription = this.listen(
+        (T value) {
+          if (index == elementIndex) {
+            _cancelAndValue(subscription, future, value);
+            return;
+          }
+          elementIndex += 1;
+        },
+        onError: future._completeError,
+        onDone: () {
+          future._completeError(
+              new RangeError.index(index, this, "index", null, elementIndex));
+        },
+        cancelOnError: true);
+    return future;
+  }
+
+  /**
+   * Creates a new stream with the same events as this stream.
+   *
+   * Whenever more than [timeLimit] passes between two events from this stream,
+   * the [onTimeout] function is called, which can emit further events on
+   * the returned stream.
+   *
+   * The countdown doesn't start until the returned stream is listened to.
+   * The countdown is reset every time an event is forwarded from this stream,
+   * or when this stream is paused and resumed.
+   *
+   * The [onTimeout] function is called with one argument: an
+   * [EventSink] that allows putting events into the returned stream.
+   * This `EventSink` is only valid during the call to [onTimeout].
+   * Calling [EventSink.close] on the sink passed to [onTimeout] closes the
+   * returned stream, and no further events are processed.
+   *
+   * If [onTimeout] is omitted, a timeout will just put a [TimeoutException]
+   * into the error channel of the returned stream.
+   * If the call to [onTimeout] throws, the error is emitted on the returned
+   * stream.
+   *
+   * The returned stream is a broadcast stream if this stream is.
+   * If a broadcast stream is listened to more than once, each subscription
+   * will have its individually timer that starts counting on listen,
+   * and the subscriptions' timers can be paused individually.
+   */
+  Stream<T> timeout(Duration timeLimit, {void onTimeout(EventSink<T> sink)}) {
+    _StreamControllerBase<T> controller;
+    // The following variables are set on listen.
+    StreamSubscription<T> subscription;
+    Timer timer;
+    Zone zone;
+    _TimerCallback timeout;
+
+    void onData(T event) {
+      timer.cancel();
+      timer = zone.createTimer(timeLimit, timeout);
+      // It might close the stream and cancel timer, so create recuring Timer
+      // before calling into add();
+      // issue: https://github.com/dart-lang/sdk/issues/37565
+      controller.add(event);
+    }
+
+    void onError(error, StackTrace stackTrace) {
+      timer.cancel();
+      assert(controller is _StreamController ||
+          controller is _BroadcastStreamController);
+      controller._addError(error, stackTrace); // Avoid Zone error replacement.
+      timer = zone.createTimer(timeLimit, timeout);
+    }
+
+    void onDone() {
+      timer.cancel();
+      controller.close();
+    }
+
+    void onListen() {
+      // This is the onListen callback for of controller.
+      // It runs in the same zone that the subscription was created in.
+      // Use that zone for creating timers and running the onTimeout
+      // callback.
+      zone = Zone.current;
+      if (onTimeout == null) {
+        timeout = () {
+          controller.addError(
+              new TimeoutException("No stream event", timeLimit), null);
+        };
+      } else {
+        // TODO(floitsch): the return type should be 'void', and the type
+        // should be inferred.
+        var registeredOnTimeout =
+            zone.registerUnaryCallback<dynamic, EventSink<T>>(onTimeout);
+        var wrapper = new _ControllerEventSinkWrapper<T>(null);
+        timeout = () {
+          wrapper._sink = controller; // Only valid during call.
+          zone.runUnaryGuarded(registeredOnTimeout, wrapper);
+          wrapper._sink = null;
+        };
+      }
+
+      subscription = this.listen(onData, onError: onError, onDone: onDone);
+      timer = zone.createTimer(timeLimit, timeout);
+    }
+
+    Future onCancel() {
+      timer.cancel();
+      Future result = subscription.cancel();
+      subscription = null;
+      return result;
+    }
+
+    controller = isBroadcast
+        ? new _SyncBroadcastStreamController<T>(onListen, onCancel)
+        : new _SyncStreamController<T>(onListen, () {
+            // Don't null the timer, onCancel may call cancel again.
+            timer.cancel();
+            subscription.pause();
+          }, () {
+            subscription.resume();
+            timer = zone.createTimer(timeLimit, timeout);
+          }, onCancel);
+    return controller.stream;
+  }
+}
+
+/**
+ * A subscription on events from a [Stream].
+ *
+ * When you listen on a [Stream] using [Stream.listen],
+ * a [StreamSubscription] object is returned.
+ *
+ * The subscription provides events to the listener,
+ * and holds the callbacks used to handle the events.
+ * The subscription can also be used to unsubscribe from the events,
+ * or to temporarily pause the events from the stream.
+ */
+abstract class StreamSubscription<T> {
+  /**
+   * Cancels this subscription.
+   *
+   * After this call, the subscription no longer receives events.
+   *
+   * The stream may need to shut down the source of events and clean up after
+   * the subscription is canceled.
+   *
+   * Returns a future that is completed once the stream has finished
+   * its cleanup.
+   *
+   * For historical reasons, may also return `null` if no cleanup was necessary.
+   * Returning `null` is deprecated and should be avoided.
+   *
+   * Typically, futures are returned when the stream needs to release resources.
+   * For example, a stream might need to close an open file (as an asynchronous
+   * operation). If the listener wants to delete the file after having
+   * canceled the subscription, it must wait for the cleanup future to complete.
+   *
+   * A returned future completes with a `null` value.
+   * If the cleanup throws, which it really shouldn't, the returned future
+   * completes with that error.
+   */
+  Future cancel();
+
+  /**
+   * Replaces the data event handler of this subscription.
+   *
+   * The [handleData] function is called for each element of the stream
+   * after this function is called.
+   * If [handleData] is `null`, further elements are ignored.
+   *
+   * This method replaces the current handler set by the invocation of
+   * [Stream.listen] or by a previous call to [onData].
+   */
+  void onData(void handleData(T data));
+
+  /**
+   * Replaces the error event handler of this subscription.
+   *
+   * The [handleError] function must be able to be called with either
+   * one positional argument, or with two positional arguments
+   * where the seconds is always a [StackTrace].
+   *
+   * The [handleError] argument may be `null`, in which case further
+   * error events are considered unhandled, and will be reported to
+   * [Zone.handleUncaughtError].
+   *
+   * The provided function is called for all error events from the
+   * stream subscription.
+   *
+   * This method replaces the current handler set by the invocation of
+   * [Stream.listen], by calling [asFuture], or by a previous call to [onError].
+   */
+  void onError(Function handleError);
+
+  /**
+   * Replaces the done event handler of this subscription.
+   *
+   * The [handleDone] function is called when the stream closes.
+   * The value may be `null`, in which case no function is called.
+   *
+   * This method replaces the current handler set by the invocation of
+   * [Stream.listen], by calling [asFuture], or by a previous call to [onDone].
+   */
+  void onDone(void handleDone());
+
+  /**
+   * Request that the stream pauses events until further notice.
+   *
+   * While paused, the subscription will not fire any events.
+   * If it receives events from its source, they will be buffered until
+   * the subscription is resumed.
+   * For non-broadcast streams, the underlying source is usually informed
+   * about the pause,
+   * so it can stop generating events until the subscription is resumed.
+   *
+   * To avoid buffering events on a broadcast stream, it is better to
+   * cancel this subscription, and start to listen again when events
+   * are needed, if the intermediate events are not important.
+   *
+   * If [resumeSignal] is provided, the stream subscription will undo the pause
+   * when the future completes, as if by a call to [resume].
+   * If the future completes with an error,
+   * the stream will still resume, but the error will be considered unhandled
+   * and is passed to [Zone.handleUncaughtError].
+   *
+   * A call to [resume] will also undo a pause.
+   *
+   * If the subscription is paused more than once, an equal number
+   * of resumes must be performed to resume the stream.
+   * Calls to [resume] and the completion of a [resumeSignal] are
+   * interchangeable - the [pause] which was passed a [resumeSignal] may be
+   * ended by a call to [resume], and completing the [resumeSignal] may end a
+   * different [pause].
+   *
+   * It is safe to [resume] or complete a [resumeSignal] even when the
+   * subscription is not paused, and the resume will have no effect.
+   *
+   * Currently DOM streams silently drop events when the stream is paused. This
+   * is a bug and will be fixed.
+   */
+  void pause([Future resumeSignal]);
+
+  /**
+   * Resume after a pause.
+   *
+   * This undoes one previous call to [pause].
+   * When all previously calls to [pause] have been matched by a calls to
+   * [resume], possibly through a `resumeSignal` passed to [pause],
+   * the stream subscription may emit events again.
+   *
+   * It is safe to [resume] even when the subscription is not paused, and the
+   * resume will have no effect.
+   */
+  void resume();
+
+  /**
+   * Whether the [StreamSubscription] is currently paused.
+   *
+   * If there have been more calls to [pause] than to [resume] on this
+   * stream subscription, the subscription is paused, and this getter
+   * returns `true`.
+   *
+   * Returns `false` if the stream can currently emit events, or if
+   * the subscription has completed or been cancelled.
+   */
+  bool get isPaused;
+
+  /**
+   * Returns a future that handles the [onDone] and [onError] callbacks.
+   *
+   * This method *overwrites* the existing [onDone] and [onError] callbacks
+   * with new ones that complete the returned future.
+   *
+   * In case of an error the subscription will automatically cancel (even
+   * when it was listening with `cancelOnError` set to `false`).
+   *
+   * In case of a `done` event the future completes with the given
+   * [futureValue].
+   */
+  Future<E> asFuture<E>([E futureValue]);
+}
+
+/**
+ * A [Sink] that supports adding errors.
+ *
+ * This makes it suitable for capturing the results of asynchronous
+ * computations, which can complete with a value or an error.
+ *
+ * The [EventSink] has been designed to handle asynchronous events from
+ * [Stream]s. See, for example, [Stream.eventTransformed] which uses
+ * `EventSink`s to transform events.
+ */
+abstract class EventSink<T> implements Sink<T> {
+  /**
+   * Adds a data [event] to the sink.
+   *
+   * Must not be called on a closed sink.
+   */
+  void add(T event);
+
+  /**
+   * Adds an [error] to the sink.
+   *
+   * Must not be called on a closed sink.
+   */
+  void addError(Object error, [StackTrace stackTrace]);
+
+  /**
+   * Closes the sink.
+   *
+   * Calling this method more than once is allowed, but does nothing.
+   *
+   * Neither [add] nor [addError] must be called after this method.
+   */
+  void close();
+}
+
+/** [Stream] wrapper that only exposes the [Stream] interface. */
+class StreamView<T> extends Stream<T> {
+  final Stream<T> _stream;
+
+  const StreamView(Stream<T> stream)
+      : _stream = stream,
+        super._internal();
+
+  bool get isBroadcast => _stream.isBroadcast;
+
+  Stream<T> asBroadcastStream(
+          {void onListen(StreamSubscription<T> subscription),
+          void onCancel(StreamSubscription<T> subscription)}) =>
+      _stream.asBroadcastStream(onListen: onListen, onCancel: onCancel);
+
+  StreamSubscription<T> listen(void onData(T value),
+      {Function onError, void onDone(), bool cancelOnError}) {
+    return _stream.listen(onData,
+        onError: onError, onDone: onDone, cancelOnError: cancelOnError);
+  }
+}
+
+/**
+ * Abstract interface for a "sink" accepting multiple entire streams.
+ *
+ * A consumer can accept a number of consecutive streams using [addStream],
+ * and when no further data need to be added, the [close] method tells the
+ * consumer to complete its work and shut down.
+ *
+ * The [Stream.pipe] accepts a `StreamConsumer` and will pass the stream
+ * to the consumer's [addStream] method. When that completes, it will
+ * call [close] and then complete its own returned future.
+ */
+abstract class StreamConsumer<S> {
+  /**
+   * Consumes the elements of [stream].
+   *
+   * Listens on [stream] and does something for each event.
+   *
+   * Returns a future which is completed when the stream is done being added,
+   * and the consumer is ready to accept a new stream.
+   * No further calls to [addStream] or [close] should happen before the
+   * returned future has completed.
+   *
+   * The consumer may stop listening to the stream after an error,
+   * it may consume all the errors and only stop at a done event,
+   * or it may be canceled early if the receiver don't want any further events.
+   *
+   * If the consumer stops listening because of some error preventing it
+   * from continuing, it may report this error in the returned future,
+   * otherwise it will just complete the future with `null`.
+   */
+  Future addStream(Stream<S> stream);
+
+  /**
+   * Tells the consumer that no further streams will be added.
+   *
+   * This allows the consumer to complete any remaining work and release
+   * resources that are no longer needed
+   *
+   * Returns a future which is completed when the consumer has shut down.
+   * If cleaning up can fail, the error may be reported in the returned future,
+   * otherwise it completes with `null`.
+   */
+  Future close();
+}
+
+/**
+ * A object that accepts stream events both synchronously and asynchronously.
+ *
+ * A [StreamSink] combines the methods from [StreamConsumer] and [EventSink].
+ *
+ * The [EventSink] methods can't be used while the [addStream] is called.
+ * As soon as the [addStream]'s [Future] completes with a value, the
+ * [EventSink] methods can be used again.
+ *
+ * If [addStream] is called after any of the [EventSink] methods, it'll
+ * be delayed until the underlying system has consumed the data added by the
+ * [EventSink] methods.
+ *
+ * When [EventSink] methods are used, the [done] [Future] can be used to
+ * catch any errors.
+ *
+ * When [close] is called, it will return the [done] [Future].
+ */
+abstract class StreamSink<S> implements EventSink<S>, StreamConsumer<S> {
+  /**
+   * Tells the stream sink that no further streams will be added.
+   *
+   * This allows the stream sink to complete any remaining work and release
+   * resources that are no longer needed
+   *
+   * Returns a future which is completed when the stream sink has shut down.
+   * If cleaning up can fail, the error may be reported in the returned future,
+   * otherwise it completes with `null`.
+   *
+   * Returns the same future as [done].
+   *
+   * The stream sink may close before the [close] method is called, either due
+   * to an error or because it is itself providing events to someone who has
+   * stopped listening. In that case, the [done] future is completed first,
+   * and the `close` method will return the `done` future when called.
+   *
+   * Unifies [StreamConsumer.close] and [EventSink.close] which both mark their
+   * object as not expecting any further events.
+   */
+  Future close();
+
+  /**
+   * Return a future which is completed when the [StreamSink] is finished.
+   *
+   * If the `StreamSink` fails with an error,
+   * perhaps in response to adding events using [add], [addError] or [close],
+   * the [done] future will complete with that error.
+   *
+   * Otherwise, the returned future will complete when either:
+   *
+   * * all events have been processed and the sink has been closed, or
+   * * the sink has otherwise been stopped from handling more events
+   *   (for example by canceling a stream subscription).
+   */
+  Future get done;
+}
+
+/**
+ * Transforms a Stream.
+ *
+ * When a stream's [Stream.transform] method is invoked with a
+ * [StreamTransformer], the stream calls the [bind] method on the provided
+ * transformer. The resulting stream is then returned from the
+ * [Stream.transform] method.
+ *
+ * Conceptually, a transformer is simply a function from [Stream] to [Stream]
+ * that is encapsulated into a class.
+ *
+ * It is good practice to write transformers that can be used multiple times.
+ *
+ * All other transforming methods on [Stream], such as [Stream.map],
+ * [Stream.where] or [Stream.expand] can be implemented using
+ * [Stream.transform]. A [StreamTransformer] is thus very powerful but often
+ * also a bit more complicated to use.
+ */
+abstract class StreamTransformer<S, T> {
+  /**
+   * Creates a [StreamTransformer] based on the given [onListen] callback.
+   *
+   * The returned stream transformer uses the provided [onListen] callback
+   * when a transformed stream is listened to. At that time, the callback
+   * receives the input stream (the one passed to [bind]) and a
+   * boolean flag `cancelOnError` to create a [StreamSubscription].
+   *
+   * If the transformed stream is a broadcast stream, so is the stream
+   * returned by the [StreamTransformer.bind] method by this transformer.
+   *
+   * If the transformed stream is listened to multiple times, the [onListen]
+   * callback is called again for each new [Stream.listen] call.
+   * This happens whether the stream is a broadcast stream or not,
+   * but the call will usually fail for non-broadcast streams.
+   *
+   * The [onListen] callback does *not* receive the handlers that were passed
+   * to [Stream.listen]. These are automatically set after the call to the
+   * [onListen] callback (using [StreamSubscription.onData],
+   * [StreamSubscription.onError] and [StreamSubscription.onDone]).
+   *
+   * Most commonly, an [onListen] callback will first call [Stream.listen] on
+   * the provided stream (with the corresponding `cancelOnError` flag), and then
+   * return a new [StreamSubscription].
+   *
+   * There are two common ways to create a StreamSubscription:
+   *
+   * 1. by allocating a [StreamController] and to return the result of
+   *    listening to its stream. It's important to forward pause, resume and
+   *    cancel events (unless the transformer intentionally wants to change
+   *    this behavior).
+   * 2. by creating a new class that implements [StreamSubscription].
+   *    Note that the subscription should run callbacks in the [Zone] the
+   *    stream was listened to (see [Zone] and [Zone.bindCallback]).
+   *
+   * Example:
+   *
+   * ```
+   * /// Starts listening to [input] and duplicates all non-error events.
+   * StreamSubscription<int> _onListen(Stream<int> input, bool cancelOnError) {
+   *   StreamSubscription<String> subscription;
+   *   // Create controller that forwards pause, resume and cancel events.
+   *   var controller = new StreamController<String>(
+   *       onPause: () {
+   *         subscription.pause();
+   *       },
+   *       onResume: () {
+   *         subscription.resume();
+   *       },
+   *       onCancel: () => subscription.cancel(),
+   *       sync: true); // "sync" is correct here, since events are forwarded.
+   *
+   *   // Listen to the provided stream using `cancelOnError`.
+   *   subscription = input.listen((data) {
+   *     // Duplicate the data.
+   *     controller.add(data);
+   *     controller.add(data);
+   *   },
+   *       onError: controller.addError,
+   *       onDone: controller.close,
+   *       cancelOnError: cancelOnError);
+   *
+   *   // Return a new [StreamSubscription] by listening to the controller's
+   *   // stream.
+   *   return controller.stream.listen(null);
+   * }
+   *
+   * // Instantiate a transformer:
+   * var duplicator = const StreamTransformer<int, int>(_onListen);
+   *
+   * // Use as follows:
+   * intStream.transform(duplicator);
+   * ```
+   */
+  const factory StreamTransformer(
+          StreamSubscription<T> onListen(
+              Stream<S> stream, bool cancelOnError)) =
+      _StreamSubscriptionTransformer<S, T>;
+
+  /**
+   * Creates a [StreamTransformer] that delegates events to the given functions.
+   *
+   * Example use of a duplicating transformer:
+   *
+   * ```
+   * stringStream.transform(new StreamTransformer<String, String>.fromHandlers(
+   *     handleData: (String value, EventSink<String> sink) {
+   *       sink.add(value);
+   *       sink.add(value);  // Duplicate the incoming events.
+   *     }));
+   * ```
+   *
+   * Transformers that are constructed this way cannot use captured state if
+   * they are used in streams that can be listened to multiple times.
+   * ```
+   * StreamController<String> controller;
+   * controller = new StreamController.broadcast(onListen: () {
+   *   scheduleMicrotask(() {
+   *     controller.addError("Bad");
+   *     controller.addError("Worse");
+   *     controller.addError("Worst");
+   *   });
+   * });
+   * var sharedState = 0;
+   * var transformedStream = controller.stream.transform(
+   *     new StreamTransformer<String>.fromHandlers(
+   *         handleError: (error, stackTrace, sink) {
+   *   sharedState++; // Increment shared error-counter.
+   *   sink.add("Error $sharedState: $error");
+   * }));
+   *
+   * transformedStream.listen(print);
+   * transformedStream.listen(print); // Listen twice.
+   * // Listening twice to the same stream makes the transformer share the same
+   * // state. Instead of having "Error 1: Bad", "Error 2: Worse",
+   * // "Error 3: Worst" as output (each twice for the separate subscriptions),
+   * // this program emits:
+   * // Error 1: Bad
+   * // Error 2: Bad
+   * // Error 3: Worse
+   * // Error 4: Worse
+   * // Error 5: Worst
+   * // Error 6: Worst
+   * ```
+   */
+  factory StreamTransformer.fromHandlers(
+      {void handleData(S data, EventSink<T> sink),
+      void handleError(Object error, StackTrace stackTrace, EventSink<T> sink),
+      void handleDone(EventSink<T> sink)}) = _StreamHandlerTransformer<S, T>;
+
+  /**
+   * Creates a [StreamTransformer] based on a [bind] callback.
+   *
+   * The returned stream transformer uses the [bind] argument to implement the
+   * [StreamTransformer.bind] API and can be used when the transformation is
+   * available as a stream-to-stream function.
+   *
+   * ```dart
+   * final splitDecoded = StreamTransformer<List<int>, String>.fromBind(
+   *     (stream) => stream.transform(utf8.decoder).transform(LineSplitter()));
+   * ```
+   */
+  @Since("2.1")
+  factory StreamTransformer.fromBind(Stream<T> Function(Stream<S>) bind) =
+      _StreamBindTransformer<S, T>;
+
+  /**
+   * Adapts [source] to be a `StreamTransformer<TS, TT>`.
+   *
+   * This allows [source] to be used at the new type, but at run-time it
+   * must satisfy the requirements of both the new type and its original type.
+   *
+   * Data events passed into the returned transformer must also be instances
+   * of [SS], and data events produced by [source] for those events must
+   * also be instances of [TT].
+   */
+  static StreamTransformer<TS, TT> castFrom<SS, ST, TS, TT>(
+      StreamTransformer<SS, ST> source) {
+    return new CastStreamTransformer<SS, ST, TS, TT>(source);
+  }
+
+  /**
+   * Transforms the provided [stream].
+   *
+   * Returns a new stream with events that are computed from events of the
+   * provided [stream].
+   *
+   * The [StreamTransformer] interface is completely generic,
+   * so it cannot say what subclasses do.
+   * Each [StreamTransformer] should document clearly how it transforms the
+   * stream (on the class or variable used to access the transformer),
+   * as well as any differences from the following typical behavior:
+   *
+   * * When the returned stream is listened to, it starts listening to the
+   *   input [stream].
+   * * Subscriptions of the returned stream forward (in a reasonable time)
+   *   a [StreamSubscription.pause] call to the subscription of the input
+   *   [stream].
+   * * Similarly, canceling a subscription of the returned stream eventually
+   *   (in reasonable time) cancels the subscription of the input [stream].
+   *
+   * "Reasonable time" depends on the transformer and stream. Some transformers,
+   * like a "timeout" transformer, might make these operations depend on a
+   * duration. Others might not delay them at all, or just by a microtask.
+   *
+   * Transformers are free to handle errors in any way.
+   * A transformer implementation may choose to propagate errors,
+   * or convert them to other events, or ignore them completely,
+   * but if errors are ignored, it should be documented explicitly.
+   */
+  Stream<T> bind(Stream<S> stream);
+
+  /**
+   * Provides a `StreamTransformer<RS, RT>` view of this stream transformer.
+   *
+   * The resulting transformer will check at run-time that all data events
+   * of the stream it transforms are actually instances of [S],
+   * and it will check that all data events produced by this transformer
+   * are actually instances of [RT].
+   */
+  StreamTransformer<RS, RT> cast<RS, RT>();
+}
+
+/**
+ * Base class for implementing [StreamTransformer].
+ *
+ * Contains default implementations of every method except [bind].
+ */
+abstract class StreamTransformerBase<S, T> implements StreamTransformer<S, T> {
+  const StreamTransformerBase();
+
+  StreamTransformer<RS, RT> cast<RS, RT>() =>
+      StreamTransformer.castFrom<S, T, RS, RT>(this);
+}
+
+/**
+ * An [Iterator] like interface for the values of a [Stream].
+ *
+ * This wraps a [Stream] and a subscription on the stream. It listens
+ * on the stream, and completes the future returned by [moveNext] when the
+ * next value becomes available.
+ *
+ * The stream may be paused between calls to [moveNext].
+ */
+abstract class StreamIterator<T> {
+  /** Create a [StreamIterator] on [stream]. */
+  factory StreamIterator(Stream<T> stream)
+      // TODO(lrn): use redirecting factory constructor when type
+      // arguments are supported.
+      =>
+      new _StreamIterator<T>(stream);
+
+  /**
+   * Wait for the next stream value to be available.
+   *
+   * Returns a future which will complete with either `true` or `false`.
+   * Completing with `true` means that another event has been received and
+   * can be read as [current].
+   * Completing with `false` means that the stream iteration is done and
+   * no further events will ever be available.
+   * The future may complete with an error, if the stream produces an error,
+   * which also ends iteration.
+   *
+   * The function must not be called again until the future returned by a
+   * previous call is completed.
+   */
+  Future<bool> moveNext();
+
+  /**
+   * The current value of the stream.
+   *
+   * Is `null` before the first call to [moveNext] and after a call to
+   * `moveNext` completes with a `false` result or an error.
+   *
+   * When a `moveNext` call completes with `true`, the `current` field holds
+   * the most recent event of the stream, and it stays like that until the next
+   * call to `moveNext`.
+   * Between a call to `moveNext` and when its returned future completes,
+   * the value is unspecified.
+   */
+  T get current;
+
+  /**
+   * Cancels the stream iterator (and the underlying stream subscription) early.
+   *
+   * The stream iterator is automatically canceled if the [moveNext] future
+   * completes with either `false` or an error.
+   *
+   * If you need to stop listening for values before the stream iterator is
+   * automatically closed, you must call [cancel] to ensure that the stream
+   * is properly closed.
+   *
+   * If [moveNext] has been called when the iterator is canceled,
+   * its returned future will complete with `false` as value,
+   * as will all further calls to [moveNext].
+   *
+   * Returns a future if the cancel-operation is not completed synchronously.
+   * Otherwise returns `null`.
+   */
+  Future cancel();
+}
+
+/**
+ * Wraps an [_EventSink] so it exposes only the [EventSink] interface.
+ */
+class _ControllerEventSinkWrapper<T> implements EventSink<T> {
+  EventSink _sink;
+  _ControllerEventSinkWrapper(this._sink);
+
+  void add(T data) {
+    _sink.add(data);
+  }
+
+  void addError(error, [StackTrace stackTrace]) {
+    _sink.addError(error, stackTrace);
+  }
+
+  void close() {
+    _sink.close();
+  }
+}
diff --git a/sdk_nnbd/lib/async/stream_controller.dart b/sdk_nnbd/lib/async/stream_controller.dart
new file mode 100644
index 0000000..34c6adf
--- /dev/null
+++ b/sdk_nnbd/lib/async/stream_controller.dart
@@ -0,0 +1,942 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.async;
+
+// -------------------------------------------------------------------
+// Controller for creating and adding events to a stream.
+// -------------------------------------------------------------------
+
+/**
+ * Type of a stream controller's `onListen`, `onPause` and `onResume` callbacks.
+ */
+typedef void ControllerCallback();
+
+/**
+ * Type of stream controller `onCancel` callbacks.
+ *
+ * The callback may return either `void` or a future.
+ */
+typedef ControllerCancelCallback();
+
+/**
+ * A controller with the stream it controls.
+ *
+ * This controller allows sending data, error and done events on
+ * its [stream].
+ * This class can be used to create a simple stream that others
+ * can listen on, and to push events to that stream.
+ *
+ * It's possible to check whether the stream is paused or not, and whether
+ * it has subscribers or not, as well as getting a callback when either of
+ * these change.
+ */
+abstract class StreamController<T> implements StreamSink<T> {
+  /** The stream that this controller is controlling. */
+  Stream<T> get stream;
+
+  /**
+   * A controller with a [stream] that supports only one single subscriber.
+   *
+   * If [sync] is true, the returned stream controller is a
+   * [SynchronousStreamController], and must be used with the care
+   * and attention necessary to not break the [Stream] contract. If in doubt,
+   * use the non-sync version.
+   *
+   * Using an asynchronous controller will never give the wrong
+   * behavior, but using a synchronous controller incorrectly can cause
+   * otherwise correct programs to break.
+   *
+   * A synchronous controller is only intended for optimizing event
+   * propagation when one asynchronous event immediately triggers another.
+   * It should not be used unless the calls to [add] or [addError]
+   * are guaranteed to occur in places where it won't break `Stream` invariants.
+   *
+   * Use synchronous controllers only to forward (potentially transformed)
+   * events from another stream or a future.
+   *
+   * A Stream should be inert until a subscriber starts listening on it (using
+   * the [onListen] callback to start producing events). Streams should not
+   * leak resources (like websockets) when no user ever listens on the stream.
+   *
+   * The controller buffers all incoming events until a subscriber is
+   * registered, but this feature should only be used in rare circumstances.
+   *
+   * The [onPause] function is called when the stream becomes
+   * paused. [onResume] is called when the stream resumed.
+   *
+   * The [onListen] callback is called when the stream
+   * receives its listener and [onCancel] when the listener ends
+   * its subscription. If [onCancel] needs to perform an asynchronous operation,
+   * [onCancel] should return a future that completes when the cancel operation
+   * is done.
+   *
+   * If the stream is canceled before the controller needs new data the
+   * [onResume] call might not be executed.
+   */
+  factory StreamController(
+      {void onListen(),
+      void onPause(),
+      void onResume(),
+      onCancel(),
+      bool sync: false}) {
+    return sync
+        ? new _SyncStreamController<T>(onListen, onPause, onResume, onCancel)
+        : new _AsyncStreamController<T>(onListen, onPause, onResume, onCancel);
+  }
+
+  /**
+   * A controller where [stream] can be listened to more than once.
+   *
+   * The [Stream] returned by [stream] is a broadcast stream.
+   * It can be listened to more than once.
+   *
+   * A Stream should be inert until a subscriber starts listening on it (using
+   * the [onListen] callback to start producing events). Streams should not
+   * leak resources (like websockets) when no user ever listens on the stream.
+   *
+   * Broadcast streams do not buffer events when there is no listener.
+   *
+   * The controller distributes any events to all currently subscribed
+   * listeners at the time when [add], [addError] or [close] is called.
+   * It is not allowed to call `add`, `addError`, or `close` before a previous
+   * call has returned. The controller does not have any internal queue of
+   * events, and if there are no listeners at the time the event is added,
+   * it will just be dropped, or, if it is an error, be reported as uncaught.
+   *
+   * Each listener subscription is handled independently,
+   * and if one pauses, only the pausing listener is affected.
+   * A paused listener will buffer events internally until unpaused or canceled.
+   *
+   * If [sync] is true, events may be fired directly by the stream's
+   * subscriptions during an [add], [addError] or [close] call.
+   * The returned stream controller is a [SynchronousStreamController],
+   * and must be used with the care and attention necessary to not break
+   * the [Stream] contract.
+   * See [Completer.sync] for some explanations on when a synchronous
+   * dispatching can be used.
+   * If in doubt, keep the controller non-sync.
+   *
+   * If [sync] is false, the event will always be fired at a later time,
+   * after the code adding the event has completed.
+   * In that case, no guarantees are given with regard to when
+   * multiple listeners get the events, except that each listener will get
+   * all events in the correct order. Each subscription handles the events
+   * individually.
+   * If two events are sent on an async controller with two listeners,
+   * one of the listeners may get both events
+   * before the other listener gets any.
+   * A listener must be subscribed both when the event is initiated
+   * (that is, when [add] is called)
+   * and when the event is later delivered,
+   * in order to receive the event.
+   *
+   * The [onListen] callback is called when the first listener is subscribed,
+   * and the [onCancel] is called when there are no longer any active listeners.
+   * If a listener is added again later, after the [onCancel] was called,
+   * the [onListen] will be called again.
+   */
+  factory StreamController.broadcast(
+      {void onListen(), void onCancel(), bool sync: false}) {
+    return sync
+        ? new _SyncBroadcastStreamController<T>(onListen, onCancel)
+        : new _AsyncBroadcastStreamController<T>(onListen, onCancel);
+  }
+
+  /**
+   * The callback which is called when the stream is listened to.
+   *
+   * May be set to `null`, in which case no callback will happen.
+   */
+  ControllerCallback get onListen;
+
+  void set onListen(void onListenHandler());
+
+  /**
+   * The callback which is called when the stream is paused.
+   *
+   * May be set to `null`, in which case no callback will happen.
+   *
+   * Pause related callbacks are not supported on broadcast stream controllers.
+   */
+  ControllerCallback get onPause;
+
+  void set onPause(void onPauseHandler());
+
+  /**
+   * The callback which is called when the stream is resumed.
+   *
+   * May be set to `null`, in which case no callback will happen.
+   *
+   * Pause related callbacks are not supported on broadcast stream controllers.
+   */
+  ControllerCallback get onResume;
+
+  void set onResume(void onResumeHandler());
+
+  /**
+   * The callback which is called when the stream is canceled.
+   *
+   * May be set to `null`, in which case no callback will happen.
+   */
+  ControllerCancelCallback get onCancel;
+
+  void set onCancel(onCancelHandler());
+
+  /**
+   * Returns a view of this object that only exposes the [StreamSink] interface.
+   */
+  StreamSink<T> get sink;
+
+  /**
+   * Whether the stream controller is closed for adding more events.
+   *
+   * The controller becomes closed by calling the [close] method.
+   * New events cannot be added, by calling [add] or [addError],
+   * to a closed controller.
+   *
+   * If the controller is closed,
+   * the "done" event might not have been delivered yet,
+   * but it has been scheduled, and it is too late to add more events.
+   */
+  bool get isClosed;
+
+  /**
+   * Whether the subscription would need to buffer events.
+   *
+   * This is the case if the controller's stream has a listener and it is
+   * paused, or if it has not received a listener yet. In that case, the
+   * controller is considered paused as well.
+   *
+   * A broadcast stream controller is never considered paused. It always
+   * forwards its events to all uncanceled subscriptions, if any,
+   * and let the subscriptions handle their own pausing and buffering.
+   */
+  bool get isPaused;
+
+  /** Whether there is a subscriber on the [Stream]. */
+  bool get hasListener;
+
+  /**
+   * Sends a data [event].
+   *
+   * Listeners receive this event in a later microtask.
+   *
+   * Note that a synchronous controller (created by passing true to the `sync`
+   * parameter of the `StreamController` constructor) delivers events
+   * immediately. Since this behavior violates the contract mentioned here,
+   * synchronous controllers should only be used as described in the
+   * documentation to ensure that the delivered events always *appear* as if
+   * they were delivered in a separate microtask.
+   */
+  void add(T event);
+
+  /**
+   * Sends or enqueues an error event.
+   *
+   * If [error] is `null`, it is replaced by a [NullThrownError].
+   *
+   * Listeners receive this event at a later microtask. This behavior can be
+   * overridden by using `sync` controllers. Note, however, that sync
+   * controllers have to satisfy the preconditions mentioned in the
+   * documentation of the constructors.
+   */
+  void addError(Object error, [StackTrace stackTrace]);
+
+  /**
+   * Closes the stream.
+   *
+   * Listeners receive the done event at a later microtask. This behavior can be
+   * overridden by using `sync` controllers. Note, however, that sync
+   * controllers have to satisfy the preconditions mentioned in the
+   * documentation of the constructors.
+   */
+  Future close();
+
+  /**
+   * Receives events from [source] and puts them into this controller's stream.
+   *
+   * Returns a future which completes when the source stream is done.
+   *
+   * Events must not be added directly to this controller using [add],
+   * [addError], [close] or [addStream], until the returned future
+   * is complete.
+   *
+   * Data and error events are forwarded to this controller's stream. A done
+   * event on the source will end the `addStream` operation and complete the
+   * returned future.
+   *
+   * If [cancelOnError] is true, only the first error on [source] is
+   * forwarded to the controller's stream, and the `addStream` ends
+   * after this. If [cancelOnError] is false, all errors are forwarded
+   * and only a done event will end the `addStream`.
+   * If [cancelOnError] is omitted, it defaults to false.
+   */
+  Future addStream(Stream<T> source, {bool cancelOnError});
+}
+
+/**
+ * A stream controller that delivers its events synchronously.
+ *
+ * A synchronous stream controller is intended for cases where
+ * an already asynchronous event triggers an event on a stream.
+ *
+ * Instead of adding the event to the stream in a later microtask,
+ * causing extra latency, the event is instead fired immediately by the
+ * synchronous stream controller, as if the stream event was
+ * the current event or microtask.
+ *
+ * The synchronous stream controller can be used to break the contract
+ * on [Stream], and it must be used carefully to avoid doing so.
+ *
+ * The only advantage to using a [SynchronousStreamController] over a
+ * normal [StreamController] is the improved latency.
+ * Only use the synchronous version if the improvement is significant,
+ * and if its use is safe. Otherwise just use a normal stream controller,
+ * which will always have the correct behavior for a [Stream], and won't
+ * accidentally break other code.
+ *
+ * Adding events to a synchronous controller should only happen as the
+ * very last part of the handling of the original event.
+ * At that point, adding an event to the stream is equivalent to
+ * returning to the event loop and adding the event in the next microtask.
+ *
+ * Each listener callback will be run as if it was a top-level event
+ * or microtask. This means that if it throws, the error will be reported as
+ * uncaught as soon as possible.
+ * This is one reason to add the event as the last thing in the original event
+ * handler - any action done after adding the event will delay the report of
+ * errors in the event listener callbacks.
+ *
+ * If an event is added in a setting that isn't known to be another event,
+ * it may cause the stream's listener to get that event before the listener
+ * is ready to handle it. We promise that after calling [Stream.listen],
+ * you won't get any events until the code doing the listen has completed.
+ * Calling [add] in response to a function call of unknown origin may break
+ * that promise.
+ *
+ * An [onListen] callback from the controller is *not* an asynchronous event,
+ * and adding events to the controller in the `onListen` callback is always
+ * wrong. The events will be delivered before the listener has even received
+ * the subscription yet.
+ *
+ * The synchronous broadcast stream controller also has a restrictions that a
+ * normal stream controller does not:
+ * The [add], [addError], [close] and [addStream] methods *must not* be
+ * called while an event is being delivered.
+ * That is, if a callback on a subscription on the controller's stream causes
+ * a call to any of the functions above, the call will fail.
+ * A broadcast stream may have more than one listener, and if an
+ * event is added synchronously while another is being also in the process
+ * of being added, the latter event might reach some listeners before
+ * the former. To prevent that, an event cannot be added while a previous
+ * event is being fired.
+ * This guarantees that an event is fully delivered when the
+ * first [add], [addError] or [close] returns,
+ * and further events will be delivered in the correct order.
+ *
+ * This still only guarantees that the event is delivered to the subscription.
+ * If the subscription is paused, the actual callback may still happen later,
+ * and the event will instead be buffered by the subscription.
+ * Barring pausing, and the following buffered events that haven't been
+ * delivered yet, callbacks will be called synchronously when an event is added.
+ *
+ * Adding an event to a synchronous non-broadcast stream controller while
+ * another event is in progress may cause the second event to be delayed
+ * and not be delivered synchronously, and until that event is delivered,
+ * the controller will not act synchronously.
+ */
+abstract class SynchronousStreamController<T> implements StreamController<T> {
+  /**
+   * Adds event to the controller's stream.
+   *
+   * As [StreamController.add], but must not be called while an event is
+   * being added by [add], [addError] or [close].
+   */
+  void add(T data);
+
+  /**
+   * Adds error to the controller's stream.
+   *
+   * As [StreamController.addError], but must not be called while an event is
+   * being added by [add], [addError] or [close].
+   */
+  void addError(Object error, [StackTrace stackTrace]);
+
+  /**
+   * Closes the controller's stream.
+   *
+   * As [StreamController.close], but must not be called while an event is
+   * being added by [add], [addError] or [close].
+   */
+  Future close();
+}
+
+abstract class _StreamControllerLifecycle<T> {
+  StreamSubscription<T> _subscribe(
+      void onData(T data), Function onError, void onDone(), bool cancelOnError);
+  void _recordPause(StreamSubscription<T> subscription) {}
+  void _recordResume(StreamSubscription<T> subscription) {}
+  Future _recordCancel(StreamSubscription<T> subscription) => null;
+}
+
+// Base type for implementations of stream controllers.
+abstract class _StreamControllerBase<T>
+    implements
+        StreamController<T>,
+        _StreamControllerLifecycle<T>,
+        _EventSink<T>,
+        _EventDispatch<T> {}
+
+/**
+ * Default implementation of [StreamController].
+ *
+ * Controls a stream that only supports a single controller.
+ */
+abstract class _StreamController<T> implements _StreamControllerBase<T> {
+  // The states are bit-flags. More than one can be set at a time.
+  //
+  // The "subscription state" goes through the states:
+  //   initial -> subscribed -> canceled.
+  // These are mutually exclusive.
+  // The "closed" state records whether the [close] method has been called
+  // on the controller. This can be done at any time. If done before
+  // subscription, the done event is queued. If done after cancel, the done
+  // event is ignored (just as any other event after a cancel).
+
+  /** The controller is in its initial state with no subscription. */
+  static const int _STATE_INITIAL = 0;
+  /** The controller has a subscription, but hasn't been closed or canceled. */
+  static const int _STATE_SUBSCRIBED = 1;
+  /** The subscription is canceled. */
+  static const int _STATE_CANCELED = 2;
+  /** Mask for the subscription state. */
+  static const int _STATE_SUBSCRIPTION_MASK = 3;
+
+  // The following state relate to the controller, not the subscription.
+  // If closed, adding more events is not allowed.
+  // If executing an [addStream], new events are not allowed either, but will
+  // be added by the stream.
+
+  /**
+   * The controller is closed due to calling [close].
+   *
+   * When the stream is closed, you can neither add new events nor add new
+   * listeners.
+   */
+  static const int _STATE_CLOSED = 4;
+  /**
+   * The controller is in the middle of an [addStream] operation.
+   *
+   * While adding events from a stream, no new events can be added directly
+   * on the controller.
+   */
+  static const int _STATE_ADDSTREAM = 8;
+
+  /**
+   * Field containing different data depending on the current subscription
+   * state.
+   *
+   * If [_state] is [_STATE_INITIAL], the field may contain a [_PendingEvents]
+   * for events added to the controller before a subscription.
+   *
+   * While [_state] is [_STATE_SUBSCRIBED], the field contains the subscription.
+   *
+   * When [_state] is [_STATE_CANCELED] the field is currently not used.
+   */
+  var _varData;
+
+  /** Current state of the controller. */
+  int _state = _STATE_INITIAL;
+
+  /**
+   * Future completed when the stream sends its last event.
+   *
+   * This is also the future returned by [close].
+   */
+  // TODO(lrn): Could this be stored in the varData field too, if it's not
+  // accessed until the call to "close"? Then we need to special case if it's
+  // accessed earlier, or if close is called before subscribing.
+  _Future _doneFuture;
+
+  ControllerCallback onListen;
+  ControllerCallback onPause;
+  ControllerCallback onResume;
+  ControllerCancelCallback onCancel;
+
+  _StreamController(this.onListen, this.onPause, this.onResume, this.onCancel);
+
+  // Return a new stream every time. The streams are equal, but not identical.
+  Stream<T> get stream => new _ControllerStream<T>(this);
+
+  /**
+   * Returns a view of this object that only exposes the [StreamSink] interface.
+   */
+  StreamSink<T> get sink => new _StreamSinkWrapper<T>(this);
+
+  /**
+   * Whether a listener has existed and been canceled.
+   *
+   * After this, adding more events will be ignored.
+   */
+  bool get _isCanceled => (_state & _STATE_CANCELED) != 0;
+
+  /** Whether there is an active listener. */
+  bool get hasListener => (_state & _STATE_SUBSCRIBED) != 0;
+
+  /** Whether there has not been a listener yet. */
+  bool get _isInitialState =>
+      (_state & _STATE_SUBSCRIPTION_MASK) == _STATE_INITIAL;
+
+  bool get isClosed => (_state & _STATE_CLOSED) != 0;
+
+  bool get isPaused =>
+      hasListener ? _subscription._isInputPaused : !_isCanceled;
+
+  bool get _isAddingStream => (_state & _STATE_ADDSTREAM) != 0;
+
+  /** New events may not be added after close, or during addStream. */
+  bool get _mayAddEvent => (_state < _STATE_CLOSED);
+
+  // Returns the pending events.
+  // Pending events are events added before a subscription exists.
+  // They are added to the subscription when it is created.
+  // Pending events, if any, are kept in the _varData field until the
+  // stream is listened to.
+  // While adding a stream, pending events are moved into the
+  // state object to allow the state object to use the _varData field.
+  _PendingEvents<T> get _pendingEvents {
+    assert(_isInitialState);
+    if (!_isAddingStream) {
+      return _varData;
+    }
+    _StreamControllerAddStreamState<T> state = _varData;
+    return state.varData;
+  }
+
+  // Returns the pending events, and creates the object if necessary.
+  _StreamImplEvents<T> _ensurePendingEvents() {
+    assert(_isInitialState);
+    if (!_isAddingStream) {
+      _varData ??= new _StreamImplEvents<T>();
+      return _varData;
+    }
+    _StreamControllerAddStreamState<T> state = _varData;
+    if (state.varData == null) state.varData = new _StreamImplEvents<T>();
+    return state.varData;
+  }
+
+  // Get the current subscription.
+  // If we are adding a stream, the subscription is moved into the state
+  // object to allow the state object to use the _varData field.
+  _ControllerSubscription<T> get _subscription {
+    assert(hasListener);
+    if (_isAddingStream) {
+      _StreamControllerAddStreamState<T> addState = _varData;
+      return addState.varData;
+    }
+    return _varData;
+  }
+
+  /**
+   * Creates an error describing why an event cannot be added.
+   *
+   * The reason, and therefore the error message, depends on the current state.
+   */
+  Error _badEventState() {
+    if (isClosed) {
+      return new StateError("Cannot add event after closing");
+    }
+    assert(_isAddingStream);
+    return new StateError("Cannot add event while adding a stream");
+  }
+
+  // StreamSink interface.
+  Future addStream(Stream<T> source, {bool cancelOnError}) {
+    if (!_mayAddEvent) throw _badEventState();
+    if (_isCanceled) return new _Future.immediate(null);
+    _StreamControllerAddStreamState<T> addState =
+        new _StreamControllerAddStreamState<T>(
+            this, _varData, source, cancelOnError ?? false);
+    _varData = addState;
+    _state |= _STATE_ADDSTREAM;
+    return addState.addStreamFuture;
+  }
+
+  /**
+   * Returns a future that is completed when the stream is done
+   * processing events.
+   *
+   * This happens either when the done event has been sent, or if the
+   * subscriber of a single-subscription stream is cancelled.
+   */
+  Future get done => _ensureDoneFuture();
+
+  Future _ensureDoneFuture() {
+    _doneFuture ??= _isCanceled ? Future._nullFuture : new _Future();
+    return _doneFuture;
+  }
+
+  /**
+   * Send or enqueue a data event.
+   */
+  void add(T value) {
+    if (!_mayAddEvent) throw _badEventState();
+    _add(value);
+  }
+
+  /**
+   * Send or enqueue an error event.
+   */
+  void addError(Object error, [StackTrace stackTrace]) {
+    if (!_mayAddEvent) throw _badEventState();
+    error = _nonNullError(error);
+    AsyncError replacement = Zone.current.errorCallback(error, stackTrace);
+    if (replacement != null) {
+      error = _nonNullError(replacement.error);
+      stackTrace = replacement.stackTrace;
+    }
+    _addError(error, stackTrace);
+  }
+
+  /**
+   * Closes this controller and sends a done event on the stream.
+   *
+   * The first time a controller is closed, a "done" event is added to its
+   * stream.
+   *
+   * You are allowed to close the controller more than once, but only the first
+   * call has any effect.
+   *
+   * After closing, no further events may be added using [add], [addError]
+   * or [addStream].
+   *
+   * The returned future is completed when the done event has been delivered.
+   */
+  Future close() {
+    if (isClosed) {
+      return _ensureDoneFuture();
+    }
+    if (!_mayAddEvent) throw _badEventState();
+    _closeUnchecked();
+    return _ensureDoneFuture();
+  }
+
+  void _closeUnchecked() {
+    _state |= _STATE_CLOSED;
+    if (hasListener) {
+      _sendDone();
+    } else if (_isInitialState) {
+      _ensurePendingEvents().add(const _DelayedDone());
+    }
+  }
+
+  // EventSink interface. Used by the [addStream] events.
+
+  // Add data event, used both by the [addStream] events and by [add].
+  void _add(T value) {
+    if (hasListener) {
+      _sendData(value);
+    } else if (_isInitialState) {
+      _ensurePendingEvents().add(new _DelayedData<T>(value));
+    }
+  }
+
+  void _addError(Object error, StackTrace stackTrace) {
+    if (hasListener) {
+      _sendError(error, stackTrace);
+    } else if (_isInitialState) {
+      _ensurePendingEvents().add(new _DelayedError(error, stackTrace));
+    }
+  }
+
+  void _close() {
+    // End of addStream stream.
+    assert(_isAddingStream);
+    _StreamControllerAddStreamState<T> addState = _varData;
+    _varData = addState.varData;
+    _state &= ~_STATE_ADDSTREAM;
+    addState.complete();
+  }
+
+  // _StreamControllerLifeCycle interface
+
+  StreamSubscription<T> _subscribe(void onData(T data), Function onError,
+      void onDone(), bool cancelOnError) {
+    if (!_isInitialState) {
+      throw new StateError("Stream has already been listened to.");
+    }
+    _ControllerSubscription<T> subscription = new _ControllerSubscription<T>(
+        this, onData, onError, onDone, cancelOnError);
+
+    _PendingEvents<T> pendingEvents = _pendingEvents;
+    _state |= _STATE_SUBSCRIBED;
+    if (_isAddingStream) {
+      _StreamControllerAddStreamState<T> addState = _varData;
+      addState.varData = subscription;
+      addState.resume();
+    } else {
+      _varData = subscription;
+    }
+    subscription._setPendingEvents(pendingEvents);
+    subscription._guardCallback(() {
+      _runGuarded(onListen);
+    });
+
+    return subscription;
+  }
+
+  Future _recordCancel(StreamSubscription<T> subscription) {
+    // When we cancel, we first cancel any stream being added,
+    // Then we call `onCancel`, and finally the _doneFuture is completed.
+    // If either of addStream's cancel or `onCancel` returns a future,
+    // we wait for it before continuing.
+    // Any error during this process ends up in the returned future.
+    // If more errors happen, we act as if it happens inside nested try/finallys
+    // or whenComplete calls, and only the last error ends up in the
+    // returned future.
+    Future result;
+    if (_isAddingStream) {
+      _StreamControllerAddStreamState<T> addState = _varData;
+      result = addState.cancel();
+    }
+    _varData = null;
+    _state =
+        (_state & ~(_STATE_SUBSCRIBED | _STATE_ADDSTREAM)) | _STATE_CANCELED;
+
+    if (onCancel != null) {
+      if (result == null) {
+        // Only introduce a future if one is needed.
+        // If _onCancel returns null, no future is needed.
+        try {
+          result = onCancel();
+        } catch (e, s) {
+          // Return the error in the returned future.
+          // Complete it asynchronously, so there is time for a listener
+          // to handle the error.
+          result = new _Future().._asyncCompleteError(e, s);
+        }
+      } else {
+        // Simpler case when we already know that we will return a future.
+        result = result.whenComplete(onCancel);
+      }
+    }
+
+    void complete() {
+      if (_doneFuture != null && _doneFuture._mayComplete) {
+        _doneFuture._asyncComplete(null);
+      }
+    }
+
+    if (result != null) {
+      result = result.whenComplete(complete);
+    } else {
+      complete();
+    }
+
+    return result;
+  }
+
+  void _recordPause(StreamSubscription<T> subscription) {
+    if (_isAddingStream) {
+      _StreamControllerAddStreamState<T> addState = _varData;
+      addState.pause();
+    }
+    _runGuarded(onPause);
+  }
+
+  void _recordResume(StreamSubscription<T> subscription) {
+    if (_isAddingStream) {
+      _StreamControllerAddStreamState<T> addState = _varData;
+      addState.resume();
+    }
+    _runGuarded(onResume);
+  }
+}
+
+abstract class _SyncStreamControllerDispatch<T>
+    implements _StreamController<T>, SynchronousStreamController<T> {
+  int get _state;
+  void set _state(int state);
+
+  void _sendData(T data) {
+    _subscription._add(data);
+  }
+
+  void _sendError(Object error, StackTrace stackTrace) {
+    _subscription._addError(error, stackTrace);
+  }
+
+  void _sendDone() {
+    _subscription._close();
+  }
+}
+
+abstract class _AsyncStreamControllerDispatch<T>
+    implements _StreamController<T> {
+  void _sendData(T data) {
+    _subscription._addPending(new _DelayedData<T>(data));
+  }
+
+  void _sendError(Object error, StackTrace stackTrace) {
+    _subscription._addPending(new _DelayedError(error, stackTrace));
+  }
+
+  void _sendDone() {
+    _subscription._addPending(const _DelayedDone());
+  }
+}
+
+// TODO(lrn): Use common superclass for callback-controllers when VM supports
+// constructors in mixin superclasses.
+
+class _AsyncStreamController<T> = _StreamController<T>
+    with _AsyncStreamControllerDispatch<T>;
+
+class _SyncStreamController<T> = _StreamController<T>
+    with _SyncStreamControllerDispatch<T>;
+
+typedef _NotificationHandler();
+
+void _runGuarded(_NotificationHandler notificationHandler) {
+  if (notificationHandler == null) return;
+  try {
+    notificationHandler();
+  } catch (e, s) {
+    Zone.current.handleUncaughtError(e, s);
+  }
+}
+
+class _ControllerStream<T> extends _StreamImpl<T> {
+  _StreamControllerLifecycle<T> _controller;
+
+  _ControllerStream(this._controller);
+
+  StreamSubscription<T> _createSubscription(void onData(T data),
+          Function onError, void onDone(), bool cancelOnError) =>
+      _controller._subscribe(onData, onError, onDone, cancelOnError);
+
+  // Override == and hashCode so that new streams returned by the same
+  // controller are considered equal. The controller returns a new stream
+  // each time it's queried, but doesn't have to cache the result.
+
+  int get hashCode => _controller.hashCode ^ 0x35323532;
+
+  bool operator ==(Object other) {
+    if (identical(this, other)) return true;
+    return other is _ControllerStream &&
+        identical(other._controller, this._controller);
+  }
+}
+
+class _ControllerSubscription<T> extends _BufferingStreamSubscription<T> {
+  final _StreamControllerLifecycle<T> _controller;
+
+  _ControllerSubscription(this._controller, void onData(T data),
+      Function onError, void onDone(), bool cancelOnError)
+      : super(onData, onError, onDone, cancelOnError);
+
+  Future _onCancel() {
+    return _controller._recordCancel(this);
+  }
+
+  void _onPause() {
+    _controller._recordPause(this);
+  }
+
+  void _onResume() {
+    _controller._recordResume(this);
+  }
+}
+
+/** A class that exposes only the [StreamSink] interface of an object. */
+class _StreamSinkWrapper<T> implements StreamSink<T> {
+  final StreamController _target;
+  _StreamSinkWrapper(this._target);
+  void add(T data) {
+    _target.add(data);
+  }
+
+  void addError(Object error, [StackTrace stackTrace]) {
+    _target.addError(error, stackTrace);
+  }
+
+  Future close() => _target.close();
+
+  Future addStream(Stream<T> source) => _target.addStream(source);
+
+  Future get done => _target.done;
+}
+
+/**
+ * Object containing the state used to handle [StreamController.addStream].
+ */
+class _AddStreamState<T> {
+  // [_Future] returned by call to addStream.
+  final _Future addStreamFuture;
+
+  // Subscription on stream argument to addStream.
+  final StreamSubscription addSubscription;
+
+  _AddStreamState(
+      _EventSink<T> controller, Stream<T> source, bool cancelOnError)
+      : addStreamFuture = new _Future(),
+        addSubscription = source.listen(controller._add,
+            onError: cancelOnError
+                ? makeErrorHandler(controller)
+                : controller._addError,
+            onDone: controller._close,
+            cancelOnError: cancelOnError);
+
+  static makeErrorHandler(_EventSink controller) => (e, StackTrace s) {
+        controller._addError(e, s);
+        controller._close();
+      };
+
+  void pause() {
+    addSubscription.pause();
+  }
+
+  void resume() {
+    addSubscription.resume();
+  }
+
+  /**
+   * Stop adding the stream.
+   *
+   * Complete the future returned by `StreamController.addStream` when
+   * the cancel is complete.
+   *
+   * Return a future if the cancel takes time, otherwise return `null`.
+   */
+  Future cancel() {
+    var cancel = addSubscription.cancel();
+    if (cancel == null) {
+      addStreamFuture._asyncComplete(null);
+      return null;
+    }
+    return cancel.whenComplete(() {
+      addStreamFuture._asyncComplete(null);
+    });
+  }
+
+  void complete() {
+    addStreamFuture._asyncComplete(null);
+  }
+}
+
+class _StreamControllerAddStreamState<T> extends _AddStreamState<T> {
+  // The subscription or pending data of a _StreamController.
+  // Stored here because we reuse the `_varData` field  in the _StreamController
+  // to store this state object.
+  var varData;
+
+  _StreamControllerAddStreamState(_StreamController<T> controller, this.varData,
+      Stream<T> source, bool cancelOnError)
+      : super(controller, source, cancelOnError) {
+    if (controller.isPaused) {
+      addSubscription.pause();
+    }
+  }
+}
diff --git a/sdk_nnbd/lib/async/stream_impl.dart b/sdk_nnbd/lib/async/stream_impl.dart
new file mode 100644
index 0000000..14c84a5
--- /dev/null
+++ b/sdk_nnbd/lib/async/stream_impl.dart
@@ -0,0 +1,1062 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.async;
+
+/** Abstract and private interface for a place to put events. */
+abstract class _EventSink<T> {
+  void _add(T data);
+  void _addError(Object error, StackTrace stackTrace);
+  void _close();
+}
+
+/**
+ * Abstract and private interface for a place to send events.
+ *
+ * Used by event buffering to finally dispatch the pending event, where
+ * [_EventSink] is where the event first enters the stream subscription,
+ * and may yet be buffered.
+ */
+abstract class _EventDispatch<T> {
+  void _sendData(T data);
+  void _sendError(Object error, StackTrace stackTrace);
+  void _sendDone();
+}
+
+/**
+ * Default implementation of stream subscription of buffering events.
+ *
+ * The only public methods are those of [StreamSubscription], so instances of
+ * [_BufferingStreamSubscription] can be returned directly as a
+ * [StreamSubscription] without exposing internal functionality.
+ *
+ * The [StreamController] is a public facing version of [Stream] and this class,
+ * with some methods made public.
+ *
+ * The user interface of [_BufferingStreamSubscription] are the following
+ * methods:
+ *
+ * * [_add]: Add a data event to the stream.
+ * * [_addError]: Add an error event to the stream.
+ * * [_close]: Request to close the stream.
+ * * [_onCancel]: Called when the subscription will provide no more events,
+ *     either due to being actively canceled, or after sending a done event.
+ * * [_onPause]: Called when the subscription wants the event source to pause.
+ * * [_onResume]: Called when allowing new events after a pause.
+ *
+ * The user should not add new events when the subscription requests a paused,
+ * but if it happens anyway, the subscription will enqueue the events just as
+ * when new events arrive while still firing an old event.
+ */
+class _BufferingStreamSubscription<T>
+    implements StreamSubscription<T>, _EventSink<T>, _EventDispatch<T> {
+  /** The `cancelOnError` flag from the `listen` call. */
+  static const int _STATE_CANCEL_ON_ERROR = 1;
+  /**
+   * Whether the "done" event has been received.
+   * No further events are accepted after this.
+   */
+  static const int _STATE_CLOSED = 2;
+  /**
+   * Set if the input has been asked not to send events.
+   *
+   * This is not the same as being paused, since the input will remain paused
+   * after a call to [resume] if there are pending events.
+   */
+  static const int _STATE_INPUT_PAUSED = 4;
+  /**
+   * Whether the subscription has been canceled.
+   *
+   * Set by calling [cancel], or by handling a "done" event, or an "error" event
+   * when `cancelOnError` is true.
+   */
+  static const int _STATE_CANCELED = 8;
+  /**
+   * Set when either:
+   *
+   *   * an error is sent, and [cancelOnError] is true, or
+   *   * a done event is sent.
+   *
+   * If the subscription is canceled while _STATE_WAIT_FOR_CANCEL is set, the
+   * state is unset, and no further events must be delivered.
+   */
+  static const int _STATE_WAIT_FOR_CANCEL = 16;
+  static const int _STATE_IN_CALLBACK = 32;
+  static const int _STATE_HAS_PENDING = 64;
+  static const int _STATE_PAUSE_COUNT = 128;
+
+  /* Event handlers provided in constructor. */
+  _DataHandler<T> _onData;
+  Function _onError;
+  _DoneHandler _onDone;
+  final Zone _zone = Zone.current;
+
+  /** Bit vector based on state-constants above. */
+  int _state;
+
+  // TODO(floitsch): reuse another field
+  /** The future [_onCancel] may return. */
+  Future _cancelFuture;
+
+  /**
+   * Queue of pending events.
+   *
+   * Is created when necessary, or set in constructor for preconfigured events.
+   */
+  _PendingEvents<T> _pending;
+
+  _BufferingStreamSubscription(
+      void onData(T data), Function onError, void onDone(), bool cancelOnError)
+      : _state = (cancelOnError ? _STATE_CANCEL_ON_ERROR : 0) {
+    this.onData(onData);
+    this.onError(onError);
+    this.onDone(onDone);
+  }
+
+  /**
+   * Sets the subscription's pending events object.
+   *
+   * This can only be done once. The pending events object is used for the
+   * rest of the subscription's life cycle.
+   */
+  void _setPendingEvents(_PendingEvents<T> pendingEvents) {
+    assert(_pending == null);
+    if (pendingEvents == null) return;
+    _pending = pendingEvents;
+    if (!pendingEvents.isEmpty) {
+      _state |= _STATE_HAS_PENDING;
+      _pending.schedule(this);
+    }
+  }
+
+  // StreamSubscription interface.
+
+  void onData(void handleData(T event)) {
+    handleData ??= _nullDataHandler;
+    // TODO(floitsch): the return type should be 'void', and the type
+    // should be inferred.
+    _onData = _zone.registerUnaryCallback<dynamic, T>(handleData);
+  }
+
+  void onError(Function handleError) {
+    handleError ??= _nullErrorHandler;
+    if (handleError is void Function(Object, StackTrace)) {
+      _onError = _zone
+          .registerBinaryCallback<dynamic, Object, StackTrace>(handleError);
+    } else if (handleError is void Function(Object)) {
+      _onError = _zone.registerUnaryCallback<dynamic, Object>(handleError);
+    } else {
+      throw new ArgumentError("handleError callback must take either an Object "
+          "(the error), or both an Object (the error) and a StackTrace.");
+    }
+  }
+
+  void onDone(void handleDone()) {
+    handleDone ??= _nullDoneHandler;
+    _onDone = _zone.registerCallback(handleDone);
+  }
+
+  void pause([Future resumeSignal]) {
+    if (_isCanceled) return;
+    bool wasPaused = _isPaused;
+    bool wasInputPaused = _isInputPaused;
+    // Increment pause count and mark input paused (if it isn't already).
+    _state = (_state + _STATE_PAUSE_COUNT) | _STATE_INPUT_PAUSED;
+    if (resumeSignal != null) resumeSignal.whenComplete(resume);
+    if (!wasPaused && _pending != null) _pending.cancelSchedule();
+    if (!wasInputPaused && !_inCallback) _guardCallback(_onPause);
+  }
+
+  void resume() {
+    if (_isCanceled) return;
+    if (_isPaused) {
+      _decrementPauseCount();
+      if (!_isPaused) {
+        if (_hasPending && !_pending.isEmpty) {
+          // Input is still paused.
+          _pending.schedule(this);
+        } else {
+          assert(_mayResumeInput);
+          _state &= ~_STATE_INPUT_PAUSED;
+          if (!_inCallback) _guardCallback(_onResume);
+        }
+      }
+    }
+  }
+
+  Future cancel() {
+    // The user doesn't want to receive any further events. If there is an
+    // error or done event pending (waiting for the cancel to be done) discard
+    // that event.
+    _state &= ~_STATE_WAIT_FOR_CANCEL;
+    if (!_isCanceled) {
+      _cancel();
+    }
+    return _cancelFuture ?? Future._nullFuture;
+  }
+
+  Future<E> asFuture<E>([E futureValue]) {
+    _Future<E> result = new _Future<E>();
+
+    // Overwrite the onDone and onError handlers.
+    _onDone = () {
+      result._complete(futureValue);
+    };
+    _onError = (error, StackTrace stackTrace) {
+      Future cancelFuture = cancel();
+      if (!identical(cancelFuture, Future._nullFuture)) {
+        cancelFuture.whenComplete(() {
+          result._completeError(error, stackTrace);
+        });
+      } else {
+        result._completeError(error, stackTrace);
+      }
+    };
+
+    return result;
+  }
+
+  // State management.
+
+  bool get _isInputPaused => (_state & _STATE_INPUT_PAUSED) != 0;
+  bool get _isClosed => (_state & _STATE_CLOSED) != 0;
+  bool get _isCanceled => (_state & _STATE_CANCELED) != 0;
+  bool get _waitsForCancel => (_state & _STATE_WAIT_FOR_CANCEL) != 0;
+  bool get _inCallback => (_state & _STATE_IN_CALLBACK) != 0;
+  bool get _hasPending => (_state & _STATE_HAS_PENDING) != 0;
+  bool get _isPaused => _state >= _STATE_PAUSE_COUNT;
+  bool get _canFire => _state < _STATE_IN_CALLBACK;
+  bool get _mayResumeInput =>
+      !_isPaused && (_pending == null || _pending.isEmpty);
+  bool get _cancelOnError => (_state & _STATE_CANCEL_ON_ERROR) != 0;
+
+  bool get isPaused => _isPaused;
+
+  void _cancel() {
+    _state |= _STATE_CANCELED;
+    if (_hasPending) {
+      _pending.cancelSchedule();
+    }
+    if (!_inCallback) _pending = null;
+    _cancelFuture = _onCancel();
+  }
+
+  /**
+   * Decrements the pause count.
+   *
+   * Does not automatically unpause the input (call [_onResume]) when
+   * the pause count reaches zero. This is handled elsewhere, and only
+   * if there are no pending events buffered.
+   */
+  void _decrementPauseCount() {
+    assert(_isPaused);
+    _state -= _STATE_PAUSE_COUNT;
+  }
+
+  // _EventSink interface.
+
+  void _add(T data) {
+    assert(!_isClosed);
+    if (_isCanceled) return;
+    if (_canFire) {
+      _sendData(data);
+    } else {
+      _addPending(new _DelayedData<T>(data));
+    }
+  }
+
+  void _addError(Object error, StackTrace stackTrace) {
+    if (_isCanceled) return;
+    if (_canFire) {
+      _sendError(error, stackTrace); // Reports cancel after sending.
+    } else {
+      _addPending(new _DelayedError(error, stackTrace));
+    }
+  }
+
+  void _close() {
+    assert(!_isClosed);
+    if (_isCanceled) return;
+    _state |= _STATE_CLOSED;
+    if (_canFire) {
+      _sendDone();
+    } else {
+      _addPending(const _DelayedDone());
+    }
+  }
+
+  // Hooks called when the input is paused, unpaused or canceled.
+  // These must not throw. If overwritten to call user code, include suitable
+  // try/catch wrapping and send any errors to
+  // [_Zone.current.handleUncaughtError].
+  void _onPause() {
+    assert(_isInputPaused);
+  }
+
+  void _onResume() {
+    assert(!_isInputPaused);
+  }
+
+  Future _onCancel() {
+    assert(_isCanceled);
+    return null;
+  }
+
+  // Handle pending events.
+
+  /**
+   * Add a pending event.
+   *
+   * If the subscription is not paused, this also schedules a firing
+   * of pending events later (if necessary).
+   */
+  void _addPending(_DelayedEvent event) {
+    _StreamImplEvents<T> pending = _pending;
+    if (_pending == null) {
+      pending = _pending = new _StreamImplEvents<T>();
+    }
+    pending.add(event);
+    if (!_hasPending) {
+      _state |= _STATE_HAS_PENDING;
+      if (!_isPaused) {
+        _pending.schedule(this);
+      }
+    }
+  }
+
+  /* _EventDispatch interface. */
+
+  void _sendData(T data) {
+    assert(!_isCanceled);
+    assert(!_isPaused);
+    assert(!_inCallback);
+    bool wasInputPaused = _isInputPaused;
+    _state |= _STATE_IN_CALLBACK;
+    _zone.runUnaryGuarded(_onData, data);
+    _state &= ~_STATE_IN_CALLBACK;
+    _checkState(wasInputPaused);
+  }
+
+  void _sendError(Object error, StackTrace stackTrace) {
+    assert(!_isCanceled);
+    assert(!_isPaused);
+    assert(!_inCallback);
+    bool wasInputPaused = _isInputPaused;
+
+    void sendError() {
+      // If the subscription has been canceled while waiting for the cancel
+      // future to finish we must not report the error.
+      if (_isCanceled && !_waitsForCancel) return;
+      _state |= _STATE_IN_CALLBACK;
+      // TODO(floitsch): this dynamic should be 'void'.
+      var onError = _onError;
+      if (onError is void Function(Object, StackTrace)) {
+        _zone.runBinaryGuarded<Object, StackTrace>(onError, error, stackTrace);
+      } else {
+        assert(_onError is void Function(Object));
+        _zone.runUnaryGuarded<Object>(_onError, error);
+      }
+      _state &= ~_STATE_IN_CALLBACK;
+    }
+
+    if (_cancelOnError) {
+      _state |= _STATE_WAIT_FOR_CANCEL;
+      _cancel();
+      if (_cancelFuture != null &&
+          !identical(_cancelFuture, Future._nullFuture)) {
+        _cancelFuture.whenComplete(sendError);
+      } else {
+        sendError();
+      }
+    } else {
+      sendError();
+      // Only check state if not cancelOnError.
+      _checkState(wasInputPaused);
+    }
+  }
+
+  void _sendDone() {
+    assert(!_isCanceled);
+    assert(!_isPaused);
+    assert(!_inCallback);
+
+    void sendDone() {
+      // If the subscription has been canceled while waiting for the cancel
+      // future to finish we must not report the done event.
+      if (!_waitsForCancel) return;
+      _state |= (_STATE_CANCELED | _STATE_CLOSED | _STATE_IN_CALLBACK);
+      _zone.runGuarded(_onDone);
+      _state &= ~_STATE_IN_CALLBACK;
+    }
+
+    _cancel();
+    _state |= _STATE_WAIT_FOR_CANCEL;
+    if (_cancelFuture != null &&
+        !identical(_cancelFuture, Future._nullFuture)) {
+      _cancelFuture.whenComplete(sendDone);
+    } else {
+      sendDone();
+    }
+  }
+
+  /**
+   * Call a hook function.
+   *
+   * The call is properly wrapped in code to avoid other callbacks
+   * during the call, and it checks for state changes after the call
+   * that should cause further callbacks.
+   */
+  void _guardCallback(void callback()) {
+    assert(!_inCallback);
+    bool wasInputPaused = _isInputPaused;
+    _state |= _STATE_IN_CALLBACK;
+    callback();
+    _state &= ~_STATE_IN_CALLBACK;
+    _checkState(wasInputPaused);
+  }
+
+  /**
+   * Check if the input needs to be informed of state changes.
+   *
+   * State changes are pausing, resuming and canceling.
+   *
+   * After canceling, no further callbacks will happen.
+   *
+   * The cancel callback is called after a user cancel, or after
+   * the final done event is sent.
+   */
+  void _checkState(bool wasInputPaused) {
+    assert(!_inCallback);
+    if (_hasPending && _pending.isEmpty) {
+      _state &= ~_STATE_HAS_PENDING;
+      if (_isInputPaused && _mayResumeInput) {
+        _state &= ~_STATE_INPUT_PAUSED;
+      }
+    }
+    // If the state changes during a callback, we immediately
+    // make a new state-change callback. Loop until the state didn't change.
+    while (true) {
+      if (_isCanceled) {
+        _pending = null;
+        return;
+      }
+      bool isInputPaused = _isInputPaused;
+      if (wasInputPaused == isInputPaused) break;
+      _state ^= _STATE_IN_CALLBACK;
+      if (isInputPaused) {
+        _onPause();
+      } else {
+        _onResume();
+      }
+      _state &= ~_STATE_IN_CALLBACK;
+      wasInputPaused = isInputPaused;
+    }
+    if (_hasPending && !_isPaused) {
+      _pending.schedule(this);
+    }
+  }
+}
+
+// -------------------------------------------------------------------
+// Common base class for single and multi-subscription streams.
+// -------------------------------------------------------------------
+abstract class _StreamImpl<T> extends Stream<T> {
+  // ------------------------------------------------------------------
+  // Stream interface.
+
+  StreamSubscription<T> listen(void onData(T data),
+      {Function onError, void onDone(), bool cancelOnError}) {
+    cancelOnError = identical(true, cancelOnError);
+    StreamSubscription<T> subscription =
+        _createSubscription(onData, onError, onDone, cancelOnError);
+    _onListen(subscription);
+    return subscription;
+  }
+
+  // -------------------------------------------------------------------
+  /** Create a subscription object. Called by [subcribe]. */
+  StreamSubscription<T> _createSubscription(void onData(T data),
+      Function onError, void onDone(), bool cancelOnError) {
+    return new _BufferingStreamSubscription<T>(
+        onData, onError, onDone, cancelOnError);
+  }
+
+  /** Hook called when the subscription has been created. */
+  void _onListen(StreamSubscription subscription) {}
+}
+
+typedef _PendingEvents<T> _EventGenerator<T>();
+
+/** Stream that generates its own events. */
+class _GeneratedStreamImpl<T> extends _StreamImpl<T> {
+  final _EventGenerator<T> _pending;
+  bool _isUsed = false;
+  /**
+   * Initializes the stream to have only the events provided by a
+   * [_PendingEvents].
+   *
+   * A new [_PendingEvents] must be generated for each listen.
+   */
+  _GeneratedStreamImpl(this._pending);
+
+  StreamSubscription<T> _createSubscription(void onData(T data),
+      Function onError, void onDone(), bool cancelOnError) {
+    if (_isUsed) throw new StateError("Stream has already been listened to.");
+    _isUsed = true;
+    return new _BufferingStreamSubscription<T>(
+        onData, onError, onDone, cancelOnError)
+      .._setPendingEvents(_pending());
+  }
+}
+
+/** Pending events object that gets its events from an [Iterable]. */
+class _IterablePendingEvents<T> extends _PendingEvents<T> {
+  // The iterator providing data for data events.
+  // Set to null when iteration has completed.
+  Iterator<T> _iterator;
+
+  _IterablePendingEvents(Iterable<T> data) : _iterator = data.iterator;
+
+  bool get isEmpty => _iterator == null;
+
+  void handleNext(_EventDispatch<T> dispatch) {
+    if (_iterator == null) {
+      throw new StateError("No events pending.");
+    }
+    // Send one event per call to moveNext.
+    // If moveNext returns true, send the current element as data.
+    // If current throws, send that error, but keep iterating.
+    // If moveNext returns false, send a done event and clear the _iterator.
+    // If moveNext throws an error, send an error and prepare to send a done
+    // event afterwards.
+    bool hasMore;
+    try {
+      hasMore = _iterator.moveNext();
+      if (hasMore) {
+        dispatch._sendData(_iterator.current);
+      } else {
+        _iterator = null;
+        dispatch._sendDone();
+      }
+    } catch (e, s) {
+      if (hasMore == null) {
+        // Threw in .moveNext().
+        // Ensure that we send a done afterwards.
+        _iterator = const EmptyIterator<Null>();
+        dispatch._sendError(e, s);
+      } else {
+        // Threw in .current.
+        dispatch._sendError(e, s);
+      }
+    }
+  }
+
+  void clear() {
+    if (isScheduled) cancelSchedule();
+    _iterator = null;
+  }
+}
+
+// Internal helpers.
+
+// Types of the different handlers on a stream. Types used to type fields.
+typedef void _DataHandler<T>(T value);
+typedef void _DoneHandler();
+
+/** Default data handler, does nothing. */
+void _nullDataHandler(Object value) {}
+
+/** Default error handler, reports the error to the current zone's handler. */
+void _nullErrorHandler(Object error, [StackTrace stackTrace]) {
+  Zone.current.handleUncaughtError(error, stackTrace);
+}
+
+/** Default done handler, does nothing. */
+void _nullDoneHandler() {}
+
+/** A delayed event on a buffering stream subscription. */
+abstract class _DelayedEvent<T> {
+  /** Added as a linked list on the [StreamController]. */
+  _DelayedEvent next;
+  /** Execute the delayed event on the [StreamController]. */
+  void perform(_EventDispatch<T> dispatch);
+}
+
+/** A delayed data event. */
+class _DelayedData<T> extends _DelayedEvent<T> {
+  final T value;
+  _DelayedData(this.value);
+  void perform(_EventDispatch<T> dispatch) {
+    dispatch._sendData(value);
+  }
+}
+
+/** A delayed error event. */
+class _DelayedError extends _DelayedEvent {
+  final error;
+  final StackTrace stackTrace;
+
+  _DelayedError(this.error, this.stackTrace);
+  void perform(_EventDispatch dispatch) {
+    dispatch._sendError(error, stackTrace);
+  }
+}
+
+/** A delayed done event. */
+class _DelayedDone implements _DelayedEvent {
+  const _DelayedDone();
+  void perform(_EventDispatch dispatch) {
+    dispatch._sendDone();
+  }
+
+  _DelayedEvent get next => null;
+
+  void set next(_DelayedEvent _) {
+    throw new StateError("No events after a done.");
+  }
+}
+
+/** Superclass for provider of pending events. */
+abstract class _PendingEvents<T> {
+  // No async event has been scheduled.
+  static const int _STATE_UNSCHEDULED = 0;
+  // An async event has been scheduled to run a function.
+  static const int _STATE_SCHEDULED = 1;
+  // An async event has been scheduled, but it will do nothing when it runs.
+  // Async events can't be preempted.
+  static const int _STATE_CANCELED = 3;
+
+  /**
+   * State of being scheduled.
+   *
+   * Set to [_STATE_SCHEDULED] when pending events are scheduled for
+   * async dispatch. Since we can't cancel a [scheduleMicrotask] call, if
+   * scheduling is "canceled", the _state is simply set to [_STATE_CANCELED]
+   * which will make the async code do nothing except resetting [_state].
+   *
+   * If events are scheduled while the state is [_STATE_CANCELED], it is
+   * merely switched back to [_STATE_SCHEDULED], but no new call to
+   * [scheduleMicrotask] is performed.
+   */
+  int _state = _STATE_UNSCHEDULED;
+
+  bool get isEmpty;
+
+  bool get isScheduled => _state == _STATE_SCHEDULED;
+  bool get _eventScheduled => _state >= _STATE_SCHEDULED;
+
+  /**
+   * Schedule an event to run later.
+   *
+   * If called more than once, it should be called with the same dispatch as
+   * argument each time. It may reuse an earlier argument in some cases.
+   */
+  void schedule(_EventDispatch<T> dispatch) {
+    if (isScheduled) return;
+    assert(!isEmpty);
+    if (_eventScheduled) {
+      assert(_state == _STATE_CANCELED);
+      _state = _STATE_SCHEDULED;
+      return;
+    }
+    scheduleMicrotask(() {
+      int oldState = _state;
+      _state = _STATE_UNSCHEDULED;
+      if (oldState == _STATE_CANCELED) return;
+      handleNext(dispatch);
+    });
+    _state = _STATE_SCHEDULED;
+  }
+
+  void cancelSchedule() {
+    if (isScheduled) _state = _STATE_CANCELED;
+  }
+
+  void handleNext(_EventDispatch<T> dispatch);
+
+  /** Throw away any pending events and cancel scheduled events. */
+  void clear();
+}
+
+/** Class holding pending events for a [_StreamImpl]. */
+class _StreamImplEvents<T> extends _PendingEvents<T> {
+  /// Single linked list of [_DelayedEvent] objects.
+  _DelayedEvent firstPendingEvent;
+
+  /// Last element in the list of pending events. New events are added after it.
+  _DelayedEvent lastPendingEvent;
+
+  bool get isEmpty => lastPendingEvent == null;
+
+  void add(_DelayedEvent event) {
+    if (lastPendingEvent == null) {
+      firstPendingEvent = lastPendingEvent = event;
+    } else {
+      lastPendingEvent = lastPendingEvent.next = event;
+    }
+  }
+
+  void handleNext(_EventDispatch<T> dispatch) {
+    assert(!isScheduled);
+    _DelayedEvent event = firstPendingEvent;
+    firstPendingEvent = event.next;
+    if (firstPendingEvent == null) {
+      lastPendingEvent = null;
+    }
+    event.perform(dispatch);
+  }
+
+  void clear() {
+    if (isScheduled) cancelSchedule();
+    firstPendingEvent = lastPendingEvent = null;
+  }
+}
+
+typedef void _BroadcastCallback<T>(StreamSubscription<T> subscription);
+
+/**
+ * Done subscription that will send one done event as soon as possible.
+ */
+class _DoneStreamSubscription<T> implements StreamSubscription<T> {
+  static const int _DONE_SENT = 1;
+  static const int _SCHEDULED = 2;
+  static const int _PAUSED = 4;
+
+  final Zone _zone;
+  int _state = 0;
+  _DoneHandler _onDone;
+
+  _DoneStreamSubscription(this._onDone) : _zone = Zone.current {
+    _schedule();
+  }
+
+  bool get _isSent => (_state & _DONE_SENT) != 0;
+  bool get _isScheduled => (_state & _SCHEDULED) != 0;
+  bool get isPaused => _state >= _PAUSED;
+
+  void _schedule() {
+    if (_isScheduled) return;
+    _zone.scheduleMicrotask(_sendDone);
+    _state |= _SCHEDULED;
+  }
+
+  void onData(void handleData(T data)) {}
+  void onError(Function handleError) {}
+  void onDone(void handleDone()) {
+    _onDone = handleDone;
+  }
+
+  void pause([Future resumeSignal]) {
+    _state += _PAUSED;
+    if (resumeSignal != null) resumeSignal.whenComplete(resume);
+  }
+
+  void resume() {
+    if (isPaused) {
+      _state -= _PAUSED;
+      if (!isPaused && !_isSent) {
+        _schedule();
+      }
+    }
+  }
+
+  Future cancel() => Future._nullFuture;
+
+  Future<E> asFuture<E>([E futureValue]) {
+    _Future<E> result = new _Future<E>();
+    _onDone = () {
+      result._completeWithValue(futureValue);
+    };
+    return result;
+  }
+
+  void _sendDone() {
+    _state &= ~_SCHEDULED;
+    if (isPaused) return;
+    _state |= _DONE_SENT;
+    if (_onDone != null) _zone.runGuarded(_onDone);
+  }
+}
+
+class _AsBroadcastStream<T> extends Stream<T> {
+  final Stream<T> _source;
+  final _BroadcastCallback<T> _onListenHandler;
+  final _BroadcastCallback<T> _onCancelHandler;
+  final Zone _zone;
+
+  _AsBroadcastStreamController<T> _controller;
+  StreamSubscription<T> _subscription;
+
+  _AsBroadcastStream(
+      this._source,
+      void onListenHandler(StreamSubscription<T> subscription),
+      void onCancelHandler(StreamSubscription<T> subscription))
+      // TODO(floitsch): the return type should be void and should be
+      // inferred.
+      : _onListenHandler = Zone.current
+            .registerUnaryCallback<dynamic, StreamSubscription<T>>(
+                onListenHandler),
+        _onCancelHandler = Zone.current
+            .registerUnaryCallback<dynamic, StreamSubscription<T>>(
+                onCancelHandler),
+        _zone = Zone.current {
+    _controller = new _AsBroadcastStreamController<T>(_onListen, _onCancel);
+  }
+
+  bool get isBroadcast => true;
+
+  StreamSubscription<T> listen(void onData(T data),
+      {Function onError, void onDone(), bool cancelOnError}) {
+    if (_controller == null || _controller.isClosed) {
+      // Return a dummy subscription backed by nothing, since
+      // it will only ever send one done event.
+      return new _DoneStreamSubscription<T>(onDone);
+    }
+    _subscription ??= _source.listen(_controller.add,
+        onError: _controller.addError, onDone: _controller.close);
+    cancelOnError = identical(true, cancelOnError);
+    return _controller._subscribe(onData, onError, onDone, cancelOnError);
+  }
+
+  void _onCancel() {
+    bool shutdown = (_controller == null) || _controller.isClosed;
+    if (_onCancelHandler != null) {
+      _zone.runUnary(
+          _onCancelHandler, new _BroadcastSubscriptionWrapper<T>(this));
+    }
+    if (shutdown) {
+      if (_subscription != null) {
+        _subscription.cancel();
+        _subscription = null;
+      }
+    }
+  }
+
+  void _onListen() {
+    if (_onListenHandler != null) {
+      _zone.runUnary(
+          _onListenHandler, new _BroadcastSubscriptionWrapper<T>(this));
+    }
+  }
+
+  // Methods called from _BroadcastSubscriptionWrapper.
+  void _cancelSubscription() {
+    if (_subscription == null) return;
+    // Called by [_controller] when it has no subscribers left.
+    StreamSubscription subscription = _subscription;
+    _subscription = null;
+    _controller = null; // Marks the stream as no longer listenable.
+    subscription.cancel();
+  }
+
+  void _pauseSubscription(Future resumeSignal) {
+    if (_subscription == null) return;
+    _subscription.pause(resumeSignal);
+  }
+
+  void _resumeSubscription() {
+    if (_subscription == null) return;
+    _subscription.resume();
+  }
+
+  bool get _isSubscriptionPaused {
+    if (_subscription == null) return false;
+    return _subscription.isPaused;
+  }
+}
+
+/**
+ * Wrapper for subscription that disallows changing handlers.
+ */
+class _BroadcastSubscriptionWrapper<T> implements StreamSubscription<T> {
+  final _AsBroadcastStream _stream;
+
+  _BroadcastSubscriptionWrapper(this._stream);
+
+  void onData(void handleData(T data)) {
+    throw new UnsupportedError(
+        "Cannot change handlers of asBroadcastStream source subscription.");
+  }
+
+  void onError(Function handleError) {
+    throw new UnsupportedError(
+        "Cannot change handlers of asBroadcastStream source subscription.");
+  }
+
+  void onDone(void handleDone()) {
+    throw new UnsupportedError(
+        "Cannot change handlers of asBroadcastStream source subscription.");
+  }
+
+  void pause([Future resumeSignal]) {
+    _stream._pauseSubscription(resumeSignal);
+  }
+
+  void resume() {
+    _stream._resumeSubscription();
+  }
+
+  Future cancel() {
+    _stream._cancelSubscription();
+    return Future._nullFuture;
+  }
+
+  bool get isPaused {
+    return _stream._isSubscriptionPaused;
+  }
+
+  Future<E> asFuture<E>([E futureValue]) {
+    throw new UnsupportedError(
+        "Cannot change handlers of asBroadcastStream source subscription.");
+  }
+}
+
+/**
+ * Simple implementation of [StreamIterator].
+ *
+ * Pauses the stream between calls to [moveNext].
+ */
+class _StreamIterator<T> implements StreamIterator<T> {
+  // The stream iterator is always in one of four states.
+  // The value of the [_stateData] field depends on the state.
+  //
+  // When `_subscription == null` and `_stateData != null`:
+  // The stream iterator has been created, but [moveNext] has not been called
+  // yet. The [_stateData] field contains the stream to listen to on the first
+  // call to [moveNext] and [current] returns `null`.
+  //
+  // When `_subscription != null` and `!_isPaused`:
+  // The user has called [moveNext] and the iterator is waiting for the next
+  // event. The [_stateData] field contains the [_Future] returned by the
+  // [_moveNext] call and [current] returns `null.`
+  //
+  // When `_subscription != null` and `_isPaused`:
+  // The most recent call to [moveNext] has completed with a `true` value
+  // and [current] provides the value of the data event.
+  // The [_stateData] field contains the [current] value.
+  //
+  // When `_subscription == null` and `_stateData == null`:
+  // The stream has completed or been canceled using [cancel].
+  // The stream completes on either a done event or an error event.
+  // The last call to [moveNext] has completed with `false` and [current]
+  // returns `null`.
+
+  /// Subscription being listened to.
+  ///
+  /// Set to `null` when the stream subscription is done or canceled.
+  StreamSubscription _subscription;
+
+  /// Data value depending on the current state.
+  ///
+  /// Before first call to [moveNext]: The stream to listen to.
+  ///
+  /// After calling [moveNext] but before the returned future completes:
+  /// The returned future.
+  ///
+  /// After calling [moveNext] and the returned future has completed
+  /// with `true`: The value of [current].
+  ///
+  /// After calling [moveNext] and the returned future has completed
+  /// with `false`, or after calling [cancel]: `null`.
+  Object _stateData;
+
+  /// Whether the iterator is between calls to `moveNext`.
+  /// This will usually cause the [_subscription] to be paused, but as an
+  /// optimization, we only pause after the [moveNext] future has been
+  /// completed.
+  bool _isPaused = false;
+
+  _StreamIterator(final Stream<T> stream)
+      : _stateData = stream ?? (throw ArgumentError.notNull("stream"));
+
+  T get current {
+    if (_subscription != null && _isPaused) {
+      return _stateData;
+    }
+    return null;
+  }
+
+  Future<bool> moveNext() {
+    if (_subscription != null) {
+      if (_isPaused) {
+        var future = new _Future<bool>();
+        _stateData = future;
+        _isPaused = false;
+        _subscription.resume();
+        return future;
+      }
+      throw new StateError("Already waiting for next.");
+    }
+    return _initializeOrDone();
+  }
+
+  /// Called if there is no active subscription when [moveNext] is called.
+  ///
+  /// Either starts listening on the stream if this is the first call to
+  /// [moveNext], or returns a `false` future because the stream has already
+  /// ended.
+  Future<bool> _initializeOrDone() {
+    assert(_subscription == null);
+    var stateData = _stateData;
+    if (stateData != null) {
+      Stream<T> stream = stateData;
+      _subscription = stream.listen(_onData,
+          onError: _onError, onDone: _onDone, cancelOnError: true);
+      var future = new _Future<bool>();
+      _stateData = future;
+      return future;
+    }
+    return Future._falseFuture;
+  }
+
+  Future cancel() {
+    StreamSubscription<T> subscription = _subscription;
+    Object stateData = _stateData;
+    _stateData = null;
+    if (subscription != null) {
+      _subscription = null;
+      if (!_isPaused) {
+        _Future<bool> future = stateData;
+        future._asyncComplete(false);
+      }
+      return subscription.cancel();
+    }
+    return Future._nullFuture;
+  }
+
+  void _onData(T data) {
+    assert(_subscription != null && !_isPaused);
+    _Future<bool> moveNextFuture = _stateData;
+    _stateData = data;
+    _isPaused = true;
+    moveNextFuture._complete(true);
+    if (_subscription != null && _isPaused) _subscription.pause();
+  }
+
+  void _onError(Object error, [StackTrace stackTrace]) {
+    assert(_subscription != null && !_isPaused);
+    _Future<bool> moveNextFuture = _stateData;
+    _subscription = null;
+    _stateData = null;
+    moveNextFuture._completeError(error, stackTrace);
+  }
+
+  void _onDone() {
+    assert(_subscription != null && !_isPaused);
+    _Future<bool> moveNextFuture = _stateData;
+    _subscription = null;
+    _stateData = null;
+    moveNextFuture._complete(false);
+  }
+}
+
+/** An empty broadcast stream, sending a done event as soon as possible. */
+class _EmptyStream<T> extends Stream<T> {
+  const _EmptyStream() : super._internal();
+  bool get isBroadcast => true;
+  StreamSubscription<T> listen(void onData(T data),
+      {Function onError, void onDone(), bool cancelOnError}) {
+    return new _DoneStreamSubscription<T>(onDone);
+  }
+}
diff --git a/sdk_nnbd/lib/async/stream_pipe.dart b/sdk_nnbd/lib/async/stream_pipe.dart
new file mode 100644
index 0000000..e526179
--- /dev/null
+++ b/sdk_nnbd/lib/async/stream_pipe.dart
@@ -0,0 +1,500 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.async;
+
+/** Runs user code and takes actions depending on success or failure. */
+_runUserCode<T>(
+    T userCode(), onSuccess(T value), onError(error, StackTrace stackTrace)) {
+  try {
+    onSuccess(userCode());
+  } catch (e, s) {
+    AsyncError replacement = Zone.current.errorCallback(e, s);
+    if (replacement == null) {
+      onError(e, s);
+    } else {
+      var error = _nonNullError(replacement.error);
+      var stackTrace = replacement.stackTrace;
+      onError(error, stackTrace);
+    }
+  }
+}
+
+/** Helper function to cancel a subscription and wait for the potential future,
+  before completing with an error. */
+void _cancelAndError(StreamSubscription subscription, _Future future, error,
+    StackTrace stackTrace) {
+  var cancelFuture = subscription.cancel();
+  if (cancelFuture != null && !identical(cancelFuture, Future._nullFuture)) {
+    cancelFuture.whenComplete(() => future._completeError(error, stackTrace));
+  } else {
+    future._completeError(error, stackTrace);
+  }
+}
+
+void _cancelAndErrorWithReplacement(StreamSubscription subscription,
+    _Future future, error, StackTrace stackTrace) {
+  AsyncError replacement = Zone.current.errorCallback(error, stackTrace);
+  if (replacement != null) {
+    error = _nonNullError(replacement.error);
+    stackTrace = replacement.stackTrace;
+  }
+  _cancelAndError(subscription, future, error, stackTrace);
+}
+
+typedef void _ErrorCallback(error, StackTrace stackTrace);
+
+/** Helper function to make an onError argument to [_runUserCode]. */
+_ErrorCallback _cancelAndErrorClosure(
+    StreamSubscription subscription, _Future future) {
+  return (error, StackTrace stackTrace) {
+    _cancelAndError(subscription, future, error, stackTrace);
+  };
+}
+
+/** Helper function to cancel a subscription and wait for the potential future,
+  before completing with a value. */
+void _cancelAndValue(StreamSubscription subscription, _Future future, value) {
+  var cancelFuture = subscription.cancel();
+  if (cancelFuture != null && !identical(cancelFuture, Future._nullFuture)) {
+    cancelFuture.whenComplete(() => future._complete(value));
+  } else {
+    future._complete(value);
+  }
+}
+
+/**
+ * A [Stream] that forwards subscriptions to another stream.
+ *
+ * This stream implements [Stream], but forwards all subscriptions
+ * to an underlying stream, and wraps the returned subscription to
+ * modify the events on the way.
+ *
+ * This class is intended for internal use only.
+ */
+abstract class _ForwardingStream<S, T> extends Stream<T> {
+  final Stream<S> _source;
+
+  _ForwardingStream(this._source);
+
+  bool get isBroadcast => _source.isBroadcast;
+
+  StreamSubscription<T> listen(void onData(T value),
+      {Function onError, void onDone(), bool cancelOnError}) {
+    cancelOnError = identical(true, cancelOnError);
+    return _createSubscription(onData, onError, onDone, cancelOnError);
+  }
+
+  StreamSubscription<T> _createSubscription(void onData(T data),
+      Function onError, void onDone(), bool cancelOnError) {
+    return new _ForwardingStreamSubscription<S, T>(
+        this, onData, onError, onDone, cancelOnError);
+  }
+
+  // Override the following methods in subclasses to change the behavior.
+
+  void _handleData(S data, _EventSink<T> sink) {
+    sink._add(data as Object);
+  }
+
+  void _handleError(error, StackTrace stackTrace, _EventSink<T> sink) {
+    sink._addError(error, stackTrace);
+  }
+
+  void _handleDone(_EventSink<T> sink) {
+    sink._close();
+  }
+}
+
+/**
+ * Abstract superclass for subscriptions that forward to other subscriptions.
+ */
+class _ForwardingStreamSubscription<S, T>
+    extends _BufferingStreamSubscription<T> {
+  final _ForwardingStream<S, T> _stream;
+
+  StreamSubscription<S> _subscription;
+
+  _ForwardingStreamSubscription(this._stream, void onData(T data),
+      Function onError, void onDone(), bool cancelOnError)
+      : super(onData, onError, onDone, cancelOnError) {
+    _subscription = _stream._source
+        .listen(_handleData, onError: _handleError, onDone: _handleDone);
+  }
+
+  // _StreamSink interface.
+  // Transformers sending more than one event have no way to know if the stream
+  // is canceled or closed after the first, so we just ignore remaining events.
+
+  void _add(T data) {
+    if (_isClosed) return;
+    super._add(data);
+  }
+
+  void _addError(Object error, StackTrace stackTrace) {
+    if (_isClosed) return;
+    super._addError(error, stackTrace);
+  }
+
+  // StreamSubscription callbacks.
+
+  void _onPause() {
+    if (_subscription == null) return;
+    _subscription.pause();
+  }
+
+  void _onResume() {
+    if (_subscription == null) return;
+    _subscription.resume();
+  }
+
+  Future _onCancel() {
+    if (_subscription != null) {
+      StreamSubscription subscription = _subscription;
+      _subscription = null;
+      return subscription.cancel();
+    }
+    return null;
+  }
+
+  // Methods used as listener on source subscription.
+
+  void _handleData(S data) {
+    _stream._handleData(data, this);
+  }
+
+  void _handleError(error, StackTrace stackTrace) {
+    _stream._handleError(error, stackTrace, this);
+  }
+
+  void _handleDone() {
+    _stream._handleDone(this);
+  }
+}
+
+// -------------------------------------------------------------------
+// Stream transformers used by the default Stream implementation.
+// -------------------------------------------------------------------
+
+typedef bool _Predicate<T>(T value);
+
+void _addErrorWithReplacement(_EventSink sink, error, StackTrace stackTrace) {
+  AsyncError replacement = Zone.current.errorCallback(error, stackTrace);
+  if (replacement != null) {
+    error = _nonNullError(replacement.error);
+    stackTrace = replacement.stackTrace;
+  }
+  sink._addError(error, stackTrace);
+}
+
+class _WhereStream<T> extends _ForwardingStream<T, T> {
+  final _Predicate<T> _test;
+
+  _WhereStream(Stream<T> source, bool test(T value))
+      : _test = test,
+        super(source);
+
+  void _handleData(T inputEvent, _EventSink<T> sink) {
+    bool satisfies;
+    try {
+      satisfies = _test(inputEvent);
+    } catch (e, s) {
+      _addErrorWithReplacement(sink, e, s);
+      return;
+    }
+    if (satisfies) {
+      sink._add(inputEvent);
+    }
+  }
+}
+
+typedef T _Transformation<S, T>(S value);
+
+/**
+ * A stream pipe that converts data events before passing them on.
+ */
+class _MapStream<S, T> extends _ForwardingStream<S, T> {
+  final _Transformation<S, T> _transform;
+
+  _MapStream(Stream<S> source, T transform(S event))
+      : this._transform = transform,
+        super(source);
+
+  void _handleData(S inputEvent, _EventSink<T> sink) {
+    T outputEvent;
+    try {
+      outputEvent = _transform(inputEvent);
+    } catch (e, s) {
+      _addErrorWithReplacement(sink, e, s);
+      return;
+    }
+    sink._add(outputEvent);
+  }
+}
+
+/**
+ * A stream pipe that converts data events before passing them on.
+ */
+class _ExpandStream<S, T> extends _ForwardingStream<S, T> {
+  final _Transformation<S, Iterable<T>> _expand;
+
+  _ExpandStream(Stream<S> source, Iterable<T> expand(S event))
+      : this._expand = expand,
+        super(source);
+
+  void _handleData(S inputEvent, _EventSink<T> sink) {
+    try {
+      for (T value in _expand(inputEvent)) {
+        sink._add(value);
+      }
+    } catch (e, s) {
+      // If either _expand or iterating the generated iterator throws,
+      // we abort the iteration.
+      _addErrorWithReplacement(sink, e, s);
+    }
+  }
+}
+
+typedef bool _ErrorTest(error);
+
+/**
+ * A stream pipe that converts or disposes error events
+ * before passing them on.
+ */
+class _HandleErrorStream<T> extends _ForwardingStream<T, T> {
+  final Function _transform;
+  final _ErrorTest _test;
+
+  _HandleErrorStream(Stream<T> source, Function onError, bool test(error))
+      : this._transform = onError,
+        this._test = test,
+        super(source);
+
+  void _handleError(Object error, StackTrace stackTrace, _EventSink<T> sink) {
+    bool matches = true;
+    if (_test != null) {
+      try {
+        matches = _test(error);
+      } catch (e, s) {
+        _addErrorWithReplacement(sink, e, s);
+        return;
+      }
+    }
+    if (matches) {
+      try {
+        _invokeErrorHandler(_transform, error, stackTrace);
+      } catch (e, s) {
+        if (identical(e, error)) {
+          sink._addError(error, stackTrace);
+        } else {
+          _addErrorWithReplacement(sink, e, s);
+        }
+        return;
+      }
+    } else {
+      sink._addError(error, stackTrace);
+    }
+  }
+}
+
+class _TakeStream<T> extends _ForwardingStream<T, T> {
+  final int _count;
+
+  _TakeStream(Stream<T> source, int count)
+      : this._count = count,
+        super(source) {
+    // This test is done early to avoid handling an async error
+    // in the _handleData method.
+    ArgumentError.checkNotNull(count, "count");
+  }
+
+  StreamSubscription<T> _createSubscription(void onData(T data),
+      Function onError, void onDone(), bool cancelOnError) {
+    if (_count == 0) {
+      _source.listen(null).cancel();
+      return new _DoneStreamSubscription<T>(onDone);
+    }
+    return new _StateStreamSubscription<T>(
+        this, onData, onError, onDone, cancelOnError, _count);
+  }
+
+  void _handleData(T inputEvent, _EventSink<T> sink) {
+    _StateStreamSubscription<T> subscription = sink;
+    int count = subscription._count;
+    if (count > 0) {
+      sink._add(inputEvent);
+      count -= 1;
+      subscription._count = count;
+      if (count == 0) {
+        // Closing also unsubscribes all subscribers, which unsubscribes
+        // this from source.
+        sink._close();
+      }
+    }
+  }
+}
+
+/**
+ * A [_ForwardingStreamSubscription] with one extra state field.
+ *
+ * Use by several different classes, storing an integer, bool or general.
+ */
+class _StateStreamSubscription<T> extends _ForwardingStreamSubscription<T, T> {
+  // Raw state field. Typed access provided by getters and setters below.
+  var _sharedState;
+
+  _StateStreamSubscription(_ForwardingStream<T, T> stream, void onData(T data),
+      Function onError, void onDone(), bool cancelOnError, this._sharedState)
+      : super(stream, onData, onError, onDone, cancelOnError);
+
+  bool get _flag => _sharedState;
+  void set _flag(bool flag) {
+    _sharedState = flag;
+  }
+
+  int get _count => _sharedState;
+  void set _count(int count) {
+    _sharedState = count;
+  }
+
+  Object get _value => _sharedState;
+  void set _value(Object value) {
+    _sharedState = value;
+  }
+}
+
+class _TakeWhileStream<T> extends _ForwardingStream<T, T> {
+  final _Predicate<T> _test;
+
+  _TakeWhileStream(Stream<T> source, bool test(T value))
+      : this._test = test,
+        super(source);
+
+  void _handleData(T inputEvent, _EventSink<T> sink) {
+    bool satisfies;
+    try {
+      satisfies = _test(inputEvent);
+    } catch (e, s) {
+      _addErrorWithReplacement(sink, e, s);
+      // The test didn't say true. Didn't say false either, but we stop anyway.
+      sink._close();
+      return;
+    }
+    if (satisfies) {
+      sink._add(inputEvent);
+    } else {
+      sink._close();
+    }
+  }
+}
+
+class _SkipStream<T> extends _ForwardingStream<T, T> {
+  final int _count;
+
+  _SkipStream(Stream<T> source, int count)
+      : this._count = count,
+        super(source) {
+    // This test is done early to avoid handling an async error
+    // in the _handleData method.
+    ArgumentError.checkNotNull(count, "count");
+    RangeError.checkNotNegative(count, "count");
+  }
+
+  StreamSubscription<T> _createSubscription(void onData(T data),
+      Function onError, void onDone(), bool cancelOnError) {
+    return new _StateStreamSubscription<T>(
+        this, onData, onError, onDone, cancelOnError, _count);
+  }
+
+  void _handleData(T inputEvent, _EventSink<T> sink) {
+    _StateStreamSubscription<T> subscription = sink;
+    int count = subscription._count;
+    if (count > 0) {
+      subscription._count = count - 1;
+      return;
+    }
+    sink._add(inputEvent);
+  }
+}
+
+class _SkipWhileStream<T> extends _ForwardingStream<T, T> {
+  final _Predicate<T> _test;
+
+  _SkipWhileStream(Stream<T> source, bool test(T value))
+      : this._test = test,
+        super(source);
+
+  StreamSubscription<T> _createSubscription(void onData(T data),
+      Function onError, void onDone(), bool cancelOnError) {
+    return new _StateStreamSubscription<T>(
+        this, onData, onError, onDone, cancelOnError, false);
+  }
+
+  void _handleData(T inputEvent, _EventSink<T> sink) {
+    _StateStreamSubscription<T> subscription = sink;
+    bool hasFailed = subscription._flag;
+    if (hasFailed) {
+      sink._add(inputEvent);
+      return;
+    }
+    bool satisfies;
+    try {
+      satisfies = _test(inputEvent);
+    } catch (e, s) {
+      _addErrorWithReplacement(sink, e, s);
+      // A failure to return a boolean is considered "not matching".
+      subscription._flag = true;
+      return;
+    }
+    if (!satisfies) {
+      subscription._flag = true;
+      sink._add(inputEvent);
+    }
+  }
+}
+
+typedef bool _Equality<T>(T a, T b);
+
+class _DistinctStream<T> extends _ForwardingStream<T, T> {
+  static final _SENTINEL = new Object();
+
+  final _Equality<T> _equals;
+
+  _DistinctStream(Stream<T> source, bool equals(T a, T b))
+      : _equals = equals,
+        super(source);
+
+  StreamSubscription<T> _createSubscription(void onData(T data),
+      Function onError, void onDone(), bool cancelOnError) {
+    return new _StateStreamSubscription<T>(
+        this, onData, onError, onDone, cancelOnError, _SENTINEL);
+  }
+
+  void _handleData(T inputEvent, _EventSink<T> sink) {
+    _StateStreamSubscription<T> subscription = sink;
+    var previous = subscription._value;
+    if (identical(previous, _SENTINEL)) {
+      // First event.
+      subscription._value = inputEvent;
+      sink._add(inputEvent);
+    } else {
+      T previousEvent = previous;
+      bool isEqual;
+      try {
+        if (_equals == null) {
+          isEqual = (previousEvent == inputEvent);
+        } else {
+          isEqual = _equals(previousEvent, inputEvent);
+        }
+      } catch (e, s) {
+        _addErrorWithReplacement(sink, e, s);
+        return;
+      }
+      if (!isEqual) {
+        sink._add(inputEvent);
+        subscription._value = inputEvent;
+      }
+    }
+  }
+}
diff --git a/sdk_nnbd/lib/async/stream_transformers.dart b/sdk_nnbd/lib/async/stream_transformers.dart
new file mode 100644
index 0000000..9ec13bd
--- /dev/null
+++ b/sdk_nnbd/lib/async/stream_transformers.dart
@@ -0,0 +1,336 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.async;
+
+/**
+ * Wraps an [_EventSink] so it exposes only the [EventSink] interface.
+ */
+class _EventSinkWrapper<T> implements EventSink<T> {
+  _EventSink _sink;
+  _EventSinkWrapper(this._sink);
+
+  void add(T data) {
+    _sink._add(data);
+  }
+
+  void addError(error, [StackTrace stackTrace]) {
+    _sink._addError(error, stackTrace);
+  }
+
+  void close() {
+    _sink._close();
+  }
+}
+
+/**
+ * A StreamSubscription that pipes data through a sink.
+ *
+ * The constructor of this class takes a [_SinkMapper] which maps from
+ * [EventSink] to [EventSink]. The input to the mapper is the output of
+ * the transformation. The returned sink is the transformation's input.
+ */
+class _SinkTransformerStreamSubscription<S, T>
+    extends _BufferingStreamSubscription<T> {
+  /// The transformer's input sink.
+  EventSink<S> _transformerSink;
+
+  /// The subscription to the input stream.
+  StreamSubscription<S> _subscription;
+
+  _SinkTransformerStreamSubscription(Stream<S> source, _SinkMapper<S, T> mapper,
+      void onData(T data), Function onError, void onDone(), bool cancelOnError)
+      // We set the adapter's target only when the user is allowed to send data.
+      : super(onData, onError, onDone, cancelOnError) {
+    _EventSinkWrapper<T> eventSink = new _EventSinkWrapper<T>(this);
+    _transformerSink = mapper(eventSink);
+    _subscription =
+        source.listen(_handleData, onError: _handleError, onDone: _handleDone);
+  }
+
+  /** Whether this subscription is still subscribed to its source. */
+  bool get _isSubscribed => _subscription != null;
+
+  // _EventSink interface.
+
+  /**
+   * Adds an event to this subscriptions.
+   *
+   * Contrary to normal [_BufferingStreamSubscription]s we may receive
+   * events when the stream is already closed. Report them as state
+   * error.
+   */
+  void _add(T data) {
+    if (_isClosed) {
+      throw new StateError("Stream is already closed");
+    }
+    super._add(data);
+  }
+
+  /**
+   * Adds an error event to this subscriptions.
+   *
+   * Contrary to normal [_BufferingStreamSubscription]s we may receive
+   * events when the stream is already closed. Report them as state
+   * error.
+   */
+  void _addError(Object error, StackTrace stackTrace) {
+    if (_isClosed) {
+      throw new StateError("Stream is already closed");
+    }
+    super._addError(error, stackTrace);
+  }
+
+  /**
+   * Adds a close event to this subscriptions.
+   *
+   * Contrary to normal [_BufferingStreamSubscription]s we may receive
+   * events when the stream is already closed. Report them as state
+   * error.
+   */
+  void _close() {
+    if (_isClosed) {
+      throw new StateError("Stream is already closed");
+    }
+    super._close();
+  }
+
+  // _BufferingStreamSubscription hooks.
+
+  void _onPause() {
+    if (_isSubscribed) _subscription.pause();
+  }
+
+  void _onResume() {
+    if (_isSubscribed) _subscription.resume();
+  }
+
+  Future _onCancel() {
+    if (_isSubscribed) {
+      StreamSubscription subscription = _subscription;
+      _subscription = null;
+      return subscription.cancel();
+    }
+    return null;
+  }
+
+  void _handleData(S data) {
+    try {
+      _transformerSink.add(data);
+    } catch (e, s) {
+      _addError(e, s);
+    }
+  }
+
+  void _handleError(error, [StackTrace stackTrace]) {
+    try {
+      _transformerSink.addError(error, stackTrace);
+    } catch (e, s) {
+      if (identical(e, error)) {
+        _addError(error, stackTrace);
+      } else {
+        _addError(e, s);
+      }
+    }
+  }
+
+  void _handleDone() {
+    try {
+      _subscription = null;
+      _transformerSink.close();
+    } catch (e, s) {
+      _addError(e, s);
+    }
+  }
+}
+
+typedef EventSink<S> _SinkMapper<S, T>(EventSink<T> output);
+
+/**
+ * A StreamTransformer for Sink-mappers.
+ *
+ * A Sink-mapper takes an [EventSink] (its output) and returns another
+ * EventSink (its input).
+ *
+ * Note that this class can be `const`.
+ */
+class _StreamSinkTransformer<S, T> extends StreamTransformerBase<S, T> {
+  final _SinkMapper<S, T> _sinkMapper;
+  const _StreamSinkTransformer(this._sinkMapper);
+
+  Stream<T> bind(Stream<S> stream) =>
+      new _BoundSinkStream<S, T>(stream, _sinkMapper);
+}
+
+/**
+ * The result of binding a StreamTransformer for Sink-mappers.
+ *
+ * It contains the bound Stream and the sink-mapper. Only when the user starts
+ * listening to this stream is the sink-mapper invoked. The result is used
+ * to create a StreamSubscription that transforms events.
+ */
+class _BoundSinkStream<S, T> extends Stream<T> {
+  final _SinkMapper<S, T> _sinkMapper;
+  final Stream<S> _stream;
+
+  bool get isBroadcast => _stream.isBroadcast;
+
+  _BoundSinkStream(this._stream, this._sinkMapper);
+
+  StreamSubscription<T> listen(void onData(T event),
+      {Function onError, void onDone(), bool cancelOnError}) {
+    cancelOnError = identical(true, cancelOnError);
+    StreamSubscription<T> subscription =
+        new _SinkTransformerStreamSubscription<S, T>(
+            _stream, _sinkMapper, onData, onError, onDone, cancelOnError);
+    return subscription;
+  }
+}
+
+/// Data-handler coming from [StreamTransformer.fromHandlers].
+typedef void _TransformDataHandler<S, T>(S data, EventSink<T> sink);
+
+/// Error-handler coming from [StreamTransformer.fromHandlers].
+typedef void _TransformErrorHandler<T>(
+    Object error, StackTrace stackTrace, EventSink<T> sink);
+
+/// Done-handler coming from [StreamTransformer.fromHandlers].
+typedef void _TransformDoneHandler<T>(EventSink<T> sink);
+
+/**
+ * Wraps handlers (from [StreamTransformer.fromHandlers]) into an `EventSink`.
+ *
+ * This way we can reuse the code from [_StreamSinkTransformer].
+ */
+class _HandlerEventSink<S, T> implements EventSink<S> {
+  final _TransformDataHandler<S, T> _handleData;
+  final _TransformErrorHandler<T> _handleError;
+  final _TransformDoneHandler<T> _handleDone;
+
+  /// The output sink where the handlers should send their data into.
+  EventSink<T> _sink;
+
+  _HandlerEventSink(
+      this._handleData, this._handleError, this._handleDone, this._sink) {
+    if (_sink == null) {
+      throw new ArgumentError("The provided sink must not be null.");
+    }
+  }
+
+  bool get _isClosed => _sink == null;
+
+  void add(S data) {
+    if (_isClosed) {
+      throw StateError("Sink is closed");
+    }
+    if (_handleData != null) {
+      _handleData(data, _sink);
+    } else {
+      _sink.add(data as T);
+    }
+  }
+
+  void addError(Object error, [StackTrace stackTrace]) {
+    if (_isClosed) {
+      throw StateError("Sink is closed");
+    }
+    if (_handleError != null) {
+      _handleError(error, stackTrace, _sink);
+    } else {
+      _sink.addError(error, stackTrace);
+    }
+  }
+
+  void close() {
+    if (_isClosed) return;
+    var sink = _sink;
+    _sink = null;
+    if (_handleDone != null) {
+      _handleDone(sink);
+    } else {
+      sink.close();
+    }
+  }
+}
+
+/**
+ * A StreamTransformer that transformers events with the given handlers.
+ *
+ * Note that this transformer can only be used once.
+ */
+class _StreamHandlerTransformer<S, T> extends _StreamSinkTransformer<S, T> {
+  _StreamHandlerTransformer(
+      {void handleData(S data, EventSink<T> sink),
+      void handleError(Object error, StackTrace stackTrace, EventSink<T> sink),
+      void handleDone(EventSink<T> sink)})
+      : super((EventSink<T> outputSink) {
+          return new _HandlerEventSink<S, T>(
+              handleData, handleError, handleDone, outputSink);
+        });
+
+  Stream<T> bind(Stream<S> stream) {
+    return super.bind(stream);
+  }
+}
+
+/**
+ * A StreamTransformer that overrides [StreamTransformer.bind] with a callback.
+ */
+class _StreamBindTransformer<S, T> extends StreamTransformerBase<S, T> {
+  final Stream<T> Function(Stream<S>) _bind;
+  _StreamBindTransformer(this._bind);
+
+  Stream<T> bind(Stream<S> stream) => _bind(stream);
+}
+
+/// A closure mapping a stream and cancelOnError to a StreamSubscription.
+typedef StreamSubscription<T> _SubscriptionTransformer<S, T>(
+    Stream<S> stream, bool cancelOnError);
+
+/**
+ * A [StreamTransformer] that minimizes the number of additional classes.
+ *
+ * Instead of implementing three classes: a [StreamTransformer], a [Stream]
+ * (as the result of a `bind` call) and a [StreamSubscription] (which does the
+ * actual work), this class only requires a function that is invoked when the
+ * last bit (the subscription) of the transformer-workflow is needed.
+ *
+ * The given transformer function maps from Stream and cancelOnError to a
+ * `StreamSubscription`. As such it can also act on `cancel` events, making it
+ * fully general.
+ */
+class _StreamSubscriptionTransformer<S, T> extends StreamTransformerBase<S, T> {
+  final _SubscriptionTransformer<S, T> _onListen;
+
+  const _StreamSubscriptionTransformer(this._onListen);
+
+  Stream<T> bind(Stream<S> stream) =>
+      new _BoundSubscriptionStream<S, T>(stream, _onListen);
+}
+
+/**
+ * A stream transformed by a [_StreamSubscriptionTransformer].
+ *
+ * When this stream is listened to it invokes the [_onListen] function with
+ * the stored [_stream]. Usually the transformer starts listening at this
+ * moment.
+ */
+class _BoundSubscriptionStream<S, T> extends Stream<T> {
+  final _SubscriptionTransformer<S, T> _onListen;
+  final Stream<S> _stream;
+
+  bool get isBroadcast => _stream.isBroadcast;
+
+  _BoundSubscriptionStream(this._stream, this._onListen);
+
+  StreamSubscription<T> listen(void onData(T event),
+      {Function onError, void onDone(), bool cancelOnError}) {
+    cancelOnError = identical(true, cancelOnError);
+    StreamSubscription<T> result = _onListen(_stream, cancelOnError);
+    result.onData(onData);
+    result.onError(onError);
+    result.onDone(onDone);
+    return result;
+  }
+}
diff --git a/sdk_nnbd/lib/async/timer.dart b/sdk_nnbd/lib/async/timer.dart
new file mode 100644
index 0000000..aa2f088
--- /dev/null
+++ b/sdk_nnbd/lib/async/timer.dart
@@ -0,0 +1,127 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.async;
+
+/**
+ * A count-down timer that can be configured to fire once or repeatedly.
+ *
+ * The timer counts down from the specified duration to 0.
+ * When the timer reaches 0, the timer invokes the specified callback function.
+ * Use a periodic timer to repeatedly count down the same interval.
+ *
+ * A negative duration is treated the same as a duration of 0.
+ * If the duration is statically known to be 0, consider using [run].
+ *
+ * Frequently the duration is either a constant or computed as in the
+ * following example (taking advantage of the multiplication operator of
+ * the [Duration] class):
+ * ```dart
+ * const timeout = const Duration(seconds: 3);
+ * const ms = const Duration(milliseconds: 1);
+ *
+ * startTimeout([int milliseconds]) {
+ *   var duration = milliseconds == null ? timeout : ms * milliseconds;
+ *   return new Timer(duration, handleTimeout);
+ * }
+ * ...
+ * void handleTimeout() {  // callback function
+ *   ...
+ * }
+ * ```
+ * Note: If Dart code using Timer is compiled to JavaScript, the finest
+ * granularity available in the browser is 4 milliseconds.
+ *
+ * See [Stopwatch] for measuring elapsed time.
+ */
+abstract class Timer {
+  /**
+   * Creates a new timer.
+   *
+   * The [callback] function is invoked after the given [duration].
+   *
+   */
+  factory Timer(Duration duration, void callback()) {
+    if (Zone.current == Zone.root) {
+      // No need to bind the callback. We know that the root's timer will
+      // be invoked in the root zone.
+      return Zone.current.createTimer(duration, callback);
+    }
+    return Zone.current
+        .createTimer(duration, Zone.current.bindCallbackGuarded(callback));
+  }
+
+  /**
+   * Creates a new repeating timer.
+   *
+   * The [callback] is invoked repeatedly with [duration] intervals until
+   * canceled with the [cancel] function.
+   *
+   * The exact timing depends on the underlying timer implementation.
+   * No more than `n` callbacks will be made in `duration * n` time,
+   * but the time between two consecutive callbacks
+   * can be shorter and longer than `duration`.
+   *
+   * In particular, an implementation may schedule the next callback, e.g.,
+   * a `duration` after either when the previous callback ended,
+   * when the previous callback started, or when the previous callback was
+   * scheduled for - even if the actual callback was delayed.
+   */
+  factory Timer.periodic(Duration duration, void callback(Timer timer)) {
+    if (Zone.current == Zone.root) {
+      // No need to bind the callback. We know that the root's timer will
+      // be invoked in the root zone.
+      return Zone.current.createPeriodicTimer(duration, callback);
+    }
+    var boundCallback = Zone.current.bindUnaryCallbackGuarded<Timer>(callback);
+    return Zone.current.createPeriodicTimer(duration, boundCallback);
+  }
+
+  /**
+   * Runs the given [callback] asynchronously as soon as possible.
+   *
+   * This function is equivalent to `new Timer(Duration.zero, callback)`.
+   */
+  static void run(void callback()) {
+    new Timer(Duration.zero, callback);
+  }
+
+  /**
+   * Cancels the timer.
+   *
+   * Once a [Timer] has been canceled, the callback function will not be called
+   * by the timer. Calling [cancel] more than once on a [Timer] is allowed, and
+   * will have no further effect.
+   */
+  void cancel();
+
+  /**
+   * The number of durations preceding the most recent timer event.
+   *
+   * The value starts at zero and is incremented each time a timer event
+   * occurs, so each callback will see a larger value than the previous one.
+   *
+   * If a periodic timer with a non-zero duration is delayed too much,
+   * so more than one tick should have happened,
+   * all but the last tick in the past are considered "missed",
+   * and no callback is invoked for them.
+   * The [tick] count reflects the number of durations that have passed and
+   * not the number of callback invocations that have happened.
+   */
+  int get tick;
+
+  /**
+   * Returns whether the timer is still active.
+   *
+   * A non-periodic timer is active if the callback has not been executed,
+   * and the timer has not been canceled.
+   *
+   * A periodic timer is active if it has not been canceled.
+   */
+  bool get isActive;
+
+  external static Timer _createTimer(Duration duration, void callback());
+  external static Timer _createPeriodicTimer(
+      Duration duration, void callback(Timer timer));
+}
diff --git a/sdk_nnbd/lib/async/zone.dart b/sdk_nnbd/lib/async/zone.dart
new file mode 100644
index 0000000..911ecff
--- /dev/null
+++ b/sdk_nnbd/lib/async/zone.dart
@@ -0,0 +1,1516 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.async;
+
+typedef R ZoneCallback<R>();
+typedef R ZoneUnaryCallback<R, T>(T arg);
+typedef R ZoneBinaryCallback<R, T1, T2>(T1 arg1, T2 arg2);
+
+typedef HandleUncaughtErrorHandler = void Function(Zone self,
+    ZoneDelegate parent, Zone zone, Object error, StackTrace stackTrace);
+typedef RunHandler = R Function<R>(
+    Zone self, ZoneDelegate parent, Zone zone, R Function() f);
+typedef RunUnaryHandler = R Function<R, T>(
+    Zone self, ZoneDelegate parent, Zone zone, R Function(T arg) f, T arg);
+typedef RunBinaryHandler = R Function<R, T1, T2>(Zone self, ZoneDelegate parent,
+    Zone zone, R Function(T1 arg1, T2 arg2) f, T1 arg1, T2 arg2);
+typedef RegisterCallbackHandler = ZoneCallback<R> Function<R>(
+    Zone self, ZoneDelegate parent, Zone zone, R Function() f);
+typedef RegisterUnaryCallbackHandler = ZoneUnaryCallback<R, T> Function<R, T>(
+    Zone self, ZoneDelegate parent, Zone zone, R Function(T arg) f);
+typedef RegisterBinaryCallbackHandler
+    = ZoneBinaryCallback<R, T1, T2> Function<R, T1, T2>(Zone self,
+        ZoneDelegate parent, Zone zone, R Function(T1 arg1, T2 arg2) f);
+typedef AsyncError ErrorCallbackHandler(Zone self, ZoneDelegate parent,
+    Zone zone, Object error, StackTrace stackTrace);
+typedef void ScheduleMicrotaskHandler(
+    Zone self, ZoneDelegate parent, Zone zone, void f());
+typedef Timer CreateTimerHandler(
+    Zone self, ZoneDelegate parent, Zone zone, Duration duration, void f());
+typedef Timer CreatePeriodicTimerHandler(Zone self, ZoneDelegate parent,
+    Zone zone, Duration period, void f(Timer timer));
+typedef void PrintHandler(
+    Zone self, ZoneDelegate parent, Zone zone, String line);
+typedef Zone ForkHandler(Zone self, ZoneDelegate parent, Zone zone,
+    ZoneSpecification specification, Map zoneValues);
+
+/** Pair of error and stack trace. Returned by [Zone.errorCallback]. */
+class AsyncError implements Error {
+  final Object error;
+  final StackTrace stackTrace;
+
+  AsyncError(this.error, this.stackTrace);
+
+  String toString() => '$error';
+}
+
+class _ZoneFunction<T extends Function> {
+  final _Zone zone;
+  final T function;
+  const _ZoneFunction(this.zone, this.function);
+}
+
+/**
+ * This class provides the specification for a forked zone.
+ *
+ * When forking a new zone (see [Zone.fork]) one can override the default
+ * behavior of the zone by providing callbacks. These callbacks must be
+ * given in an instance of this class.
+ *
+ * Handlers have the same signature as the same-named methods on [Zone] but
+ * receive three additional arguments:
+ *
+ *   1. the zone the handlers are attached to (the "self" zone).
+ *   2. a [ZoneDelegate] to the parent zone.
+ *   3. the zone that first received the request (before the request was
+ *     bubbled up).
+ *
+ * Handlers can either stop propagation the request (by simply not calling the
+ * parent handler), or forward to the parent zone, potentially modifying the
+ * arguments on the way.
+ */
+abstract class ZoneSpecification {
+  /**
+   * Creates a specification with the provided handlers.
+   */
+  const factory ZoneSpecification(
+      {HandleUncaughtErrorHandler handleUncaughtError,
+      RunHandler run,
+      RunUnaryHandler runUnary,
+      RunBinaryHandler runBinary,
+      RegisterCallbackHandler registerCallback,
+      RegisterUnaryCallbackHandler registerUnaryCallback,
+      RegisterBinaryCallbackHandler registerBinaryCallback,
+      ErrorCallbackHandler errorCallback,
+      ScheduleMicrotaskHandler scheduleMicrotask,
+      CreateTimerHandler createTimer,
+      CreatePeriodicTimerHandler createPeriodicTimer,
+      PrintHandler print,
+      ForkHandler fork}) = _ZoneSpecification;
+
+  /**
+   * Creates a specification from [other] with the provided handlers overriding
+   * the ones in [other].
+   */
+  factory ZoneSpecification.from(ZoneSpecification other,
+      {HandleUncaughtErrorHandler handleUncaughtError,
+      RunHandler run,
+      RunUnaryHandler runUnary,
+      RunBinaryHandler runBinary,
+      RegisterCallbackHandler registerCallback,
+      RegisterUnaryCallbackHandler registerUnaryCallback,
+      RegisterBinaryCallbackHandler registerBinaryCallback,
+      ErrorCallbackHandler errorCallback,
+      ScheduleMicrotaskHandler scheduleMicrotask,
+      CreateTimerHandler createTimer,
+      CreatePeriodicTimerHandler createPeriodicTimer,
+      PrintHandler print,
+      ForkHandler fork}) {
+    return new ZoneSpecification(
+        handleUncaughtError: handleUncaughtError ?? other.handleUncaughtError,
+        run: run ?? other.run,
+        runUnary: runUnary ?? other.runUnary,
+        runBinary: runBinary ?? other.runBinary,
+        registerCallback: registerCallback ?? other.registerCallback,
+        registerUnaryCallback:
+            registerUnaryCallback ?? other.registerUnaryCallback,
+        registerBinaryCallback:
+            registerBinaryCallback ?? other.registerBinaryCallback,
+        errorCallback: errorCallback ?? other.errorCallback,
+        scheduleMicrotask: scheduleMicrotask ?? other.scheduleMicrotask,
+        createTimer: createTimer ?? other.createTimer,
+        createPeriodicTimer: createPeriodicTimer ?? other.createPeriodicTimer,
+        print: print ?? other.print,
+        fork: fork ?? other.fork);
+  }
+
+  HandleUncaughtErrorHandler get handleUncaughtError;
+  RunHandler get run;
+  RunUnaryHandler get runUnary;
+  RunBinaryHandler get runBinary;
+  RegisterCallbackHandler get registerCallback;
+  RegisterUnaryCallbackHandler get registerUnaryCallback;
+  RegisterBinaryCallbackHandler get registerBinaryCallback;
+  ErrorCallbackHandler get errorCallback;
+  ScheduleMicrotaskHandler get scheduleMicrotask;
+  CreateTimerHandler get createTimer;
+  CreatePeriodicTimerHandler get createPeriodicTimer;
+  PrintHandler get print;
+  ForkHandler get fork;
+}
+
+/**
+ * Internal [ZoneSpecification] class.
+ *
+ * The implementation wants to rely on the fact that the getters cannot change
+ * dynamically. We thus require users to go through the redirecting
+ * [ZoneSpecification] constructor which instantiates this class.
+ */
+class _ZoneSpecification implements ZoneSpecification {
+  const _ZoneSpecification(
+      {this.handleUncaughtError,
+      this.run,
+      this.runUnary,
+      this.runBinary,
+      this.registerCallback,
+      this.registerUnaryCallback,
+      this.registerBinaryCallback,
+      this.errorCallback,
+      this.scheduleMicrotask,
+      this.createTimer,
+      this.createPeriodicTimer,
+      this.print,
+      this.fork});
+
+  final HandleUncaughtErrorHandler handleUncaughtError;
+  final RunHandler run;
+  final RunUnaryHandler runUnary;
+  final RunBinaryHandler runBinary;
+  final RegisterCallbackHandler registerCallback;
+  final RegisterUnaryCallbackHandler registerUnaryCallback;
+  final RegisterBinaryCallbackHandler registerBinaryCallback;
+  final ErrorCallbackHandler errorCallback;
+  final ScheduleMicrotaskHandler scheduleMicrotask;
+  final CreateTimerHandler createTimer;
+  final CreatePeriodicTimerHandler createPeriodicTimer;
+  final PrintHandler print;
+  final ForkHandler fork;
+}
+
+/**
+ * An adapted view of the parent zone.
+ *
+ * This class allows the implementation of a zone method to invoke methods on
+ * the parent zone while retaining knowledge of the originating zone.
+ *
+ * Custom zones (created through [Zone.fork] or [runZoned]) can provide
+ * implementations of most methods of zones. This is similar to overriding
+ * methods on [Zone], except that this mechanism doesn't require subclassing.
+ *
+ * A custom zone function (provided through a [ZoneSpecification]) typically
+ * records or wraps its parameters and then delegates the operation to its
+ * parent zone using the provided [ZoneDelegate].
+ *
+ * While zones have access to their parent zone (through [Zone.parent]) it is
+ * recommended to call the methods on the provided parent delegate for two
+ * reasons:
+ * 1. the delegate methods take an additional `zone` argument which is the
+ *   zone the action has been initiated in.
+ * 2. delegate calls are more efficient, since the implementation knows how
+ *   to skip zones that would just delegate to their parents.
+ */
+abstract class ZoneDelegate {
+  void handleUncaughtError(Zone zone, error, StackTrace stackTrace);
+  R run<R>(Zone zone, R f());
+  R runUnary<R, T>(Zone zone, R f(T arg), T arg);
+  R runBinary<R, T1, T2>(Zone zone, R f(T1 arg1, T2 arg2), T1 arg1, T2 arg2);
+  ZoneCallback<R> registerCallback<R>(Zone zone, R f());
+  ZoneUnaryCallback<R, T> registerUnaryCallback<R, T>(Zone zone, R f(T arg));
+  ZoneBinaryCallback<R, T1, T2> registerBinaryCallback<R, T1, T2>(
+      Zone zone, R f(T1 arg1, T2 arg2));
+  AsyncError errorCallback(Zone zone, Object error, StackTrace stackTrace);
+  void scheduleMicrotask(Zone zone, void f());
+  Timer createTimer(Zone zone, Duration duration, void f());
+  Timer createPeriodicTimer(Zone zone, Duration period, void f(Timer timer));
+  void print(Zone zone, String line);
+  Zone fork(Zone zone, ZoneSpecification specification, Map zoneValues);
+}
+
+/**
+ * A zone represents an environment that remains stable across asynchronous
+ * calls.
+ *
+ * Code is always executed in the context of a zone, available as
+ * [Zone.current]. The initial `main` function runs in the context of the
+ * default zone ([Zone.root]). Code can be run in a different zone using either
+ * [runZoned], to create a new zone, or [Zone.run] to run code in the context of
+ * an existing zone likely created using [Zone.fork].
+ *
+ * Developers can create a new zone that overrides some of the functionality of
+ * an existing zone. For example, custom zones can replace of modify the
+ * behavior of `print`, timers, microtasks or how uncaught errors are handled.
+ *
+ * The [Zone] class is not subclassable, but users can provide custom zones by
+ * forking an existing zone (usually [Zone.current]) with a [ZoneSpecification].
+ * This is similar to creating a new class that extends the base `Zone` class
+ * and that overrides some methods, except without actually creating a new
+ * class. Instead the overriding methods are provided as functions that
+ * explicitly take the equivalent of their own class, the "super" class and the
+ * `this` object as parameters.
+ *
+ * Asynchronous callbacks always run in the context of the zone where they were
+ * scheduled. This is implemented using two steps:
+ * 1. the callback is first registered using one of [registerCallback],
+ *   [registerUnaryCallback], or [registerBinaryCallback]. This allows the zone
+ *   to record that a callback exists and potentially modify it (by returning a
+ *   different callback). The code doing the registration (e.g., `Future.then`)
+ *   also remembers the current zone so that it can later run the callback in
+ *   that zone.
+ * 2. At a later point the registered callback is run in the remembered zone.
+ *
+ * This is all handled internally by the platform code and most users don't need
+ * to worry about it. However, developers of new asynchronous operations,
+ * provided by the underlying system or through native extensions, must follow
+ * the protocol to be zone compatible.
+ *
+ * For convenience, zones provide [bindCallback] (and the corresponding
+ * [bindUnaryCallback] and [bindBinaryCallback]) to make it easier to respect
+ * the zone contract: these functions first invoke the corresponding `register`
+ * functions and then wrap the returned function so that it runs in the current
+ * zone when it is later asynchronously invoked.
+ *
+ * Similarly, zones provide [bindCallbackGuarded] (and the corresponding
+ * [bindUnaryCallbackGuarded] and [bindBinaryCallbackGuarded]), when the
+ * callback should be invoked through [Zone.runGuarded].
+ */
+abstract class Zone {
+  // Private constructor so that it is not possible instantiate a Zone class.
+  Zone._();
+
+  /**
+   * The root zone.
+   *
+   * All isolate entry functions (`main` or spawned functions) start running in
+   * the root zone (that is, [Zone.current] is identical to [Zone.root] when the
+   * entry function is called). If no custom zone is created, the rest of the
+   * program always runs in the root zone.
+   *
+   * The root zone implements the default behavior of all zone operations.
+   * Many methods, like [registerCallback] do the bare minimum required of the
+   * function, and are only provided as a hook for custom zones. Others, like
+   * [scheduleMicrotask], interact with the underlying system to implement the
+   * desired behavior.
+   */
+  static const Zone root = _rootZone;
+
+  /** The currently running zone. */
+  static Zone _current = _rootZone;
+
+  /** The zone that is currently active. */
+  static Zone get current => _current;
+
+  /**
+   * Handles uncaught asynchronous errors.
+   *
+   * There are two kind of asynchronous errors that are handled by this
+   * function:
+   * 1. Uncaught errors that were thrown in asynchronous callbacks, for example,
+   *   a `throw` in the function passed to [Timer.run].
+   * 2. Asynchronous errors that are pushed through [Future] and [Stream]
+   *   chains, but for which no child registered an error handler.
+   *   Most asynchronous classes, like [Future] or [Stream] push errors to their
+   *   listeners. Errors are propagated this way until either a listener handles
+   *   the error (for example with [Future.catchError]), or no listener is
+   *   available anymore. In the latter case, futures and streams invoke the
+   *   zone's [handleUncaughtError].
+   *
+   * By default, when handled by the root zone, uncaught asynchronous errors are
+   * treated like uncaught synchronous exceptions.
+   */
+  void handleUncaughtError(error, StackTrace stackTrace);
+
+  /**
+   * The parent zone of the this zone.
+   *
+   * Is `null` if `this` is the [root] zone.
+   *
+   * Zones are created by [fork] on an existing zone, or by [runZoned] which
+   * forks the [current] zone. The new zone's parent zone is the zone it was
+   * forked from.
+   */
+  Zone get parent;
+
+  /**
+   * The error zone is the one that is responsible for dealing with uncaught
+   * errors.
+   *
+   * This is the closest parent zone of this zone that provides a
+   * [handleUncaughtError] method.
+   *
+   * Asynchronous errors never cross zone boundaries between zones with
+   * different error handlers.
+   *
+   * Example:
+   * ```
+   * import 'dart:async';
+   *
+   * main() {
+   *   var future;
+   *   runZoned(() {
+   *     // The asynchronous error is caught by the custom zone which prints
+   *     // 'asynchronous error'.
+   *     future = new Future.error("asynchronous error");
+   *   }, onError: (e) { print(e); });  // Creates a zone with an error handler.
+   *   // The following `catchError` handler is never invoked, because the
+   *   // custom zone created by the call to `runZoned` provides an
+   *   // error handler.
+   *   future.catchError((e) { throw "is never reached"; });
+   * }
+   * ```
+   *
+   * Note that errors cannot enter a child zone with a different error handler
+   * either:
+   * ```
+   * import 'dart:async';
+   *
+   * main() {
+   *   runZoned(() {
+   *     // The following asynchronous error is *not* caught by the `catchError`
+   *     // in the nested zone, since errors are not to cross zone boundaries
+   *     // with different error handlers.
+   *     // Instead the error is handled by the current error handler,
+   *     // printing "Caught by outer zone: asynchronous error".
+   *     var future = new Future.error("asynchronous error");
+   *     runZoned(() {
+   *       future.catchError((e) { throw "is never reached"; });
+   *     }, onError: (e) { throw "is never reached"; });
+   *   }, onError: (e) { print("Caught by outer zone: $e"); });
+   * }
+   * ```
+   */
+  Zone get errorZone;
+
+  /**
+   * Returns true if `this` and [otherZone] are in the same error zone.
+   *
+   * Two zones are in the same error zone if they have the same [errorZone].
+   */
+  bool inSameErrorZone(Zone otherZone);
+
+  /**
+   * Creates a new zone as a child of `this`.
+   *
+   * The new zone uses the closures in the given [specification] to override
+   * the current's zone behavior. All specification entries that are `null`
+   * inherit the behavior from the parent zone (`this`).
+   *
+   * The new zone inherits the stored values (accessed through [operator []])
+   * of this zone and updates them with values from [zoneValues], which either
+   * adds new values or overrides existing ones.
+   *
+   * Note that the fork operation is interceptible. A zone can thus change
+   * the zone specification (or zone values), giving the forking zone full
+   * control over the child zone.
+   */
+  Zone fork({ZoneSpecification specification, Map zoneValues});
+
+  /**
+   * Executes [action] in this zone.
+   *
+   * By default (as implemented in the [root] zone), runs [action]
+   * with [current] set to this zone.
+   *
+   * If [action] throws, the synchronous exception is not caught by the zone's
+   * error handler. Use [runGuarded] to achieve that.
+   *
+   * Since the root zone is the only zone that can modify the value of
+   * [current], custom zones intercepting run should always delegate to their
+   * parent zone. They may take actions before and after the call.
+   */
+  R run<R>(R action());
+
+  /**
+   * Executes the given [action] with [argument] in this zone.
+   *
+   * As [run] except that [action] is called with one [argument] instead of
+   * none.
+   */
+  R runUnary<R, T>(R action(T argument), T argument);
+
+  /**
+   * Executes the given [action] with [argument1] and [argument2] in this
+   * zone.
+   *
+   * As [run] except that [action] is called with two arguments instead of none.
+   */
+  R runBinary<R, T1, T2>(
+      R action(T1 argument1, T2 argument2), T1 argument1, T2 argument2);
+
+  /**
+   * Executes the given [action] in this zone and catches synchronous
+   * errors.
+   *
+   * This function is equivalent to:
+   * ```
+   * try {
+   *   this.run(action);
+   * } catch (e, s) {
+   *   this.handleUncaughtError(e, s);
+   * }
+   * ```
+   *
+   * See [run].
+   */
+  void runGuarded(void action());
+
+  /**
+   * Executes the given [action] with [argument] in this zone and
+   * catches synchronous errors.
+   *
+   * See [runGuarded].
+   */
+  void runUnaryGuarded<T>(void action(T argument), T argument);
+
+  /**
+   * Executes the given [action] with [argument1] and [argument2] in this
+   * zone and catches synchronous errors.
+   *
+   * See [runGuarded].
+   */
+  void runBinaryGuarded<T1, T2>(
+      void action(T1 argument1, T2 argument2), T1 argument1, T2 argument2);
+
+  /**
+   * Registers the given callback in this zone.
+   *
+   * When implementing an asynchronous primitive that uses callbacks, the
+   * callback must be registered using [registerCallback] at the point where the
+   * user provides the callback. This allows zones to record other information
+   * that they need at the same time, perhaps even wrapping the callback, so
+   * that the callback is prepared when it is later run in the same zones
+   * (using [run]). For example, a zone may decide
+   * to store the stack trace (at the time of the registration) with the
+   * callback.
+   *
+   * Returns the callback that should be used in place of the provided
+   * [callback]. Frequently zones simply return the original callback.
+   *
+   * Custom zones may intercept this operation. The default implementation in
+   * [Zone.root] returns the original callback unchanged.
+   */
+  ZoneCallback<R> registerCallback<R>(R callback());
+
+  /**
+   * Registers the given callback in this zone.
+   *
+   * Similar to [registerCallback] but with a unary callback.
+   */
+  ZoneUnaryCallback<R, T> registerUnaryCallback<R, T>(R callback(T arg));
+
+  /**
+   * Registers the given callback in this zone.
+   *
+   * Similar to [registerCallback] but with a unary callback.
+   */
+  ZoneBinaryCallback<R, T1, T2> registerBinaryCallback<R, T1, T2>(
+      R callback(T1 arg1, T2 arg2));
+
+  /**
+   *  Registers the provided [callback] and returns a function that will
+   *  execute in this zone.
+   *
+   *  Equivalent to:
+   *
+   *      ZoneCallback registered = this.registerCallback(callback);
+   *      return () => this.run(registered);
+   *
+   */
+  ZoneCallback<R> bindCallback<R>(R callback());
+
+  /**
+   *  Registers the provided [callback] and returns a function that will
+   *  execute in this zone.
+   *
+   *  Equivalent to:
+   *
+   *      ZoneCallback registered = this.registerUnaryCallback(callback);
+   *      return (arg) => thin.runUnary(registered, arg);
+   */
+  ZoneUnaryCallback<R, T> bindUnaryCallback<R, T>(R callback(T argument));
+
+  /**
+   *  Registers the provided [callback] and returns a function that will
+   *  execute in this zone.
+   *
+   *  Equivalent to:
+   *
+   *      ZoneCallback registered = registerBinaryCallback(callback);
+   *      return (arg1, arg2) => thin.runBinary(registered, arg1, arg2);
+   */
+  ZoneBinaryCallback<R, T1, T2> bindBinaryCallback<R, T1, T2>(
+      R callback(T1 argument1, T2 argument2));
+
+  /**
+   * Registers the provided [callback] and returns a function that will
+   * execute in this zone.
+   *
+   * When the function executes, errors are caught and treated as uncaught
+   * errors.
+   *
+   * Equivalent to:
+   *
+   *     ZoneCallback registered = this.registerCallback(callback);
+   *     return () => this.runGuarded(registered);
+   *
+   */
+  void Function() bindCallbackGuarded(void callback());
+
+  /**
+   * Registers the provided [callback] and returns a function that will
+   * execute in this zone.
+   *
+   * When the function executes, errors are caught and treated as uncaught
+   * errors.
+   *
+   * Equivalent to:
+   *
+   *     ZoneCallback registered = this.registerUnaryCallback(callback);
+   *     return (arg) => this.runUnaryGuarded(registered, arg);
+   */
+  void Function(T) bindUnaryCallbackGuarded<T>(void callback(T argument));
+
+  /**
+   *  Registers the provided [callback] and returns a function that will
+   *  execute in this zone.
+   *
+   *  Equivalent to:
+   *
+   *      ZoneCallback registered = registerBinaryCallback(callback);
+   *      return (arg1, arg2) => this.runBinaryGuarded(registered, arg1, arg2);
+   */
+  void Function(T1, T2) bindBinaryCallbackGuarded<T1, T2>(
+      void callback(T1 argument1, T2 argument2));
+
+  /**
+   * Intercepts errors when added programmatically to a `Future` or `Stream`.
+   *
+   * When calling [Completer.completeError], [StreamController.addError],
+   * or some [Future] constructors, the current zone is allowed to intercept
+   * and replace the error.
+   *
+   * Future constructors invoke this function when the error is received
+   * directly, for example with [Future.error], or when the error is caught
+   * synchronously, for example with [Future.sync].
+   *
+   * There is no guarantee that an error is only sent through [errorCallback]
+   * once. Libraries that use intermediate controllers or completers might
+   * end up invoking [errorCallback] multiple times.
+   *
+   * Returns `null` if no replacement is desired. Otherwise returns an instance
+   * of [AsyncError] holding the new pair of error and stack trace.
+   *
+   * Although not recommended, the returned instance may have its `error` member
+   * ([AsyncError.error]) be equal to `null` in which case the error should be
+   * replaced by a [NullThrownError].
+   *
+   * Custom zones may intercept this operation.
+   *
+   * Implementations of a new asynchronous primitive that converts synchronous
+   * errors to asynchronous errors rarely need to invoke [errorCallback], since
+   * errors are usually reported through future completers or stream
+   * controllers.
+   */
+  AsyncError errorCallback(Object error, StackTrace stackTrace);
+
+  /**
+   * Runs [callback] asynchronously in this zone.
+   *
+   * The global `scheduleMicrotask` delegates to the current zone's
+   * [scheduleMicrotask]. The root zone's implementation interacts with the
+   * underlying system to schedule the given callback as a microtask.
+   *
+   * Custom zones may intercept this operation (for example to wrap the given
+   * [callback]).
+   */
+  void scheduleMicrotask(void callback());
+
+  /**
+   * Creates a Timer where the callback is executed in this zone.
+   */
+  Timer createTimer(Duration duration, void callback());
+
+  /**
+   * Creates a periodic Timer where the callback is executed in this zone.
+   */
+  Timer createPeriodicTimer(Duration period, void callback(Timer timer));
+
+  /**
+   * Prints the given [line].
+   *
+   * The global `print` function delegates to the current zone's [print]
+   * function which makes it possible to intercept printing.
+   *
+   * Example:
+   * ```
+   * import 'dart:async';
+   *
+   * main() {
+   *   runZoned(() {
+   *     // Ends up printing: "Intercepted: in zone".
+   *     print("in zone");
+   *   }, zoneSpecification: new ZoneSpecification(
+   *       print: (Zone self, ZoneDelegate parent, Zone zone, String line) {
+   *     parent.print(zone, "Intercepted: $line");
+   *   }));
+   * }
+   * ```
+   */
+  void print(String line);
+
+  /**
+   * Call to enter the Zone.
+   *
+   * The previous current zone is returned.
+   */
+  static Zone _enter(Zone zone) {
+    assert(zone != null);
+    assert(!identical(zone, _current));
+    Zone previous = _current;
+    _current = zone;
+    return previous;
+  }
+
+  /**
+   * Call to leave the Zone.
+   *
+   * The previous Zone must be provided as `previous`.
+   */
+  static void _leave(Zone previous) {
+    assert(previous != null);
+    Zone._current = previous;
+  }
+
+  /**
+   * Retrieves the zone-value associated with [key].
+   *
+   * If this zone does not contain the value looks up the same key in the
+   * parent zone. If the [key] is not found returns `null`.
+   *
+   * Any object can be used as key, as long as it has compatible `operator ==`
+   * and `hashCode` implementations.
+   * By controlling access to the key, a zone can grant or deny access to the
+   * zone value.
+   */
+  operator [](Object key);
+}
+
+ZoneDelegate _parentDelegate(_Zone zone) {
+  if (zone.parent == null) return null;
+  return zone.parent._delegate;
+}
+
+class _ZoneDelegate implements ZoneDelegate {
+  final _Zone _delegationTarget;
+
+  _ZoneDelegate(this._delegationTarget);
+
+  void handleUncaughtError(Zone zone, error, StackTrace stackTrace) {
+    var implementation = _delegationTarget._handleUncaughtError;
+    _Zone implZone = implementation.zone;
+    HandleUncaughtErrorHandler handler = implementation.function;
+    return handler(
+        implZone, _parentDelegate(implZone), zone, error, stackTrace);
+  }
+
+  R run<R>(Zone zone, R f()) {
+    var implementation = _delegationTarget._run;
+    _Zone implZone = implementation.zone;
+    RunHandler handler = implementation.function;
+    return handler(implZone, _parentDelegate(implZone), zone, f);
+  }
+
+  R runUnary<R, T>(Zone zone, R f(T arg), T arg) {
+    var implementation = _delegationTarget._runUnary;
+    _Zone implZone = implementation.zone;
+    RunUnaryHandler handler = implementation.function;
+    return handler(implZone, _parentDelegate(implZone), zone, f, arg);
+  }
+
+  R runBinary<R, T1, T2>(Zone zone, R f(T1 arg1, T2 arg2), T1 arg1, T2 arg2) {
+    var implementation = _delegationTarget._runBinary;
+    _Zone implZone = implementation.zone;
+    RunBinaryHandler handler = implementation.function;
+    return handler(implZone, _parentDelegate(implZone), zone, f, arg1, arg2);
+  }
+
+  ZoneCallback<R> registerCallback<R>(Zone zone, R f()) {
+    var implementation = _delegationTarget._registerCallback;
+    _Zone implZone = implementation.zone;
+    RegisterCallbackHandler handler = implementation.function;
+    return handler(implZone, _parentDelegate(implZone), zone, f);
+  }
+
+  ZoneUnaryCallback<R, T> registerUnaryCallback<R, T>(Zone zone, R f(T arg)) {
+    var implementation = _delegationTarget._registerUnaryCallback;
+    _Zone implZone = implementation.zone;
+    RegisterUnaryCallbackHandler handler = implementation.function;
+    return handler(implZone, _parentDelegate(implZone), zone, f);
+  }
+
+  ZoneBinaryCallback<R, T1, T2> registerBinaryCallback<R, T1, T2>(
+      Zone zone, R f(T1 arg1, T2 arg2)) {
+    var implementation = _delegationTarget._registerBinaryCallback;
+    _Zone implZone = implementation.zone;
+    RegisterBinaryCallbackHandler handler = implementation.function;
+    return handler(implZone, _parentDelegate(implZone), zone, f);
+  }
+
+  AsyncError errorCallback(Zone zone, Object error, StackTrace stackTrace) {
+    var implementation = _delegationTarget._errorCallback;
+    _Zone implZone = implementation.zone;
+    if (identical(implZone, _rootZone)) return null;
+    ErrorCallbackHandler handler = implementation.function;
+    return handler(
+        implZone, _parentDelegate(implZone), zone, error, stackTrace);
+  }
+
+  void scheduleMicrotask(Zone zone, f()) {
+    var implementation = _delegationTarget._scheduleMicrotask;
+    _Zone implZone = implementation.zone;
+    ScheduleMicrotaskHandler handler = implementation.function;
+    handler(implZone, _parentDelegate(implZone), zone, f);
+  }
+
+  Timer createTimer(Zone zone, Duration duration, void f()) {
+    var implementation = _delegationTarget._createTimer;
+    _Zone implZone = implementation.zone;
+    CreateTimerHandler handler = implementation.function;
+    return handler(implZone, _parentDelegate(implZone), zone, duration, f);
+  }
+
+  Timer createPeriodicTimer(Zone zone, Duration period, void f(Timer timer)) {
+    var implementation = _delegationTarget._createPeriodicTimer;
+    _Zone implZone = implementation.zone;
+    CreatePeriodicTimerHandler handler = implementation.function;
+    return handler(implZone, _parentDelegate(implZone), zone, period, f);
+  }
+
+  void print(Zone zone, String line) {
+    var implementation = _delegationTarget._print;
+    _Zone implZone = implementation.zone;
+    PrintHandler handler = implementation.function;
+    handler(implZone, _parentDelegate(implZone), zone, line);
+  }
+
+  Zone fork(Zone zone, ZoneSpecification specification, Map zoneValues) {
+    var implementation = _delegationTarget._fork;
+    _Zone implZone = implementation.zone;
+    ForkHandler handler = implementation.function;
+    return handler(
+        implZone, _parentDelegate(implZone), zone, specification, zoneValues);
+  }
+}
+
+/**
+ * Base class for Zone implementations.
+ */
+abstract class _Zone implements Zone {
+  const _Zone();
+
+  // TODO(floitsch): the types of the `_ZoneFunction`s should have a type for
+  // all fields.
+  _ZoneFunction<Function> get _run;
+  _ZoneFunction<Function> get _runUnary;
+  _ZoneFunction<Function> get _runBinary;
+  _ZoneFunction<Function> get _registerCallback;
+  _ZoneFunction<Function> get _registerUnaryCallback;
+  _ZoneFunction<Function> get _registerBinaryCallback;
+  _ZoneFunction<ErrorCallbackHandler> get _errorCallback;
+  _ZoneFunction<ScheduleMicrotaskHandler> get _scheduleMicrotask;
+  _ZoneFunction<CreateTimerHandler> get _createTimer;
+  _ZoneFunction<CreatePeriodicTimerHandler> get _createPeriodicTimer;
+  _ZoneFunction<PrintHandler> get _print;
+  _ZoneFunction<ForkHandler> get _fork;
+  _ZoneFunction<HandleUncaughtErrorHandler> get _handleUncaughtError;
+  _Zone get parent;
+  ZoneDelegate get _delegate;
+  Map get _map;
+
+  bool inSameErrorZone(Zone otherZone) {
+    return identical(this, otherZone) ||
+        identical(errorZone, otherZone.errorZone);
+  }
+}
+
+class _CustomZone extends _Zone {
+  // The actual zone and implementation of each of these
+  // inheritable zone functions.
+  // TODO(floitsch): the types of the `_ZoneFunction`s should have a type for
+  // all fields.
+  _ZoneFunction<Function> _run;
+  _ZoneFunction<Function> _runUnary;
+  _ZoneFunction<Function> _runBinary;
+  _ZoneFunction<Function> _registerCallback;
+  _ZoneFunction<Function> _registerUnaryCallback;
+  _ZoneFunction<Function> _registerBinaryCallback;
+  _ZoneFunction<ErrorCallbackHandler> _errorCallback;
+  _ZoneFunction<ScheduleMicrotaskHandler> _scheduleMicrotask;
+  _ZoneFunction<CreateTimerHandler> _createTimer;
+  _ZoneFunction<CreatePeriodicTimerHandler> _createPeriodicTimer;
+  _ZoneFunction<PrintHandler> _print;
+  _ZoneFunction<ForkHandler> _fork;
+  _ZoneFunction<HandleUncaughtErrorHandler> _handleUncaughtError;
+
+  // A cached delegate to this zone.
+  ZoneDelegate _delegateCache;
+
+  /// The parent zone.
+  final _Zone parent;
+
+  /// The zone's scoped value declaration map.
+  ///
+  /// This is always a [HashMap].
+  final Map _map;
+
+  ZoneDelegate get _delegate {
+    if (_delegateCache != null) return _delegateCache;
+    _delegateCache = new _ZoneDelegate(this);
+    return _delegateCache;
+  }
+
+  _CustomZone(this.parent, ZoneSpecification specification, this._map) {
+    // The root zone will have implementations of all parts of the
+    // specification, so it will never try to access the (null) parent.
+    // All other zones have a non-null parent.
+    _run = (specification.run != null)
+        ? new _ZoneFunction<Function>(this, specification.run)
+        : parent._run;
+    _runUnary = (specification.runUnary != null)
+        ? new _ZoneFunction<Function>(this, specification.runUnary)
+        : parent._runUnary;
+    _runBinary = (specification.runBinary != null)
+        ? new _ZoneFunction<Function>(this, specification.runBinary)
+        : parent._runBinary;
+    _registerCallback = (specification.registerCallback != null)
+        ? new _ZoneFunction<Function>(this, specification.registerCallback)
+        : parent._registerCallback;
+    _registerUnaryCallback = (specification.registerUnaryCallback != null)
+        ? new _ZoneFunction<Function>(this, specification.registerUnaryCallback)
+        : parent._registerUnaryCallback;
+    _registerBinaryCallback = (specification.registerBinaryCallback != null)
+        ? new _ZoneFunction<Function>(
+            this, specification.registerBinaryCallback)
+        : parent._registerBinaryCallback;
+    _errorCallback = (specification.errorCallback != null)
+        ? new _ZoneFunction<ErrorCallbackHandler>(
+            this, specification.errorCallback)
+        : parent._errorCallback;
+    _scheduleMicrotask = (specification.scheduleMicrotask != null)
+        ? new _ZoneFunction<ScheduleMicrotaskHandler>(
+            this, specification.scheduleMicrotask)
+        : parent._scheduleMicrotask;
+    _createTimer = (specification.createTimer != null)
+        ? new _ZoneFunction<CreateTimerHandler>(this, specification.createTimer)
+        : parent._createTimer;
+    _createPeriodicTimer = (specification.createPeriodicTimer != null)
+        ? new _ZoneFunction<CreatePeriodicTimerHandler>(
+            this, specification.createPeriodicTimer)
+        : parent._createPeriodicTimer;
+    _print = (specification.print != null)
+        ? new _ZoneFunction<PrintHandler>(this, specification.print)
+        : parent._print;
+    _fork = (specification.fork != null)
+        ? new _ZoneFunction<ForkHandler>(this, specification.fork)
+        : parent._fork;
+    _handleUncaughtError = (specification.handleUncaughtError != null)
+        ? new _ZoneFunction<HandleUncaughtErrorHandler>(
+            this, specification.handleUncaughtError)
+        : parent._handleUncaughtError;
+  }
+
+  /**
+   * The closest error-handling zone.
+   *
+   * Returns `this` if `this` has an error-handler. Otherwise returns the
+   * parent's error-zone.
+   */
+  Zone get errorZone => _handleUncaughtError.zone;
+
+  void runGuarded(void f()) {
+    try {
+      run(f);
+    } catch (e, s) {
+      handleUncaughtError(e, s);
+    }
+  }
+
+  void runUnaryGuarded<T>(void f(T arg), T arg) {
+    try {
+      runUnary(f, arg);
+    } catch (e, s) {
+      handleUncaughtError(e, s);
+    }
+  }
+
+  void runBinaryGuarded<T1, T2>(void f(T1 arg1, T2 arg2), T1 arg1, T2 arg2) {
+    try {
+      runBinary(f, arg1, arg2);
+    } catch (e, s) {
+      handleUncaughtError(e, s);
+    }
+  }
+
+  ZoneCallback<R> bindCallback<R>(R f()) {
+    var registered = registerCallback(f);
+    return () => this.run(registered);
+  }
+
+  ZoneUnaryCallback<R, T> bindUnaryCallback<R, T>(R f(T arg)) {
+    var registered = registerUnaryCallback(f);
+    return (arg) => this.runUnary(registered, arg);
+  }
+
+  ZoneBinaryCallback<R, T1, T2> bindBinaryCallback<R, T1, T2>(
+      R f(T1 arg1, T2 arg2)) {
+    var registered = registerBinaryCallback(f);
+    return (arg1, arg2) => this.runBinary(registered, arg1, arg2);
+  }
+
+  void Function() bindCallbackGuarded(void f()) {
+    var registered = registerCallback(f);
+    return () => this.runGuarded(registered);
+  }
+
+  void Function(T) bindUnaryCallbackGuarded<T>(void f(T arg)) {
+    var registered = registerUnaryCallback(f);
+    return (arg) => this.runUnaryGuarded(registered, arg);
+  }
+
+  void Function(T1, T2) bindBinaryCallbackGuarded<T1, T2>(
+      void f(T1 arg1, T2 arg2)) {
+    var registered = registerBinaryCallback(f);
+    return (arg1, arg2) => this.runBinaryGuarded(registered, arg1, arg2);
+  }
+
+  operator [](Object key) {
+    var result = _map[key];
+    if (result != null || _map.containsKey(key)) return result;
+    // If we are not the root zone, look up in the parent zone.
+    if (parent != null) {
+      // We do not optimize for repeatedly looking up a key which isn't
+      // there. That would require storing the key and keeping it alive.
+      // Copying the key/value from the parent does not keep any new values
+      // alive.
+      var value = parent[key];
+      if (value != null) {
+        _map[key] = value;
+      }
+      return value;
+    }
+    assert(this == _rootZone);
+    return null;
+  }
+
+  // Methods that can be customized by the zone specification.
+
+  void handleUncaughtError(error, StackTrace stackTrace) {
+    var implementation = this._handleUncaughtError;
+    assert(implementation != null);
+    ZoneDelegate parentDelegate = _parentDelegate(implementation.zone);
+    HandleUncaughtErrorHandler handler = implementation.function;
+    return handler(
+        implementation.zone, parentDelegate, this, error, stackTrace);
+  }
+
+  Zone fork({ZoneSpecification specification, Map zoneValues}) {
+    var implementation = this._fork;
+    assert(implementation != null);
+    ZoneDelegate parentDelegate = _parentDelegate(implementation.zone);
+    ForkHandler handler = implementation.function;
+    return handler(
+        implementation.zone, parentDelegate, this, specification, zoneValues);
+  }
+
+  R run<R>(R f()) {
+    var implementation = this._run;
+    assert(implementation != null);
+    ZoneDelegate parentDelegate = _parentDelegate(implementation.zone);
+    RunHandler handler = implementation.function;
+    return handler(implementation.zone, parentDelegate, this, f);
+  }
+
+  R runUnary<R, T>(R f(T arg), T arg) {
+    var implementation = this._runUnary;
+    assert(implementation != null);
+    ZoneDelegate parentDelegate = _parentDelegate(implementation.zone);
+    RunUnaryHandler handler = implementation.function;
+    return handler(implementation.zone, parentDelegate, this, f, arg);
+  }
+
+  R runBinary<R, T1, T2>(R f(T1 arg1, T2 arg2), T1 arg1, T2 arg2) {
+    var implementation = this._runBinary;
+    assert(implementation != null);
+    ZoneDelegate parentDelegate = _parentDelegate(implementation.zone);
+    RunBinaryHandler handler = implementation.function;
+    return handler(implementation.zone, parentDelegate, this, f, arg1, arg2);
+  }
+
+  ZoneCallback<R> registerCallback<R>(R callback()) {
+    var implementation = this._registerCallback;
+    assert(implementation != null);
+    ZoneDelegate parentDelegate = _parentDelegate(implementation.zone);
+    RegisterCallbackHandler handler = implementation.function;
+    return handler(implementation.zone, parentDelegate, this, callback);
+  }
+
+  ZoneUnaryCallback<R, T> registerUnaryCallback<R, T>(R callback(T arg)) {
+    var implementation = this._registerUnaryCallback;
+    assert(implementation != null);
+    ZoneDelegate parentDelegate = _parentDelegate(implementation.zone);
+    RegisterUnaryCallbackHandler handler = implementation.function;
+    return handler(implementation.zone, parentDelegate, this, callback);
+  }
+
+  ZoneBinaryCallback<R, T1, T2> registerBinaryCallback<R, T1, T2>(
+      R callback(T1 arg1, T2 arg2)) {
+    var implementation = this._registerBinaryCallback;
+    assert(implementation != null);
+    ZoneDelegate parentDelegate = _parentDelegate(implementation.zone);
+    RegisterBinaryCallbackHandler handler = implementation.function;
+    return handler(implementation.zone, parentDelegate, this, callback);
+  }
+
+  AsyncError errorCallback(Object error, StackTrace stackTrace) {
+    var implementation = this._errorCallback;
+    assert(implementation != null);
+    final Zone implementationZone = implementation.zone;
+    if (identical(implementationZone, _rootZone)) return null;
+    final ZoneDelegate parentDelegate = _parentDelegate(implementationZone);
+    ErrorCallbackHandler handler = implementation.function;
+    return handler(implementationZone, parentDelegate, this, error, stackTrace);
+  }
+
+  void scheduleMicrotask(void f()) {
+    var implementation = this._scheduleMicrotask;
+    assert(implementation != null);
+    ZoneDelegate parentDelegate = _parentDelegate(implementation.zone);
+    ScheduleMicrotaskHandler handler = implementation.function;
+    return handler(implementation.zone, parentDelegate, this, f);
+  }
+
+  Timer createTimer(Duration duration, void f()) {
+    var implementation = this._createTimer;
+    assert(implementation != null);
+    ZoneDelegate parentDelegate = _parentDelegate(implementation.zone);
+    CreateTimerHandler handler = implementation.function;
+    return handler(implementation.zone, parentDelegate, this, duration, f);
+  }
+
+  Timer createPeriodicTimer(Duration duration, void f(Timer timer)) {
+    var implementation = this._createPeriodicTimer;
+    assert(implementation != null);
+    ZoneDelegate parentDelegate = _parentDelegate(implementation.zone);
+    CreatePeriodicTimerHandler handler = implementation.function;
+    return handler(implementation.zone, parentDelegate, this, duration, f);
+  }
+
+  void print(String line) {
+    var implementation = this._print;
+    assert(implementation != null);
+    ZoneDelegate parentDelegate = _parentDelegate(implementation.zone);
+    PrintHandler handler = implementation.function;
+    return handler(implementation.zone, parentDelegate, this, line);
+  }
+}
+
+void _rootHandleUncaughtError(
+    Zone self, ZoneDelegate parent, Zone zone, error, StackTrace stackTrace) {
+  _schedulePriorityAsyncCallback(() {
+    error ??= new NullThrownError();
+    if (stackTrace == null) throw error;
+    _rethrow(error, stackTrace);
+  });
+}
+
+external void _rethrow(Object error, StackTrace stackTrace);
+
+R _rootRun<R>(Zone self, ZoneDelegate parent, Zone zone, R f()) {
+  if (Zone._current == zone) return f();
+
+  Zone old = Zone._enter(zone);
+  try {
+    return f();
+  } finally {
+    Zone._leave(old);
+  }
+}
+
+R _rootRunUnary<R, T>(
+    Zone self, ZoneDelegate parent, Zone zone, R f(T arg), T arg) {
+  if (Zone._current == zone) return f(arg);
+
+  Zone old = Zone._enter(zone);
+  try {
+    return f(arg);
+  } finally {
+    Zone._leave(old);
+  }
+}
+
+R _rootRunBinary<R, T1, T2>(Zone self, ZoneDelegate parent, Zone zone,
+    R f(T1 arg1, T2 arg2), T1 arg1, T2 arg2) {
+  if (Zone._current == zone) return f(arg1, arg2);
+
+  Zone old = Zone._enter(zone);
+  try {
+    return f(arg1, arg2);
+  } finally {
+    Zone._leave(old);
+  }
+}
+
+ZoneCallback<R> _rootRegisterCallback<R>(
+    Zone self, ZoneDelegate parent, Zone zone, R f()) {
+  return f;
+}
+
+ZoneUnaryCallback<R, T> _rootRegisterUnaryCallback<R, T>(
+    Zone self, ZoneDelegate parent, Zone zone, R f(T arg)) {
+  return f;
+}
+
+ZoneBinaryCallback<R, T1, T2> _rootRegisterBinaryCallback<R, T1, T2>(
+    Zone self, ZoneDelegate parent, Zone zone, R f(T1 arg1, T2 arg2)) {
+  return f;
+}
+
+AsyncError _rootErrorCallback(Zone self, ZoneDelegate parent, Zone zone,
+        Object error, StackTrace stackTrace) =>
+    null;
+
+void _rootScheduleMicrotask(
+    Zone self, ZoneDelegate parent, Zone zone, void f()) {
+  if (!identical(_rootZone, zone)) {
+    bool hasErrorHandler = !_rootZone.inSameErrorZone(zone);
+    if (hasErrorHandler) {
+      f = zone.bindCallbackGuarded(f);
+    } else {
+      f = zone.bindCallback(f);
+    }
+    // Use root zone as event zone if the function is already bound.
+    zone = _rootZone;
+  }
+  _scheduleAsyncCallback(f);
+}
+
+Timer _rootCreateTimer(Zone self, ZoneDelegate parent, Zone zone,
+    Duration duration, void callback()) {
+  if (!identical(_rootZone, zone)) {
+    callback = zone.bindCallback(callback);
+  }
+  return Timer._createTimer(duration, callback);
+}
+
+Timer _rootCreatePeriodicTimer(Zone self, ZoneDelegate parent, Zone zone,
+    Duration duration, void callback(Timer timer)) {
+  if (!identical(_rootZone, zone)) {
+    // TODO(floitsch): the return type should be 'void'.
+    callback = zone.bindUnaryCallback<dynamic, Timer>(callback);
+  }
+  return Timer._createPeriodicTimer(duration, callback);
+}
+
+void _rootPrint(Zone self, ZoneDelegate parent, Zone zone, String line) {
+  printToConsole(line);
+}
+
+void _printToZone(String line) {
+  Zone.current.print(line);
+}
+
+Zone _rootFork(Zone self, ZoneDelegate parent, Zone zone,
+    ZoneSpecification specification, Map zoneValues) {
+  // TODO(floitsch): it would be nice if we could get rid of this hack.
+  // Change the static zoneOrDirectPrint function to go through zones
+  // from now on.
+  printToZone = _printToZone;
+
+  if (specification == null) {
+    specification = const ZoneSpecification();
+  } else if (specification is! _ZoneSpecification) {
+    throw new ArgumentError("ZoneSpecifications must be instantiated"
+        " with the provided constructor.");
+  }
+  Map valueMap;
+  if (zoneValues == null) {
+    if (zone is _Zone) {
+      valueMap = zone._map;
+    } else {
+      valueMap = new HashMap();
+    }
+  } else {
+    valueMap = new HashMap.from(zoneValues);
+  }
+  return new _CustomZone(zone, specification, valueMap);
+}
+
+class _RootZone extends _Zone {
+  const _RootZone();
+
+  _ZoneFunction<Function> get _run =>
+      const _ZoneFunction<Function>(_rootZone, _rootRun);
+  _ZoneFunction<Function> get _runUnary =>
+      const _ZoneFunction<Function>(_rootZone, _rootRunUnary);
+  _ZoneFunction<Function> get _runBinary =>
+      const _ZoneFunction<Function>(_rootZone, _rootRunBinary);
+  _ZoneFunction<Function> get _registerCallback =>
+      const _ZoneFunction<Function>(_rootZone, _rootRegisterCallback);
+  _ZoneFunction<Function> get _registerUnaryCallback =>
+      const _ZoneFunction<Function>(_rootZone, _rootRegisterUnaryCallback);
+  _ZoneFunction<Function> get _registerBinaryCallback =>
+      const _ZoneFunction<Function>(_rootZone, _rootRegisterBinaryCallback);
+  _ZoneFunction<ErrorCallbackHandler> get _errorCallback =>
+      const _ZoneFunction<ErrorCallbackHandler>(_rootZone, _rootErrorCallback);
+  _ZoneFunction<ScheduleMicrotaskHandler> get _scheduleMicrotask =>
+      const _ZoneFunction<ScheduleMicrotaskHandler>(
+          _rootZone, _rootScheduleMicrotask);
+  _ZoneFunction<CreateTimerHandler> get _createTimer =>
+      const _ZoneFunction<CreateTimerHandler>(_rootZone, _rootCreateTimer);
+  _ZoneFunction<CreatePeriodicTimerHandler> get _createPeriodicTimer =>
+      const _ZoneFunction<CreatePeriodicTimerHandler>(
+          _rootZone, _rootCreatePeriodicTimer);
+  _ZoneFunction<PrintHandler> get _print =>
+      const _ZoneFunction<PrintHandler>(_rootZone, _rootPrint);
+  _ZoneFunction<ForkHandler> get _fork =>
+      const _ZoneFunction<ForkHandler>(_rootZone, _rootFork);
+  _ZoneFunction<HandleUncaughtErrorHandler> get _handleUncaughtError =>
+      const _ZoneFunction<HandleUncaughtErrorHandler>(
+          _rootZone, _rootHandleUncaughtError);
+
+  // The parent zone.
+  _Zone get parent => null;
+
+  /// The zone's scoped value declaration map.
+  ///
+  /// This is always a [HashMap].
+  Map get _map => _rootMap;
+
+  static final _rootMap = new HashMap();
+
+  static ZoneDelegate _rootDelegate;
+
+  ZoneDelegate get _delegate {
+    if (_rootDelegate != null) return _rootDelegate;
+    return _rootDelegate = new _ZoneDelegate(this);
+  }
+
+  /**
+   * The closest error-handling zone.
+   *
+   * Returns `this` if `this` has an error-handler. Otherwise returns the
+   * parent's error-zone.
+   */
+  Zone get errorZone => this;
+
+  // Zone interface.
+
+  void runGuarded(void f()) {
+    try {
+      if (identical(_rootZone, Zone._current)) {
+        f();
+        return;
+      }
+      _rootRun(null, null, this, f);
+    } catch (e, s) {
+      handleUncaughtError(e, s);
+    }
+  }
+
+  void runUnaryGuarded<T>(void f(T arg), T arg) {
+    try {
+      if (identical(_rootZone, Zone._current)) {
+        f(arg);
+        return;
+      }
+      _rootRunUnary(null, null, this, f, arg);
+    } catch (e, s) {
+      handleUncaughtError(e, s);
+    }
+  }
+
+  void runBinaryGuarded<T1, T2>(void f(T1 arg1, T2 arg2), T1 arg1, T2 arg2) {
+    try {
+      if (identical(_rootZone, Zone._current)) {
+        f(arg1, arg2);
+        return;
+      }
+      _rootRunBinary(null, null, this, f, arg1, arg2);
+    } catch (e, s) {
+      handleUncaughtError(e, s);
+    }
+  }
+
+  ZoneCallback<R> bindCallback<R>(R f()) {
+    return () => this.run<R>(f);
+  }
+
+  ZoneUnaryCallback<R, T> bindUnaryCallback<R, T>(R f(T arg)) {
+    return (arg) => this.runUnary<R, T>(f, arg);
+  }
+
+  ZoneBinaryCallback<R, T1, T2> bindBinaryCallback<R, T1, T2>(
+      R f(T1 arg1, T2 arg2)) {
+    return (arg1, arg2) => this.runBinary<R, T1, T2>(f, arg1, arg2);
+  }
+
+  void Function() bindCallbackGuarded(void f()) {
+    return () => this.runGuarded(f);
+  }
+
+  void Function(T) bindUnaryCallbackGuarded<T>(void f(T arg)) {
+    return (arg) => this.runUnaryGuarded(f, arg);
+  }
+
+  void Function(T1, T2) bindBinaryCallbackGuarded<T1, T2>(
+      void f(T1 arg1, T2 arg2)) {
+    return (arg1, arg2) => this.runBinaryGuarded(f, arg1, arg2);
+  }
+
+  operator [](Object key) => null;
+
+  // Methods that can be customized by the zone specification.
+
+  void handleUncaughtError(error, StackTrace stackTrace) {
+    _rootHandleUncaughtError(null, null, this, error, stackTrace);
+  }
+
+  Zone fork({ZoneSpecification specification, Map zoneValues}) {
+    return _rootFork(null, null, this, specification, zoneValues);
+  }
+
+  R run<R>(R f()) {
+    if (identical(Zone._current, _rootZone)) return f();
+    return _rootRun(null, null, this, f);
+  }
+
+  R runUnary<R, T>(R f(T arg), T arg) {
+    if (identical(Zone._current, _rootZone)) return f(arg);
+    return _rootRunUnary(null, null, this, f, arg);
+  }
+
+  R runBinary<R, T1, T2>(R f(T1 arg1, T2 arg2), T1 arg1, T2 arg2) {
+    if (identical(Zone._current, _rootZone)) return f(arg1, arg2);
+    return _rootRunBinary(null, null, this, f, arg1, arg2);
+  }
+
+  ZoneCallback<R> registerCallback<R>(R f()) => f;
+
+  ZoneUnaryCallback<R, T> registerUnaryCallback<R, T>(R f(T arg)) => f;
+
+  ZoneBinaryCallback<R, T1, T2> registerBinaryCallback<R, T1, T2>(
+          R f(T1 arg1, T2 arg2)) =>
+      f;
+
+  AsyncError errorCallback(Object error, StackTrace stackTrace) => null;
+
+  void scheduleMicrotask(void f()) {
+    _rootScheduleMicrotask(null, null, this, f);
+  }
+
+  Timer createTimer(Duration duration, void f()) {
+    return Timer._createTimer(duration, f);
+  }
+
+  Timer createPeriodicTimer(Duration duration, void f(Timer timer)) {
+    return Timer._createPeriodicTimer(duration, f);
+  }
+
+  void print(String line) {
+    printToConsole(line);
+  }
+}
+
+const _rootZone = const _RootZone();
+
+/**
+ * Runs [body] in its own zone.
+ *
+ * Creates a new zone using [Zone.fork] based on [zoneSpecification] and
+ * [zoneValues], then runs [body] in that zone and returns the result.
+ *
+ * If [onError] is provided, it must have one of the types
+ * * `void Function(Object)`
+ * * `void Function(Object, StackTrace)`
+ * and the [onError] handler is used *both* to handle asynchronous errors
+ * by overriding [ZoneSpecification.handleUncaughtError] in [zoneSpecification],
+ * if any, *and* to handle errors thrown synchronously by the call to [body].
+ *
+ * If an error occurs synchronously in [body],
+ * then throwing in the [onError] handler
+ * makes the call to `runZone` throw that error,
+ * and otherwise the call to `runZoned` returns `null`.
+ *
+ * If the zone specification has a `handleUncaughtError` value or the [onError]
+ * parameter is provided, the zone becomes an error-zone.
+ *
+ * Errors will never cross error-zone boundaries by themselves.
+ * Errors that try to cross error-zone boundaries are considered uncaught in
+ * their originating error zone.
+ *
+ *     var future = new Future.value(499);
+ *     runZoned(() {
+ *       var future2 = future.then((_) { throw "error in first error-zone"; });
+ *       runZoned(() {
+ *         var future3 = future2.catchError((e) { print("Never reached!"); });
+ *       }, onError: (e) { print("unused error handler"); });
+ *     }, onError: (e) { print("catches error of first error-zone."); });
+ *
+ * Example:
+ *
+ *     runZoned(() {
+ *       new Future(() { throw "asynchronous error"; });
+ *     }, onError: print);  // Will print "asynchronous error".
+ *
+ * It is possible to manually pass an error from one error zone to another
+ * by re-throwing it in the new zone. If [onError] throws, that error will
+ * occur in the original zone where [runZoned] was called.
+ */
+R runZoned<R>(R body(),
+    {Map zoneValues, ZoneSpecification zoneSpecification, Function onError}) {
+  if (onError == null) {
+    return _runZoned<R>(body, zoneValues, zoneSpecification);
+  }
+  void Function(Object) unaryOnError;
+  void Function(Object, StackTrace) binaryOnError;
+  if (onError is void Function(Object, StackTrace)) {
+    binaryOnError = onError;
+  } else if (onError is void Function(Object)) {
+    unaryOnError = onError;
+  } else {
+    throw new ArgumentError("onError callback must take either an Object "
+        "(the error), or both an Object (the error) and a StackTrace.");
+  }
+  HandleUncaughtErrorHandler errorHandler = (Zone self, ZoneDelegate parent,
+      Zone zone, error, StackTrace stackTrace) {
+    try {
+      if (binaryOnError != null) {
+        self.parent.runBinary(binaryOnError, error, stackTrace);
+      } else {
+        assert(unaryOnError != null);
+        self.parent.runUnary(unaryOnError, error);
+      }
+    } catch (e, s) {
+      if (identical(e, error)) {
+        parent.handleUncaughtError(zone, error, stackTrace);
+      } else {
+        parent.handleUncaughtError(zone, e, s);
+      }
+    }
+  };
+  if (zoneSpecification == null) {
+    zoneSpecification =
+        new ZoneSpecification(handleUncaughtError: errorHandler);
+  } else {
+    zoneSpecification = new ZoneSpecification.from(zoneSpecification,
+        handleUncaughtError: errorHandler);
+  }
+  try {
+    return _runZoned<R>(body, zoneValues, zoneSpecification);
+  } catch (e, stackTrace) {
+    if (binaryOnError != null) {
+      binaryOnError(e, stackTrace);
+    } else {
+      assert(unaryOnError != null);
+      unaryOnError(e);
+    }
+  }
+  return null;
+}
+
+/// Runs [body] in a new zone based on [zoneValues] and [specification].
+R _runZoned<R>(R body(), Map zoneValues, ZoneSpecification specification) =>
+    Zone.current
+        .fork(specification: specification, zoneValues: zoneValues)
+        .run<R>(body);
diff --git a/sdk_nnbd/lib/cli/cli.dart b/sdk_nnbd/lib/cli/cli.dart
new file mode 100644
index 0000000..9c19c3a
--- /dev/null
+++ b/sdk_nnbd/lib/cli/cli.dart
@@ -0,0 +1,11 @@
+// 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.
+
+/// {@category VM}
+library dart.cli;
+
+import 'dart:async';
+import 'dart:math';
+
+part 'wait_for.dart';
diff --git a/sdk_nnbd/lib/cli/cli_sources.gni b/sdk_nnbd/lib/cli/cli_sources.gni
new file mode 100644
index 0000000..e90e1de
--- /dev/null
+++ b/sdk_nnbd/lib/cli/cli_sources.gni
@@ -0,0 +1,10 @@
+# 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.
+
+cli_sdk_sources = [
+  "cli.dart",
+
+  # The above file needs to be first if additional parts are added to the lib.
+  "wait_for.dart",
+]
diff --git a/sdk_nnbd/lib/cli/wait_for.dart b/sdk_nnbd/lib/cli/wait_for.dart
new file mode 100644
index 0000000..1886ff1
--- /dev/null
+++ b/sdk_nnbd/lib/cli/wait_for.dart
@@ -0,0 +1,152 @@
+// 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.
+
+part of dart.cli;
+
+/**
+ * Synchronously blocks the calling isolate to wait for asynchronous events to
+ * complete.
+ *
+ * If the [timeout] parameter is supplied, [waitForEvent] will return after
+ * the specified timeout even if no events have occurred.
+ *
+ * This call does the following:
+ * - suspends the current execution stack,
+ * - runs the microtask queue until it is empty,
+ * - waits until the message queue is not empty,
+ * - handles messages on the message queue, plus their associated microtasks,
+ *   until the message queue is empty,
+ * - resumes the original stack.
+ *
+ * This function breaks the usual promise offered by Dart semantics that
+ * message handlers and microtasks run to completion before the next message
+ * handler or microtask begins to run. Of particular note is that use of this
+ * function in a finally block will allow microtasks and message handlers to
+ * run before all finally blocks for an exception have completed, possibly
+ * breaking invariants in your program.
+ *
+ * This function will synchronously throw the first unhandled exception it
+ * encounters in running the microtasks and message handlers as though the
+ * throwing microtask or message handler was the only Dart invocation on the
+ * stack. That is, unhandled exceptions in a microtask or message handler will
+ * skip over stacks suspended in a call to [waitForEvent].
+ *
+ * Calls to this function may be nested. Earlier invocations will not
+ * be able to complete until subsequent ones do. Messages that arrive after
+ * a subsequent invocation are "consumed" by that invocation, and do not
+ * unblock an earlier invocation. Please be aware that nesting calls to
+ * [waitForEvent] can lead to deadlock when subsequent calls block to wait for
+ * a condition that is only satisfied after an earlier call returns.
+ *
+ * Please note that this call is only available in the standalone command-line
+ * Dart VM. Further, because it suspends the current execution stack until the
+ * message queue is empty, even when running in the standalone command-line VM
+ * there exists a risk that the current execution stack will be starved.
+ */
+external void _waitForEvent(int timeoutMillis);
+
+@pragma("vm:entry-point")
+void Function(int) _getWaitForEvent() => _waitForEvent;
+
+// This should be set from C++ code by the embedder to wire up waitFor() to the
+// native implementation. In the standalone VM this is set to _waitForEvent()
+// above. If it is null, calling waitFor() will throw an UnsupportedError.
+@pragma("vm:entry-point")
+void Function(int) _waitForEventClosure;
+
+class _WaitForUtils {
+  static void waitForEvent({Duration timeout}) {
+    if (_waitForEventClosure == null) {
+      throw new UnsupportedError("waitFor is not supported by this embedder");
+    }
+    _waitForEventClosure(timeout == null ? 0 : max(1, timeout.inMilliseconds));
+  }
+}
+
+/**
+ * Suspends the stack, runs microtasks, and handles incoming events until
+ * [future] completes.
+ *
+ * WARNING: EXPERIMENTAL. USE AT YOUR OWN RISK.
+ *
+ * This call does the following:
+ * - While [future] is not completed:
+ *   - suspends the current execution stack,
+ *   - runs the microtask queue until it is empty,
+ *   - waits until the message queue is not empty,
+ *   - handles messages on the message queue, plus their associated microtasks,
+ *     until the message queue is empty,
+ *   - resumes the original stack.
+ *
+ * This function breaks the usual promise offered by Dart semantics that
+ * message handlers and microtasks run to completion before the next message
+ * handler or microtask begins to run. Of particular note is that use of this
+ * function in a finally block will allow microtasks and message handlers to
+ * run before all finally blocks for an exception have completed, possibly
+ * breaking invariants in your program.
+ *
+ * Use of this function should be considered a last resort when it is not
+ * possible to convert a Dart program entirely to an asynchronous style using
+ * `async` and `await`.
+ *
+ * If the [Future] completes normally, its result is returned. If the [Future]
+ * completes with an error, the error and stack trace are wrapped in an
+ * [AsyncError] and thrown. If a microtask or message handler run during this
+ * call results in an unhandled exception, that exception will be propagated
+ * as though the microtask or message handler was the only Dart invocation on
+ * the stack. That is, unhandled exceptions in a microtask or message handler
+ * will skip over stacks suspended in a call to [waitFor].
+ *
+ * If the optional `timeout` parameter is passed, [waitFor] throws a
+ * [TimeoutException] if the [Future] is not completed within the specified
+ * period.
+ *
+ * Calls to [waitFor] may be nested. Earlier invocations will not complete
+ * until subsequent ones do, but the completion of a subsequent invocation will
+ * cause the previous invocation to wake up and check its [Future] for
+ * completion.
+ *
+ * Please be aware that nesting calls to [waitFor] can lead to deadlock if
+ * subsequent calls block waiting for a condition that is only satisfied when
+ * an earlier call returns.
+ */
+T waitFor<T>(Future<T> future, {Duration timeout}) {
+  T result;
+  bool futureCompleted = false;
+  Object error;
+  StackTrace stacktrace;
+  future.then((r) {
+    futureCompleted = true;
+    result = r;
+  }, onError: (e, st) {
+    error = e;
+    stacktrace = st;
+  });
+
+  Stopwatch s;
+  if (timeout != null) {
+    s = new Stopwatch()..start();
+  }
+  Timer.run(() {}); // Enusre there is at least one message.
+  while (!futureCompleted && (error == null)) {
+    Duration remaining;
+    if (timeout != null) {
+      if (s.elapsed >= timeout) {
+        throw new TimeoutException("waitFor() timed out", timeout);
+      }
+      remaining = timeout - s.elapsed;
+    }
+    _WaitForUtils.waitForEvent(timeout: remaining);
+  }
+  if (timeout != null) {
+    s.stop();
+  }
+  Timer.run(() {}); // Ensure that previous calls to waitFor are woken up.
+
+  if (error != null) {
+    throw new AsyncError(error, stacktrace);
+  }
+
+  return result;
+}
diff --git a/sdk_nnbd/lib/collection/collection.dart b/sdk_nnbd/lib/collection/collection.dart
new file mode 100644
index 0000000..b050a48
--- /dev/null
+++ b/sdk_nnbd/lib/collection/collection.dart
@@ -0,0 +1,29 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// Classes and utilities that supplement the collection support in dart:core.
+///
+/// To use this library in your code:
+///
+///     import 'dart:collection';
+///
+/// {@category Core}
+library dart.collection;
+
+import 'dart:_internal' hide Symbol;
+import 'dart:math' show Random; // Used by ListMixin.shuffle.
+
+part 'collections.dart';
+part 'hash_map.dart';
+part 'hash_set.dart';
+part 'iterable.dart';
+part 'iterator.dart';
+part 'linked_hash_map.dart';
+part 'linked_hash_set.dart';
+part 'linked_list.dart';
+part 'list.dart';
+part 'maps.dart';
+part 'queue.dart';
+part 'set.dart';
+part 'splay_tree.dart';
diff --git a/sdk_nnbd/lib/collection/collection_sources.gni b/sdk_nnbd/lib/collection/collection_sources.gni
new file mode 100644
index 0000000..3f2f19e
--- /dev/null
+++ b/sdk_nnbd/lib/collection/collection_sources.gni
@@ -0,0 +1,23 @@
+# 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.
+
+# This file contains all sources for the dart:collection library.
+collection_sdk_sources = [
+  "collection.dart",
+
+  # The above file needs to be first as it lists the parts below.
+  "collections.dart",
+  "hash_map.dart",
+  "hash_set.dart",
+  "iterable.dart",
+  "iterator.dart",
+  "linked_hash_map.dart",
+  "linked_hash_set.dart",
+  "linked_list.dart",
+  "list.dart",
+  "maps.dart",
+  "queue.dart",
+  "set.dart",
+  "splay_tree.dart",
+]
diff --git a/sdk_nnbd/lib/collection/collections.dart b/sdk_nnbd/lib/collection/collections.dart
new file mode 100644
index 0000000..9b43996
--- /dev/null
+++ b/sdk_nnbd/lib/collection/collections.dart
@@ -0,0 +1,24 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.collection;
+
+/// An unmodifiable [List] view of another List.
+///
+/// The source of the elements may be a [List] or any [Iterable] with
+/// efficient [Iterable.length] and [Iterable.elementAt].
+class UnmodifiableListView<E> extends UnmodifiableListBase<E> {
+  final Iterable<E> _source;
+
+  /// Creates an unmodifiable list backed by [source].
+  ///
+  /// The [source] of the elements may be a [List] or any [Iterable] with
+  /// efficient [Iterable.length] and [Iterable.elementAt].
+  UnmodifiableListView(Iterable<E> source) : _source = source;
+
+  List<R> cast<R>() => UnmodifiableListView(_source.cast<R>());
+  int get length => _source.length;
+
+  E operator [](int index) => _source.elementAt(index);
+}
diff --git a/sdk_nnbd/lib/collection/hash_map.dart b/sdk_nnbd/lib/collection/hash_map.dart
new file mode 100644
index 0000000..525f43a
--- /dev/null
+++ b/sdk_nnbd/lib/collection/hash_map.dart
@@ -0,0 +1,156 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.collection;
+
+/// Default function for equality comparison in customized HashMaps
+bool _defaultEquals(a, b) => a == b;
+
+/// Default function for hash-code computation in customized HashMaps
+int _defaultHashCode(a) => a.hashCode;
+
+/// Type of custom equality function
+typedef _Equality<K> = bool Function(K a, K b);
+
+/// Type of custom hash code function.
+typedef _Hasher<K> = int Function(K object);
+
+/// A hash-table based implementation of [Map].
+///
+/// The keys of a `HashMap` must have consistent [Object.==]
+/// and [Object.hashCode] implementations. This means that the `==` operator
+/// must define a stable equivalence relation on the keys (reflexive,
+/// symmetric, transitive, and consistent over time), and that `hashCode`
+/// must be the same for objects that are considered equal by `==`.
+///
+/// The map allows `null` as a key.
+///
+/// Iterating the map's keys, values or entries (through [forEach])
+/// may happen in any order.
+/// The iteration order only changes when the map is modified.
+/// Values are iterated in the same order as their associated keys,
+/// so iterating the [keys] and [values] in parallel
+/// will give matching key and value pairs.
+abstract class HashMap<K, V> implements Map<K, V> {
+  /// Creates an unordered hash-table based [Map].
+  ///
+  /// The created map is not ordered in any way. When iterating the keys or
+  /// values, the iteration order is unspecified except that it will stay the
+  /// same as long as the map isn't changed.
+  ///
+  /// If [equals] is provided, it is used to compare the keys in the table with
+  /// new keys. If [equals] is omitted, the key's own [Object.==] is used
+  /// instead.
+  ///
+  /// Similar, if [hashCode] is provided, it is used to produce a hash value
+  /// for keys in order to place them in the hash table. If it is omitted, the
+  /// key's own [Object.hashCode] is used.
+  ///
+  /// If using methods like [operator []], [remove] and [containsKey] together
+  /// with a custom equality and hashcode, an extra `isValidKey` function
+  /// can be supplied. This function is called before calling [equals] or
+  /// [hashCode] with an argument that may not be a [K] instance, and if the
+  /// call returns false, the key is assumed to not be in the set.
+  /// The [isValidKey] function defaults to just testing if the object is a
+  /// [K] instance.
+  ///
+  /// Example:
+  ///
+  ///     new HashMap<int,int>(equals: (int a, int b) => (b - a) % 5 == 0,
+  ///                          hashCode: (int e) => e % 5)
+  ///
+  /// This example map does not need an `isValidKey` function to be passed.
+  /// The default function accepts only `int` values, which can safely be
+  /// passed to both the `equals` and `hashCode` functions.
+  ///
+  /// If neither `equals`, `hashCode`, nor `isValidKey` is provided,
+  /// the default `isValidKey` instead accepts all keys.
+  /// The default equality and hashcode operations are assumed to work on all
+  /// objects.
+  ///
+  /// Likewise, if `equals` is [identical], `hashCode` is [identityHashCode]
+  /// and `isValidKey` is omitted, the resulting map is identity based,
+  /// and the `isValidKey` defaults to accepting all keys.
+  /// Such a map can be created directly using [HashMap.identity].
+  ///
+  /// The used `equals` and `hashCode` method should always be consistent,
+  /// so that if `equals(a, b)` then `hashCode(a) == hashCode(b)`. The hash
+  /// of an object, or what it compares equal to, should not change while the
+  /// object is a key in the map. If it does change, the result is
+  /// unpredictable.
+  ///
+  /// If you supply one of [equals] and [hashCode],
+  /// you should generally also to supply the other.
+  external factory HashMap(
+      {bool equals(K key1, K key2),
+      int hashCode(K key),
+      bool isValidKey(potentialKey)});
+
+  /// Creates an unordered identity-based map.
+  ///
+  /// Effectively a shorthand for:
+  ///
+  ///     new HashMap<K, V>(equals: identical,
+  ///                       hashCode: identityHashCode)
+  external factory HashMap.identity();
+
+  /// Creates a [HashMap] that contains all key/value pairs of [other].
+  ///
+  /// The keys must all be instances of [K] and the values of [V].
+  /// The [other] map itself can have any type.
+  factory HashMap.from(Map other) {
+    Map<K, V> result = HashMap<K, V>();
+    other.forEach((k, v) {
+      result[k] = v;
+    });
+    return result;
+  }
+
+  /// Creates a [HashMap] that contains all key/value pairs of [other].
+  factory HashMap.of(Map<K, V> other) => HashMap<K, V>()..addAll(other);
+
+  /// Creates a [HashMap] where the keys and values are computed from the
+  /// [iterable].
+  ///
+  /// For each element of the [iterable] this constructor computes a key/value
+  /// pair, by applying [key] and [value] respectively.
+  ///
+  /// The keys of the key/value pairs do not need to be unique. The last
+  /// occurrence of a key will simply overwrite any previous value.
+  ///
+  /// If no values are specified for [key] and [value] the default is the
+  /// identity function.
+  factory HashMap.fromIterable(Iterable iterable,
+      {K key(element), V value(element)}) {
+    Map<K, V> map = HashMap<K, V>();
+    MapBase._fillMapWithMappedIterable(map, iterable, key, value);
+    return map;
+  }
+
+  /// Creates a [HashMap] associating the given [keys] to [values].
+  ///
+  /// This constructor iterates over [keys] and [values] and maps each element
+  /// of [keys] to the corresponding element of [values].
+  ///
+  /// If [keys] contains the same object multiple times, the last occurrence
+  /// overwrites the previous value.
+  ///
+  /// It is an error if the two [Iterable]s don't have the same length.
+  factory HashMap.fromIterables(Iterable<K> keys, Iterable<V> values) {
+    Map<K, V> map = HashMap<K, V>();
+    MapBase._fillMapWithIterables(map, keys, values);
+    return map;
+  }
+
+  /// Creates a [HashMap] containing the entries of [entries].
+  ///
+  /// Returns a new `HashMap<K, V>` where all entries of [entries]
+  /// have been added in iteration order.
+  ///
+  /// If multiple [entries] have the same key,
+  /// later occurrences overwrite the earlier ones.
+  @Since("2.1")
+  factory HashMap.fromEntries(Iterable<MapEntry<K, V>> entries) =>
+      HashMap<K, V>()..addEntries(entries);
+}
diff --git a/sdk_nnbd/lib/collection/hash_set.dart b/sdk_nnbd/lib/collection/hash_set.dart
new file mode 100644
index 0000000..3fd00fe
--- /dev/null
+++ b/sdk_nnbd/lib/collection/hash_set.dart
@@ -0,0 +1,115 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.collection;
+
+/// An unordered hash-table based [Set] implementation.
+///
+/// The elements of a `HashSet` must have consistent equality
+/// and hashCode implementations. This means that the equals operation
+/// must define a stable equivalence relation on the elements (reflexive,
+/// symmetric, transitive, and consistent over time), and that the hashCode
+/// must consistent with equality, so that the same for objects that are
+/// considered equal.
+///
+/// The set allows `null` as an element.
+///
+/// Most simple operations on `HashSet` are done in (potentially amortized)
+/// constant time: [add], [contains], [remove], and [length], provided the hash
+/// codes of objects are well distributed.
+///
+/// The iteration order of the set is not specified and depends on
+/// the hashcodes of the provided elements. However, the order is stable:
+/// multiple iterations over the same set produce the same order, as long as
+/// the set is not modified.
+abstract class HashSet<E> implements Set<E> {
+  /// Create a hash set using the provided [equals] as equality.
+  ///
+  /// The provided [equals] must define a stable equivalence relation, and
+  /// [hashCode] must be consistent with [equals]. If the [equals] or [hashCode]
+  /// methods won't work on all objects, but only on some instances of E, the
+  /// [isValidKey] predicate can be used to restrict the keys that the functions
+  /// are applied to.
+  /// Any key for which [isValidKey] returns false is automatically assumed
+  /// to not be in the set when asking `contains`.
+  ///
+  /// If [equals] or [hashCode] are omitted, the set uses
+  /// the elements' intrinsic [Object.==] and [Object.hashCode].
+  ///
+  /// If you supply one of [equals] and [hashCode],
+  /// you should generally also to supply the other.
+  ///
+  /// If the supplied `equals` or `hashCode` functions won't work on all [E]
+  /// objects, and the map will be used in a setting where a non-`E` object
+  /// is passed to, e.g., `contains`, then the [isValidKey] function should
+  /// also be supplied.
+  ///
+  /// If [isValidKey] is omitted, it defaults to testing if the object is an
+  /// [E] instance. That means that:
+  ///
+  ///     new HashSet<int>(equals: (int e1, int e2) => (e1 - e2) % 5 == 0,
+  ///                      hashCode: (int e) => e % 5)
+  ///
+  /// does not need an `isValidKey` argument, because it defaults to only
+  /// accepting `int` values which are accepted by both `equals` and `hashCode`.
+  ///
+  /// If neither `equals`, `hashCode`, nor `isValidKey` is provided,
+  /// the default `isValidKey` instead accepts all values.
+  /// The default equality and hashcode operations are assumed to work on all
+  /// objects.
+  ///
+  /// Likewise, if `equals` is [identical], `hashCode` is [identityHashCode]
+  /// and `isValidKey` is omitted, the resulting set is identity based,
+  /// and the `isValidKey` defaults to accepting all keys.
+  /// Such a map can be created directly using [HashSet.identity].
+  external factory HashSet(
+      {bool equals(E e1, E e2),
+      int hashCode(E e),
+      bool isValidKey(potentialKey)});
+
+  /// Creates an unordered identity-based set.
+  ///
+  /// Effectively a shorthand for:
+  ///
+  ///     new HashSet<E>(equals: identical,
+  ///                    hashCode: identityHashCode)
+  external factory HashSet.identity();
+
+  /// Create a hash set containing all [elements].
+  ///
+  /// Creates a hash set as by `new HashSet<E>()` and adds all given [elements]
+  /// to the set. The elements are added in order. If [elements] contains
+  /// two entries that are equal, but not identical, then the first one is
+  /// the one in the resulting set.
+  ///
+  /// All the [elements] should be instances of [E].
+  /// The `elements` iterable itself may have any element type, so this
+  /// constructor can be used to down-cast a `Set`, for example as:
+  /// ```dart
+  /// Set<SuperType> superSet = ...;
+  /// Set<SubType> subSet =
+  ///     new HashSet<SubType>.from(superSet.whereType<SubType>());
+  /// ```
+  factory HashSet.from(Iterable elements) {
+    HashSet<E> result = HashSet<E>();
+    for (final e in elements) {
+      result.add(e);
+    }
+    return result;
+  }
+
+  /// Create a hash set containing all [elements].
+  ///
+  /// Creates a hash set as by `new HashSet<E>()` and adds all given [elements]
+  /// to the set. The elements are added in order. If [elements] contains
+  /// two entries that are equal, but not identical, then the first one is
+  /// the one in the resulting set.
+  factory HashSet.of(Iterable<E> elements) => HashSet<E>()..addAll(elements);
+
+  /// Provides an iterator that iterates over the elements of this set.
+  ///
+  /// The order of iteration is unspecified,
+  /// but consistent between changes to the set.
+  Iterator<E> get iterator;
+}
diff --git a/sdk_nnbd/lib/collection/iterable.dart b/sdk_nnbd/lib/collection/iterable.dart
new file mode 100644
index 0000000..14e7226
--- /dev/null
+++ b/sdk_nnbd/lib/collection/iterable.dart
@@ -0,0 +1,402 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.collection;
+
+/// This [Iterable] mixin implements all [Iterable] members except `iterator`.
+///
+/// All other methods are implemented in terms of `iterator`.
+abstract class IterableMixin<E> implements Iterable<E> {
+  // This class has methods copied verbatim into:
+  // - IterableBase
+  // - SetMixin
+  // If changing a method here, also change the other copies.
+
+  Iterable<R> cast<R>() => Iterable.castFrom<E, R>(this);
+  Iterable<T> map<T>(T f(E element)) => MappedIterable<E, T>(this, f);
+
+  Iterable<E> where(bool f(E element)) => WhereIterable<E>(this, f);
+
+  Iterable<T> whereType<T>() => WhereTypeIterable<T>(this);
+
+  Iterable<T> expand<T>(Iterable<T> f(E element)) =>
+      ExpandIterable<E, T>(this, f);
+
+  Iterable<E> followedBy(Iterable<E> other) {
+    // Type workaround because IterableMixin<E> doesn't promote
+    // to EfficientLengthIterable<E>.
+    Iterable<E> self = this;
+    if (self is EfficientLengthIterable<E>) {
+      return FollowedByIterable<E>.firstEfficient(self, other);
+    }
+    return FollowedByIterable<E>(this, other);
+  }
+
+  bool contains(Object element) {
+    for (E e in this) {
+      if (e == element) return true;
+    }
+    return false;
+  }
+
+  void forEach(void f(E element)) {
+    for (E element in this) f(element);
+  }
+
+  E reduce(E combine(E value, E element)) {
+    Iterator<E> iterator = this.iterator;
+    if (!iterator.moveNext()) {
+      throw IterableElementError.noElement();
+    }
+    E value = iterator.current;
+    while (iterator.moveNext()) {
+      value = combine(value, iterator.current);
+    }
+    return value;
+  }
+
+  T fold<T>(T initialValue, T combine(T previousValue, E element)) {
+    var value = initialValue;
+    for (E element in this) value = combine(value, element);
+    return value;
+  }
+
+  bool every(bool f(E element)) {
+    for (E element in this) {
+      if (!f(element)) return false;
+    }
+    return true;
+  }
+
+  String join([String separator = ""]) {
+    Iterator<E> iterator = this.iterator;
+    if (!iterator.moveNext()) return "";
+    StringBuffer buffer = StringBuffer();
+    if (separator == null || separator == "") {
+      do {
+        buffer.write("${iterator.current}");
+      } while (iterator.moveNext());
+    } else {
+      buffer.write("${iterator.current}");
+      while (iterator.moveNext()) {
+        buffer.write(separator);
+        buffer.write("${iterator.current}");
+      }
+    }
+    return buffer.toString();
+  }
+
+  bool any(bool test(E element)) {
+    for (E element in this) {
+      if (test(element)) return true;
+    }
+    return false;
+  }
+
+  List<E> toList({bool growable = true}) =>
+      List<E>.from(this, growable: growable);
+
+  Set<E> toSet() => Set<E>.from(this);
+
+  int get length {
+    assert(this is! EfficientLengthIterable);
+    int count = 0;
+    Iterator it = iterator;
+    while (it.moveNext()) {
+      count++;
+    }
+    return count;
+  }
+
+  bool get isEmpty => !iterator.moveNext();
+
+  bool get isNotEmpty => !isEmpty;
+
+  Iterable<E> take(int count) {
+    return TakeIterable<E>(this, count);
+  }
+
+  Iterable<E> takeWhile(bool test(E value)) {
+    return TakeWhileIterable<E>(this, test);
+  }
+
+  Iterable<E> skip(int count) {
+    return SkipIterable<E>(this, count);
+  }
+
+  Iterable<E> skipWhile(bool test(E value)) {
+    return SkipWhileIterable<E>(this, test);
+  }
+
+  E get first {
+    Iterator<E> it = iterator;
+    if (!it.moveNext()) {
+      throw IterableElementError.noElement();
+    }
+    return it.current;
+  }
+
+  E get last {
+    Iterator<E> it = iterator;
+    if (!it.moveNext()) {
+      throw IterableElementError.noElement();
+    }
+    E result;
+    do {
+      result = it.current;
+    } while (it.moveNext());
+    return result;
+  }
+
+  E get single {
+    Iterator<E> it = iterator;
+    if (!it.moveNext()) throw IterableElementError.noElement();
+    E result = it.current;
+    if (it.moveNext()) throw IterableElementError.tooMany();
+    return result;
+  }
+
+  E firstWhere(bool test(E value), {E orElse()}) {
+    for (E element in this) {
+      if (test(element)) return element;
+    }
+    if (orElse != null) return orElse();
+    throw IterableElementError.noElement();
+  }
+
+  E lastWhere(bool test(E value), {E orElse()}) {
+    E result;
+    bool foundMatching = false;
+    for (E element in this) {
+      if (test(element)) {
+        result = element;
+        foundMatching = true;
+      }
+    }
+    if (foundMatching) return result;
+    if (orElse != null) return orElse();
+    throw IterableElementError.noElement();
+  }
+
+  E singleWhere(bool test(E element), {E orElse()}) {
+    E result;
+    bool foundMatching = false;
+    for (E element in this) {
+      if (test(element)) {
+        if (foundMatching) {
+          throw IterableElementError.tooMany();
+        }
+        result = element;
+        foundMatching = true;
+      }
+    }
+    if (foundMatching) return result;
+    if (orElse != null) return orElse();
+    throw IterableElementError.noElement();
+  }
+
+  E elementAt(int index) {
+    ArgumentError.checkNotNull(index, "index");
+    RangeError.checkNotNegative(index, "index");
+    int elementIndex = 0;
+    for (E element in this) {
+      if (index == elementIndex) return element;
+      elementIndex++;
+    }
+    throw RangeError.index(index, this, "index", null, elementIndex);
+  }
+
+  String toString() => IterableBase.iterableToShortString(this, '(', ')');
+}
+
+/// Base class for implementing [Iterable].
+///
+/// This class implements all methods of [Iterable], except [Iterable.iterator],
+/// in terms of `iterator`.
+abstract class IterableBase<E> extends Iterable<E> {
+  const IterableBase();
+
+  /// Convert an `Iterable` to a string like [IterableBase.toString].
+  ///
+  /// Allows using other delimiters than '(' and ')'.
+  ///
+  /// Handles circular references where converting one of the elements
+  /// to a string ends up converting [iterable] to a string again.
+  static String iterableToShortString(Iterable iterable,
+      [String leftDelimiter = '(', String rightDelimiter = ')']) {
+    if (_isToStringVisiting(iterable)) {
+      if (leftDelimiter == "(" && rightDelimiter == ")") {
+        // Avoid creating a new string in the "common" case.
+        return "(...)";
+      }
+      return "$leftDelimiter...$rightDelimiter";
+    }
+    List<String> parts = <String>[];
+    _toStringVisiting.add(iterable);
+    try {
+      _iterablePartsToStrings(iterable, parts);
+    } finally {
+      assert(identical(_toStringVisiting.last, iterable));
+      _toStringVisiting.removeLast();
+    }
+    return (StringBuffer(leftDelimiter)
+          ..writeAll(parts, ", ")
+          ..write(rightDelimiter))
+        .toString();
+  }
+
+  /// Converts an `Iterable` to a string.
+  ///
+  /// Converts each elements to a string, and separates the results by ", ".
+  /// Then wraps the result in [leftDelimiter] and [rightDelimiter].
+  ///
+  /// Unlike [iterableToShortString], this conversion doesn't omit any
+  /// elements or puts any limit on the size of the result.
+  ///
+  /// Handles circular references where converting one of the elements
+  /// to a string ends up converting [iterable] to a string again.
+  static String iterableToFullString(Iterable iterable,
+      [String leftDelimiter = '(', String rightDelimiter = ')']) {
+    if (_isToStringVisiting(iterable)) {
+      return "$leftDelimiter...$rightDelimiter";
+    }
+    StringBuffer buffer = StringBuffer(leftDelimiter);
+    _toStringVisiting.add(iterable);
+    try {
+      buffer.writeAll(iterable, ", ");
+    } finally {
+      assert(identical(_toStringVisiting.last, iterable));
+      _toStringVisiting.removeLast();
+    }
+    buffer.write(rightDelimiter);
+    return buffer.toString();
+  }
+}
+
+/// A collection used to identify cyclic lists during toString() calls.
+final List _toStringVisiting = [];
+
+/// Check if we are currently visiting `o` in a toString call.
+bool _isToStringVisiting(Object o) {
+  for (int i = 0; i < _toStringVisiting.length; i++) {
+    if (identical(o, _toStringVisiting[i])) return true;
+  }
+  return false;
+}
+
+/// Convert elements of [iterable] to strings and store them in [parts].
+void _iterablePartsToStrings(Iterable iterable, List<String> parts) {
+  /*
+   * This is the complicated part of [iterableToShortString].
+   * It is extracted as a separate function to avoid having too much code
+   * inside the try/finally.
+   */
+  /// Try to stay below this many characters.
+  const int lengthLimit = 80;
+
+  /// Always at least this many elements at the start.
+  const int headCount = 3;
+
+  /// Always at least this many elements at the end.
+  const int tailCount = 2;
+
+  /// Stop iterating after this many elements. Iterables can be infinite.
+  const int maxCount = 100;
+  // Per entry length overhead. It's for ", " for all after the first entry,
+  // and for "(" and ")" for the initial entry. By pure luck, that's the same
+  // number.
+  const int overhead = 2;
+  const int ellipsisSize = 3; // "...".length.
+
+  int length = 0;
+  int count = 0;
+  Iterator it = iterable.iterator;
+  // Initial run of elements, at least headCount, and then continue until
+  // passing at most lengthLimit characters.
+  while (length < lengthLimit || count < headCount) {
+    if (!it.moveNext()) return;
+    String next = "${it.current}";
+    parts.add(next);
+    length += next.length + overhead;
+    count++;
+  }
+
+  String penultimateString;
+  String ultimateString;
+
+  // Find last two elements. One or more of them may already be in the
+  // parts array. Include their length in `length`.
+  Object penultimate;
+  Object ultimate;
+  if (!it.moveNext()) {
+    if (count <= headCount + tailCount) return;
+    ultimateString = parts.removeLast();
+    penultimateString = parts.removeLast();
+  } else {
+    penultimate = it.current;
+    count++;
+    if (!it.moveNext()) {
+      if (count <= headCount + 1) {
+        parts.add("$penultimate");
+        return;
+      }
+      ultimateString = "$penultimate";
+      penultimateString = parts.removeLast();
+      length += ultimateString.length + overhead;
+    } else {
+      ultimate = it.current;
+      count++;
+      // Then keep looping, keeping the last two elements in variables.
+      assert(count < maxCount);
+      while (it.moveNext()) {
+        penultimate = ultimate;
+        ultimate = it.current;
+        count++;
+        if (count > maxCount) {
+          // If we haven't found the end before maxCount, give up.
+          // This cannot happen in the code above because each entry
+          // increases length by at least two, so there is no way to
+          // visit more than ~40 elements before this loop.
+
+          // Remove any surplus elements until length, including ", ...)",
+          // is at most lengthLimit.
+          while (length > lengthLimit - ellipsisSize - overhead &&
+              count > headCount) {
+            length -= parts.removeLast().length + overhead;
+            count--;
+          }
+          parts.add("...");
+          return;
+        }
+      }
+      penultimateString = "$penultimate";
+      ultimateString = "$ultimate";
+      length += ultimateString.length + penultimateString.length + 2 * overhead;
+    }
+  }
+
+  // If there is a gap between the initial run and the last two,
+  // prepare to add an ellipsis.
+  String elision;
+  if (count > parts.length + tailCount) {
+    elision = "...";
+    length += ellipsisSize + overhead;
+  }
+
+  // If the last two elements were very long, and we have more than
+  // headCount elements in the initial run, drop some to make room for
+  // the last two.
+  while (length > lengthLimit && parts.length > headCount) {
+    length -= parts.removeLast().length + overhead;
+    if (elision == null) {
+      elision = "...";
+      length += ellipsisSize + overhead;
+    }
+  }
+  if (elision != null) {
+    parts.add(elision);
+  }
+  parts.add(penultimateString);
+  parts.add(ultimateString);
+}
diff --git a/sdk_nnbd/lib/collection/iterator.dart b/sdk_nnbd/lib/collection/iterator.dart
new file mode 100644
index 0000000..671f0ee
--- /dev/null
+++ b/sdk_nnbd/lib/collection/iterator.dart
@@ -0,0 +1,43 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.collection;
+
+/// The [HasNextIterator] class wraps an [Iterator] and provides methods to
+/// iterate over an object using `hasNext` and `next`.
+///
+/// An [HasNextIterator] does not implement the [Iterator] interface.
+class HasNextIterator<E> {
+  static const int _HAS_NEXT_AND_NEXT_IN_CURRENT = 0;
+  static const int _NO_NEXT = 1;
+  static const int _NOT_MOVED_YET = 2;
+
+  Iterator<E> _iterator;
+  int _state = _NOT_MOVED_YET;
+
+  HasNextIterator(this._iterator);
+
+  bool get hasNext {
+    if (_state == _NOT_MOVED_YET) _move();
+    return _state == _HAS_NEXT_AND_NEXT_IN_CURRENT;
+  }
+
+  E next() {
+    // Call to hasNext is necessary to make sure we are positioned at the first
+    // element when we start iterating.
+    if (!hasNext) throw StateError("No more elements");
+    assert(_state == _HAS_NEXT_AND_NEXT_IN_CURRENT);
+    E result = _iterator.current;
+    _move();
+    return result;
+  }
+
+  void _move() {
+    if (_iterator.moveNext()) {
+      _state = _HAS_NEXT_AND_NEXT_IN_CURRENT;
+    } else {
+      _state = _NO_NEXT;
+    }
+  }
+}
diff --git a/sdk_nnbd/lib/collection/linked_hash_map.dart b/sdk_nnbd/lib/collection/linked_hash_map.dart
new file mode 100644
index 0000000..e3a650d
--- /dev/null
+++ b/sdk_nnbd/lib/collection/linked_hash_map.dart
@@ -0,0 +1,141 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.collection;
+
+/// A hash-table based implementation of [Map].
+///
+/// The insertion order of keys is remembered,
+/// and keys are iterated in the order they were inserted into the map.
+/// Values are iterated in their corresponding key's order.
+/// Changing a key's value, when the key is already in the map,
+/// does not change the iteration order,
+/// but removing the key and adding it again
+/// will make it be last in the iteration order.
+///
+/// The keys of a `LinkedHashMap` must have consistent [Object.==]
+/// and [Object.hashCode] implementations. This means that the `==` operator
+/// must define a stable equivalence relation on the keys (reflexive,
+/// symmetric, transitive, and consistent over time), and that `hashCode`
+/// must be the same for objects that are considered equal by `==`.
+///
+/// The map allows `null` as a key.
+abstract class LinkedHashMap<K, V> implements Map<K, V> {
+  /// Creates an insertion-ordered hash-table based [Map].
+  ///
+  /// If [equals] is provided, it is used to compare the keys in the table with
+  /// new keys. If [equals] is omitted, the key's own [Object.==] is used
+  /// instead.
+  ///
+  /// Similar, if [hashCode] is provided, it is used to produce a hash value
+  /// for keys in order to place them in the hash table. If it is omitted, the
+  /// key's own [Object.hashCode] is used.
+  ///
+  /// If using methods like [operator []], [remove] and [containsKey] together
+  /// with a custom equality and hashcode, an extra `isValidKey` function
+  /// can be supplied. This function is called before calling [equals] or
+  /// [hashCode] with an argument that may not be a [K] instance, and if the
+  /// call returns false, the key is assumed to not be in the set.
+  /// The [isValidKey] function defaults to just testing if the object is a
+  /// [K] instance.
+  ///
+  /// Example:
+  ///
+  ///     new LinkedHashMap<int,int>(equals: (int a, int b) => (b - a) % 5 == 0,
+  ///                                hashCode: (int e) => e % 5)
+  ///
+  /// This example map does not need an `isValidKey` function to be passed.
+  /// The default function accepts only `int` values, which can safely be
+  /// passed to both the `equals` and `hashCode` functions.
+  ///
+  /// If neither `equals`, `hashCode`, nor `isValidKey` is provided,
+  /// the default `isValidKey` instead accepts all keys.
+  /// The default equality and hashcode operations are assumed to work on all
+  /// objects.
+  ///
+  /// Likewise, if `equals` is [identical], `hashCode` is [identityHashCode]
+  /// and `isValidKey` is omitted, the resulting map is identity based,
+  /// and the `isValidKey` defaults to accepting all keys.
+  /// Such a map can be created directly using [LinkedHashMap.identity].
+  ///
+  /// The used `equals` and `hashCode` method should always be consistent,
+  /// so that if `equals(a, b)` then `hashCode(a) == hashCode(b)`. The hash
+  /// of an object, or what it compares equal to, should not change while the
+  /// object is in the table. If it does change, the result is unpredictable.
+  ///
+  /// If you supply one of [equals] and [hashCode],
+  /// you should generally also to supply the other.
+  external factory LinkedHashMap(
+      {bool equals(K key1, K key2),
+      int hashCode(K key),
+      bool isValidKey(potentialKey)});
+
+  /// Creates an insertion-ordered identity-based map.
+  ///
+  /// Effectively a shorthand for:
+  ///
+  ///     new LinkedHashMap<K, V>(equals: identical,
+  ///                             hashCode: identityHashCode)
+  external factory LinkedHashMap.identity();
+
+  /// Creates a [LinkedHashMap] that contains all key value pairs of [other].
+  ///
+  /// The keys must all be instances of [K] and the values to [V].
+  /// The [other] map itself can have any type.
+  factory LinkedHashMap.from(Map other) {
+    LinkedHashMap<K, V> result = LinkedHashMap<K, V>();
+    other.forEach((k, v) {
+      result[k] = v;
+    });
+    return result;
+  }
+
+  /// Creates a [LinkedHashMap] that contains all key value pairs of [other].
+  factory LinkedHashMap.of(Map<K, V> other) =>
+      LinkedHashMap<K, V>()..addAll(other);
+
+  /// Creates a [LinkedHashMap] where the keys and values are computed from the
+  /// [iterable].
+  ///
+  /// For each element of the [iterable] this constructor computes a key/value
+  /// pair, by applying [key] and [value] respectively.
+  ///
+  /// The keys of the key/value pairs do not need to be unique. The last
+  /// occurrence of a key will simply overwrite any previous value.
+  ///
+  /// If no values are specified for [key] and [value] the default is the
+  /// identity function.
+  factory LinkedHashMap.fromIterable(Iterable iterable,
+      {K key(element), V value(element)}) {
+    LinkedHashMap<K, V> map = LinkedHashMap<K, V>();
+    MapBase._fillMapWithMappedIterable(map, iterable, key, value);
+    return map;
+  }
+
+  /// Creates a [LinkedHashMap] associating the given [keys] to [values].
+  ///
+  /// This constructor iterates over [keys] and [values] and maps each element of
+  /// [keys] to the corresponding element of [values].
+  ///
+  /// If [keys] contains the same object multiple times, the last occurrence
+  /// overwrites the previous value.
+  ///
+  /// It is an error if the two [Iterable]s don't have the same length.
+  factory LinkedHashMap.fromIterables(Iterable<K> keys, Iterable<V> values) {
+    LinkedHashMap<K, V> map = LinkedHashMap<K, V>();
+    MapBase._fillMapWithIterables(map, keys, values);
+    return map;
+  }
+
+  /// Creates a [LinkedHashMap] containing the entries of [entries].
+  ///
+  /// Returns a new `LinkedHashMap<K, V>` where all entries of [entries]
+  /// have been added in iteration order.
+  ///
+  /// If multiple [entries] have the same key,
+  /// later occurrences overwrite the earlier ones.
+  @Since("2.1")
+  factory LinkedHashMap.fromEntries(Iterable<MapEntry<K, V>> entries) =>
+      <K, V>{}..addEntries(entries);
+}
diff --git a/sdk_nnbd/lib/collection/linked_hash_set.dart b/sdk_nnbd/lib/collection/linked_hash_set.dart
new file mode 100644
index 0000000..a058b5e
--- /dev/null
+++ b/sdk_nnbd/lib/collection/linked_hash_set.dart
@@ -0,0 +1,120 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.collection;
+
+/// A [LinkedHashSet] is a hash-table based [Set] implementation.
+///
+/// The `LinkedHashSet` also keep track of the order that elements were inserted
+/// in, and iteration happens in first-to-last insertion order.
+///
+/// The elements of a `LinkedHashSet` must have consistent [Object.==]
+/// and [Object.hashCode] implementations. This means that the `==` operator
+/// must define a stable equivalence relation on the elements (reflexive,
+/// symmetric, transitive, and consistent over time), and that `hashCode`
+/// must be the same for objects that are considered equal by `==`.
+///
+/// The set allows `null` as an element.
+///
+/// Iteration of elements is done in element insertion order.
+/// An element that was added after another will occur later in the iteration.
+/// Adding an element that is already in the set
+/// does not change its position in the iteration order,
+/// but removing an element and adding it again,
+/// will make it the last element of an iteration.
+///
+/// Most simple operations on `HashSet` are done in (potentially amortized)
+/// constant time: [add], [contains], [remove], and [length], provided the hash
+/// codes of objects are well distributed..
+abstract class LinkedHashSet<E> implements Set<E> {
+  /// Create an insertion-ordered hash set using the provided
+  /// [equals] and [hashCode].
+  ///
+  /// The provided [equals] must define a stable equivalence relation, and
+  /// [hashCode] must be consistent with [equals]. If the [equals] or [hashCode]
+  /// methods won't work on all objects, but only on some instances of E, the
+  /// [isValidKey] predicate can be used to restrict the keys that the functions
+  /// are applied to.
+  /// Any key for which [isValidKey] returns false is automatically assumed
+  /// to not be in the set when asking `contains`.
+  ///
+  /// If [equals] or [hashCode] are omitted, the set uses
+  /// the elements' intrinsic [Object.==] and [Object.hashCode],
+  /// and [isValidKey] is ignored since these operations are assumed
+  /// to work on all objects.
+  ///
+  /// If you supply one of [equals] and [hashCode],
+  /// you should generally also to supply the other.
+  ///
+  /// If the supplied `equals` or `hashCode` functions won't work on all [E]
+  /// objects, and the map will be used in a setting where a non-`E` object
+  /// is passed to, e.g., `contains`, then the [isValidKey] function should
+  /// also be supplied.
+  ///
+  /// If [isValidKey] is omitted, it defaults to testing if the object is an
+  /// [E] instance. That means that:
+  ///
+  ///     new LinkedHashSet<int>(equals: (int e1, int e2) => (e1 - e2) % 5 == 0,
+  ///                            hashCode: (int e) => e % 5)
+  ///
+  /// does not need an `isValidKey` argument, because it defaults to only
+  /// accepting `int` values which are accepted by both `equals` and `hashCode`.
+  ///
+  /// If neither `equals`, `hashCode`, nor `isValidKey` is provided,
+  /// the default `isValidKey` instead accepts all values.
+  /// The default equality and hashcode operations are assumed to work on all
+  /// objects.
+  ///
+  /// Likewise, if `equals` is [identical], `hashCode` is [identityHashCode]
+  /// and `isValidKey` is omitted, the resulting set is identity based,
+  /// and the `isValidKey` defaults to accepting all keys.
+  /// Such a map can be created directly using [LinkedHashSet.identity].
+  external factory LinkedHashSet(
+      {bool equals(E e1, E e2),
+      int hashCode(E e),
+      bool isValidKey(potentialKey)});
+
+  /// Creates an insertion-ordered identity-based set.
+  ///
+  /// Effectively a shorthand for:
+  ///
+  ///     new LinkedHashSet<E>(equals: identical,
+  ///                          hashCode: identityHashCode)
+  external factory LinkedHashSet.identity();
+
+  /// Create a linked hash set containing all [elements].
+  ///
+  /// Creates a linked hash set as by `new LinkedHashSet<E>()` and adds each
+  /// element of `elements` to this set in the order they are iterated.
+  ///
+  /// All the [elements] should be instances of [E].
+  /// The `elements` iterable itself may have any element type,
+  /// so this constructor can be used to down-cast a `Set`, for example as:
+  ///
+  ///     Set<SuperType> superSet = ...;
+  ///     Iterable<SuperType> tmp = superSet.where((e) => e is SubType);
+  ///     Set<SubType> subSet = new LinkedHashSet<SubType>.from(tmp);
+  factory LinkedHashSet.from(Iterable elements) {
+    LinkedHashSet<E> result = LinkedHashSet<E>();
+    for (final element in elements) {
+      result.add(element);
+    }
+    return result;
+  }
+
+  /// Create a linked hash set from [elements].
+  ///
+  /// Creates a linked hash set as by `new LinkedHashSet<E>()` and adds each
+  /// element of `elements` to this set in the order they are iterated.
+  factory LinkedHashSet.of(Iterable<E> elements) =>
+      LinkedHashSet<E>()..addAll(elements);
+
+  /// Executes a function on each element of the set.
+  ///
+  /// The elements are iterated in insertion order.
+  void forEach(void action(E element));
+
+  /// Provides an iterator that iterates over the elements in insertion order.
+  Iterator<E> get iterator;
+}
diff --git a/sdk_nnbd/lib/collection/linked_list.dart b/sdk_nnbd/lib/collection/linked_list.dart
new file mode 100644
index 0000000..91461cb
--- /dev/null
+++ b/sdk_nnbd/lib/collection/linked_list.dart
@@ -0,0 +1,263 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.collection;
+
+/// A specialized double-linked list of elements that extends [LinkedListEntry].
+///
+/// This is not a generic data structure. It only accepts elements that extend
+/// the [LinkedListEntry] class. See the [Queue] implementations for generic
+/// collections that allow constant time adding and removing at the ends.
+///
+/// This is not a [List] implementation. Despite its name, this class does not
+/// implement the [List] interface. It does not allow constant time lookup by
+/// index.
+///
+/// Because the elements themselves contain the links of this linked list,
+/// each element can be in only one list at a time. To add an element to another
+/// list, it must first be removed from its current list (if any).
+///
+/// In return, each element knows its own place in the linked list, as well as
+/// which list it is in. This allows constant time
+/// [LinkedListEntry.insertAfter], [LinkedListEntry.insertBefore] and
+/// [LinkedListEntry.unlink] operations when all you have is the element.
+///
+/// A `LinkedList` also allows constant time adding and removing at either end,
+/// and a constant time length getter.
+class LinkedList<E extends LinkedListEntry<E>> extends Iterable<E> {
+  int _modificationCount = 0;
+  int _length = 0;
+  E _first;
+
+  /// Construct a new empty linked list.
+  LinkedList();
+
+  /// Add [entry] to the beginning of the linked list.
+  void addFirst(E entry) {
+    _insertBefore(_first, entry, updateFirst: true);
+    _first = entry;
+  }
+
+  /// Add [entry] to the end of the linked list.
+  void add(E entry) {
+    _insertBefore(_first, entry, updateFirst: false);
+  }
+
+  /// Add [entries] to the end of the linked list.
+  void addAll(Iterable<E> entries) {
+    entries.forEach(add);
+  }
+
+  /// Remove [entry] from the linked list.
+  ///
+  /// Returns false and does nothing if [entry] is not in this linked list.
+  ///
+  /// This is equivalent to calling `entry.unlink()` if the entry is in this
+  /// list.
+  bool remove(E entry) {
+    if (entry._list != this) return false;
+    _unlink(entry); // Unlink will decrement length.
+    return true;
+  }
+
+  Iterator<E> get iterator => _LinkedListIterator<E>(this);
+
+  int get length => _length;
+
+  /// Remove all elements from this linked list.
+  void clear() {
+    _modificationCount++;
+    if (isEmpty) return;
+
+    E next = _first;
+    do {
+      E entry = next;
+      next = entry._next;
+      entry._next = entry._previous = entry._list = null;
+    } while (!identical(next, _first));
+
+    _first = null;
+    _length = 0;
+  }
+
+  E get first {
+    if (isEmpty) {
+      throw StateError('No such element');
+    }
+    return _first;
+  }
+
+  E get last {
+    if (isEmpty) {
+      throw StateError('No such element');
+    }
+    return _first._previous;
+  }
+
+  E get single {
+    if (isEmpty) {
+      throw StateError('No such element');
+    }
+    if (_length > 1) {
+      throw StateError('Too many elements');
+    }
+    return _first;
+  }
+
+  /// Call [action] with each entry in this linked list.
+  ///
+  /// It's an error if [action] modify the linked list.
+  void forEach(void action(E entry)) {
+    int modificationCount = _modificationCount;
+    if (isEmpty) return;
+
+    E current = _first;
+    do {
+      action(current);
+      if (modificationCount != _modificationCount) {
+        throw ConcurrentModificationError(this);
+      }
+      current = current._next;
+    } while (!identical(current, _first));
+  }
+
+  bool get isEmpty => _length == 0;
+
+  /// Inserts [newEntry] as last entry of the list.
+  ///
+  /// If [updateFirst] is true and [entry] is the first entry in the list,
+  /// updates the [_first] field to point to the [newEntry] as first entry.
+  void _insertBefore(E entry, E newEntry, {bool updateFirst}) {
+    if (newEntry.list != null) {
+      throw StateError('LinkedListEntry is already in a LinkedList');
+    }
+    _modificationCount++;
+
+    newEntry._list = this;
+    if (isEmpty) {
+      assert(entry == null);
+      newEntry._previous = newEntry._next = newEntry;
+      _first = newEntry;
+      _length++;
+      return;
+    }
+    E predecessor = entry._previous;
+    E successor = entry;
+    newEntry._previous = predecessor;
+    newEntry._next = successor;
+    predecessor._next = newEntry;
+    successor._previous = newEntry;
+    if (updateFirst && identical(entry, _first)) {
+      _first = newEntry;
+    }
+    _length++;
+  }
+
+  void _unlink(E entry) {
+    _modificationCount++;
+    entry._next._previous = entry._previous;
+    E next = entry._previous._next = entry._next;
+    _length--;
+    entry._list = entry._next = entry._previous = null;
+    if (isEmpty) {
+      _first = null;
+    } else if (identical(entry, _first)) {
+      _first = next;
+    }
+  }
+}
+
+class _LinkedListIterator<E extends LinkedListEntry<E>> implements Iterator<E> {
+  final LinkedList<E> _list;
+  final int _modificationCount;
+  E _current;
+  LinkedListEntry<E> _next;
+  bool _visitedFirst;
+
+  _LinkedListIterator(LinkedList<E> list)
+      : _list = list,
+        _modificationCount = list._modificationCount,
+        _next = list._first,
+        _visitedFirst = false;
+
+  E get current => _current;
+
+  bool moveNext() {
+    if (_modificationCount != _list._modificationCount) {
+      throw ConcurrentModificationError(this);
+    }
+    if (_list.isEmpty || (_visitedFirst && identical(_next, _list.first))) {
+      _current = null;
+      return false;
+    }
+    _visitedFirst = true;
+    _current = _next;
+    _next = _next._next;
+    return true;
+  }
+}
+
+/// An object that can be an element in a [LinkedList].
+///
+/// All elements of a `LinkedList` must extend this class.
+/// The class provides the internal links that link elements together
+/// in the `LinkedList`, and a reference to the linked list itself
+/// that an element is currently part of.
+///
+/// An entry can be in at most one linked list at a time.
+/// While an entry is in a linked list, the [list] property points to that
+/// linked list, and otherwise the `list` property is `null`.
+///
+/// When created, an entry is not in any linked list.
+abstract class LinkedListEntry<E extends LinkedListEntry<E>> {
+  LinkedList<E> _list;
+  E _next;
+  E _previous;
+
+  /// Get the linked list containing this element.
+  ///
+  /// Returns `null` if this entry is not currently in any list.
+  LinkedList<E> get list => _list;
+
+  /// Unlink the element from its linked list.
+  ///
+  /// The entry must currently be in a linked list when this method is called.
+  void unlink() {
+    _list._unlink(this);
+  }
+
+  /// Return the successor of this element in its linked list.
+  ///
+  /// Returns `null` if there is no successor in the linked list, or if this
+  /// entry is not currently in any list.
+  E get next {
+    if (_list == null || identical(_list.first, _next)) return null;
+    return _next;
+  }
+
+  /// Return the predecessor of this element in its linked list.
+  ///
+  /// Returns `null` if there is no predecessor in the linked list, or if this
+  /// entry is not currently in any list.
+  E get previous {
+    if (_list == null || identical(this, _list.first)) return null;
+    return _previous;
+  }
+
+  /// Insert an element after this element in this element's linked list.
+  ///
+  /// This entry must be in a linked list when this method is called.
+  /// The [entry] must not be in a linked list.
+  void insertAfter(E entry) {
+    _list._insertBefore(_next, entry, updateFirst: false);
+  }
+
+  /// Insert an element before this element in this element's linked list.
+  ///
+  /// This entry must be in a linked list when this method is called.
+  /// The [entry] must not be in a linked list.
+  void insertBefore(E entry) {
+    _list._insertBefore(this, entry, updateFirst: true);
+  }
+}
diff --git a/sdk_nnbd/lib/collection/list.dart b/sdk_nnbd/lib/collection/list.dart
new file mode 100644
index 0000000..1d83aa4
--- /dev/null
+++ b/sdk_nnbd/lib/collection/list.dart
@@ -0,0 +1,535 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.collection;
+
+/// Abstract implementation of a list.
+///
+/// `ListBase` can be used as a base class for implementing the `List`
+/// interface.
+///
+/// All operations are defined in terms of `length`, `operator[]`,
+/// `operator[]=` and `length=`, which need to be implemented.
+///
+/// *NOTICE*: Forwarding just these four operations to a normal growable [List]
+/// (as created by `new List()`) will give very bad performance for `add` and
+/// `addAll` operations of `ListBase`. These operations are implemented by
+/// increasing the length of the list by one for each `add` operation, and
+/// repeatedly increasing the length of a growable list is not efficient.
+/// To avoid this, either override 'add' and 'addAll' to also forward directly
+/// to the growable list, or, preferably, use `DelegatingList` from
+/// "package:collection/wrappers.dart" instead.
+abstract class ListBase<E> extends Object with ListMixin<E> {
+  /// Convert a `List` to a string as `[each, element, as, string]`.
+  ///
+  /// Handles circular references where converting one of the elements
+  /// to a string ends up converting [list] to a string again.
+  static String listToString(List list) =>
+      IterableBase.iterableToFullString(list, '[', ']');
+}
+
+/// Base implementation of a [List] class.
+///
+/// `ListMixin` can be used as a mixin to make a class implement
+/// the `List` interface.
+///
+/// This implements all read operations using only the `length` and
+/// `operator[]` members. It implements write operations using those and
+/// `length=` and `operator[]=`
+///
+/// *NOTICE*: Forwarding just these four operations to a normal growable [List]
+/// (as created by `new List()`) will give very bad performance for `add` and
+/// `addAll` operations of `ListBase`. These operations are implemented by
+/// increasing the length of the list by one for each `add` operation, and
+/// repeatedly increasing the length of a growable list is not efficient.
+/// To avoid this, either override 'add' and 'addAll' to also forward directly
+/// to the growable list, or, if possible, use `DelegatingList` from
+/// "package:collection/wrappers.dart" instead.
+abstract class ListMixin<E> implements List<E> {
+  // Iterable interface.
+  // TODO(lrn): When we get composable mixins, reuse IterableMixin instead
+  // of redaclating everything.
+  Iterator<E> get iterator => ListIterator<E>(this);
+
+  E elementAt(int index) => this[index];
+
+  Iterable<E> followedBy(Iterable<E> other) =>
+      FollowedByIterable<E>.firstEfficient(this, other);
+
+  void forEach(void action(E element)) {
+    int length = this.length;
+    for (int i = 0; i < length; i++) {
+      action(this[i]);
+      if (length != this.length) {
+        throw ConcurrentModificationError(this);
+      }
+    }
+  }
+
+  @pragma("vm:prefer-inline")
+  bool get isEmpty => length == 0;
+
+  bool get isNotEmpty => !isEmpty;
+
+  E get first {
+    if (length == 0) throw IterableElementError.noElement();
+    return this[0];
+  }
+
+  void set first(E value) {
+    if (length == 0) throw IterableElementError.noElement();
+    this[0] = value;
+  }
+
+  E get last {
+    if (length == 0) throw IterableElementError.noElement();
+    return this[length - 1];
+  }
+
+  void set last(E value) {
+    if (length == 0) throw IterableElementError.noElement();
+    this[length - 1] = value;
+  }
+
+  E get single {
+    if (length == 0) throw IterableElementError.noElement();
+    if (length > 1) throw IterableElementError.tooMany();
+    return this[0];
+  }
+
+  bool contains(Object element) {
+    int length = this.length;
+    for (int i = 0; i < length; i++) {
+      if (this[i] == element) return true;
+      if (length != this.length) {
+        throw ConcurrentModificationError(this);
+      }
+    }
+    return false;
+  }
+
+  bool every(bool test(E element)) {
+    int length = this.length;
+    for (int i = 0; i < length; i++) {
+      if (!test(this[i])) return false;
+      if (length != this.length) {
+        throw ConcurrentModificationError(this);
+      }
+    }
+    return true;
+  }
+
+  bool any(bool test(E element)) {
+    int length = this.length;
+    for (int i = 0; i < length; i++) {
+      if (test(this[i])) return true;
+      if (length != this.length) {
+        throw ConcurrentModificationError(this);
+      }
+    }
+    return false;
+  }
+
+  E firstWhere(bool test(E element), {E orElse()}) {
+    int length = this.length;
+    for (int i = 0; i < length; i++) {
+      E element = this[i];
+      if (test(element)) return element;
+      if (length != this.length) {
+        throw ConcurrentModificationError(this);
+      }
+    }
+    if (orElse != null) return orElse();
+    throw IterableElementError.noElement();
+  }
+
+  E lastWhere(bool test(E element), {E orElse()}) {
+    int length = this.length;
+    for (int i = length - 1; i >= 0; i--) {
+      E element = this[i];
+      if (test(element)) return element;
+      if (length != this.length) {
+        throw ConcurrentModificationError(this);
+      }
+    }
+    if (orElse != null) return orElse();
+    throw IterableElementError.noElement();
+  }
+
+  E singleWhere(bool test(E element), {E orElse()}) {
+    int length = this.length;
+    E match;
+    bool matchFound = false;
+    for (int i = 0; i < length; i++) {
+      E element = this[i];
+      if (test(element)) {
+        if (matchFound) {
+          throw IterableElementError.tooMany();
+        }
+        matchFound = true;
+        match = element;
+      }
+      if (length != this.length) {
+        throw ConcurrentModificationError(this);
+      }
+    }
+    if (matchFound) return match;
+    if (orElse != null) return orElse();
+    throw IterableElementError.noElement();
+  }
+
+  String join([String separator = ""]) {
+    if (length == 0) return "";
+    StringBuffer buffer = StringBuffer()..writeAll(this, separator);
+    return buffer.toString();
+  }
+
+  Iterable<E> where(bool test(E element)) => WhereIterable<E>(this, test);
+
+  Iterable<T> whereType<T>() => WhereTypeIterable<T>(this);
+
+  Iterable<T> map<T>(T f(E element)) => MappedListIterable<E, T>(this, f);
+
+  Iterable<T> expand<T>(Iterable<T> f(E element)) =>
+      ExpandIterable<E, T>(this, f);
+
+  E reduce(E combine(E previousValue, E element)) {
+    int length = this.length;
+    if (length == 0) throw IterableElementError.noElement();
+    E value = this[0];
+    for (int i = 1; i < length; i++) {
+      value = combine(value, this[i]);
+      if (length != this.length) {
+        throw ConcurrentModificationError(this);
+      }
+    }
+    return value;
+  }
+
+  T fold<T>(T initialValue, T combine(T previousValue, E element)) {
+    var value = initialValue;
+    int length = this.length;
+    for (int i = 0; i < length; i++) {
+      value = combine(value, this[i]);
+      if (length != this.length) {
+        throw ConcurrentModificationError(this);
+      }
+    }
+    return value;
+  }
+
+  Iterable<E> skip(int count) => SubListIterable<E>(this, count, null);
+
+  Iterable<E> skipWhile(bool test(E element)) {
+    return SkipWhileIterable<E>(this, test);
+  }
+
+  Iterable<E> take(int count) => SubListIterable<E>(this, 0, count);
+
+  Iterable<E> takeWhile(bool test(E element)) {
+    return TakeWhileIterable<E>(this, test);
+  }
+
+  List<E> toList({bool growable = true}) {
+    List<E> result;
+    if (growable) {
+      result = <E>[]..length = length;
+    } else {
+      result = List<E>(length);
+    }
+    for (int i = 0; i < length; i++) {
+      result[i] = this[i];
+    }
+    return result;
+  }
+
+  Set<E> toSet() {
+    Set<E> result = Set<E>();
+    for (int i = 0; i < length; i++) {
+      result.add(this[i]);
+    }
+    return result;
+  }
+
+  // List interface.
+  void add(E element) {
+    this[this.length++] = element;
+  }
+
+  void addAll(Iterable<E> iterable) {
+    int i = this.length;
+    for (E element in iterable) {
+      assert(this.length == i || (throw ConcurrentModificationError(this)));
+      this.length = i + 1;
+      this[i] = element;
+      i++;
+    }
+  }
+
+  bool remove(Object element) {
+    for (int i = 0; i < this.length; i++) {
+      if (this[i] == element) {
+        this._closeGap(i, i + 1);
+        return true;
+      }
+    }
+    return false;
+  }
+
+  /// Removes elements from the list starting at [start] up to but not including
+  /// [end].  Arguments are pre-validated.
+  void _closeGap(int start, int end) {
+    int length = this.length;
+    assert(0 <= start);
+    assert(start < end);
+    assert(end <= length);
+    int size = end - start;
+    for (int i = end; i < length; i++) {
+      this[i - size] = this[i];
+    }
+    this.length = length - size;
+  }
+
+  void removeWhere(bool test(E element)) {
+    _filter(test, false);
+  }
+
+  void retainWhere(bool test(E element)) {
+    _filter(test, true);
+  }
+
+  void _filter(bool test(E element), bool retainMatching) {
+    List<E> retained = <E>[];
+    int length = this.length;
+    for (int i = 0; i < length; i++) {
+      var element = this[i];
+      if (test(element) == retainMatching) {
+        retained.add(element);
+      }
+      if (length != this.length) {
+        throw ConcurrentModificationError(this);
+      }
+    }
+    if (retained.length != this.length) {
+      this.setRange(0, retained.length, retained);
+      this.length = retained.length;
+    }
+  }
+
+  void clear() {
+    this.length = 0;
+  }
+
+  List<R> cast<R>() => List.castFrom<E, R>(this);
+  E removeLast() {
+    if (length == 0) {
+      throw IterableElementError.noElement();
+    }
+    E result = this[length - 1];
+    length--;
+    return result;
+  }
+
+  void sort([int compare(E a, E b)]) {
+    Sort.sort(this, compare ?? _compareAny);
+  }
+
+  static int _compareAny(a, b) {
+    // In strong mode Comparable.compare requires an implicit cast to ensure
+    // `a` and `b` are Comparable.
+    return Comparable.compare(a, b);
+  }
+
+  void shuffle([Random random]) {
+    random ??= Random();
+    int length = this.length;
+    while (length > 1) {
+      int pos = random.nextInt(length);
+      length -= 1;
+      var tmp = this[length];
+      this[length] = this[pos];
+      this[pos] = tmp;
+    }
+  }
+
+  Map<int, E> asMap() {
+    return ListMapView<E>(this);
+  }
+
+  List<E> operator +(List<E> other) {
+    var result = <E>[]..length = (this.length + other.length);
+    result.setRange(0, this.length, this);
+    result.setRange(this.length, result.length, other);
+    return result;
+  }
+
+  List<E> sublist(int start, [int end]) {
+    int listLength = this.length;
+    end ??= listLength;
+    RangeError.checkValidRange(start, end, listLength);
+    int length = end - start;
+    List<E> result = <E>[]..length = length;
+    for (int i = 0; i < length; i++) {
+      result[i] = this[start + i];
+    }
+    return result;
+  }
+
+  Iterable<E> getRange(int start, int end) {
+    RangeError.checkValidRange(start, end, this.length);
+    return SubListIterable<E>(this, start, end);
+  }
+
+  void removeRange(int start, int end) {
+    RangeError.checkValidRange(start, end, this.length);
+    if (end > start) {
+      _closeGap(start, end);
+    }
+  }
+
+  void fillRange(int start, int end, [E fill]) {
+    RangeError.checkValidRange(start, end, this.length);
+    for (int i = start; i < end; i++) {
+      this[i] = fill;
+    }
+  }
+
+  void setRange(int start, int end, Iterable<E> iterable, [int skipCount = 0]) {
+    RangeError.checkValidRange(start, end, this.length);
+    int length = end - start;
+    if (length == 0) return;
+    RangeError.checkNotNegative(skipCount, "skipCount");
+
+    List<E> otherList;
+    int otherStart;
+    // TODO(floitsch): Make this accept more.
+    if (iterable is List<E>) {
+      otherList = iterable;
+      otherStart = skipCount;
+    } else {
+      otherList = iterable.skip(skipCount).toList(growable: false);
+      otherStart = 0;
+    }
+    if (otherStart + length > otherList.length) {
+      throw IterableElementError.tooFew();
+    }
+    if (otherStart < start) {
+      // Copy backwards to ensure correct copy if [from] is this.
+      for (int i = length - 1; i >= 0; i--) {
+        this[start + i] = otherList[otherStart + i];
+      }
+    } else {
+      for (int i = 0; i < length; i++) {
+        this[start + i] = otherList[otherStart + i];
+      }
+    }
+  }
+
+  void replaceRange(int start, int end, Iterable<E> newContents) {
+    RangeError.checkValidRange(start, end, this.length);
+    if (newContents is! EfficientLengthIterable) {
+      newContents = newContents.toList();
+    }
+    int removeLength = end - start;
+    int insertLength = newContents.length;
+    if (removeLength >= insertLength) {
+      int insertEnd = start + insertLength;
+      this.setRange(start, insertEnd, newContents);
+      if (removeLength > insertLength) {
+        _closeGap(insertEnd, end);
+      }
+    } else {
+      int delta = insertLength - removeLength;
+      int newLength = this.length + delta;
+      int insertEnd = start + insertLength; // aka. end + delta.
+      this.length = newLength;
+      this.setRange(insertEnd, newLength, this, end);
+      this.setRange(start, insertEnd, newContents);
+    }
+  }
+
+  int indexOf(Object element, [int start = 0]) {
+    if (start < 0) start = 0;
+    for (int i = start; i < this.length; i++) {
+      if (this[i] == element) return i;
+    }
+    return -1;
+  }
+
+  int indexWhere(bool test(E element), [int start = 0]) {
+    if (start < 0) start = 0;
+    for (int i = start; i < this.length; i++) {
+      if (test(this[i])) return i;
+    }
+    return -1;
+  }
+
+  int lastIndexOf(Object element, [int start]) {
+    if (start == null || start >= this.length) start = this.length - 1;
+    for (int i = start; i >= 0; i--) {
+      if (this[i] == element) return i;
+    }
+    return -1;
+  }
+
+  int lastIndexWhere(bool test(E element), [int start]) {
+    if (start == null || start >= this.length) start = this.length - 1;
+    for (int i = start; i >= 0; i--) {
+      if (test(this[i])) return i;
+    }
+    return -1;
+  }
+
+  void insert(int index, E element) {
+    ArgumentError.checkNotNull(index, "index");
+    RangeError.checkValueInInterval(index, 0, length, "index");
+    if (index == this.length) {
+      add(element);
+      return;
+    }
+    this.length++;
+    setRange(index + 1, this.length, this, index);
+    this[index] = element;
+  }
+
+  E removeAt(int index) {
+    E result = this[index];
+    _closeGap(index, index + 1);
+    return result;
+  }
+
+  void insertAll(int index, Iterable<E> iterable) {
+    RangeError.checkValueInInterval(index, 0, length, "index");
+    if (iterable is! EfficientLengthIterable || identical(iterable, this)) {
+      iterable = iterable.toList();
+    }
+    int insertionLength = iterable.length;
+    // There might be errors after the length change, in which case the list
+    // will end up being modified but the operation not complete. Unless we
+    // always go through a "toList" we can't really avoid that.
+    this.length += insertionLength;
+    if (iterable.length != insertionLength) {
+      // If the iterable's length is linked to this list's length somehow,
+      // we can't insert one in the other.
+      this.length -= insertionLength;
+      throw ConcurrentModificationError(iterable);
+    }
+    setRange(index + insertionLength, this.length, this, index);
+    setAll(index, iterable);
+  }
+
+  void setAll(int index, Iterable<E> iterable) {
+    if (iterable is List) {
+      setRange(index, index + iterable.length, iterable);
+    } else {
+      for (E element in iterable) {
+        this[index++] = element;
+      }
+    }
+  }
+
+  Iterable<E> get reversed => ReversedListIterable<E>(this);
+
+  String toString() => IterableBase.iterableToFullString(this, '[', ']');
+}
diff --git a/sdk_nnbd/lib/collection/maps.dart b/sdk_nnbd/lib/collection/maps.dart
new file mode 100644
index 0000000..8159342
--- /dev/null
+++ b/sdk_nnbd/lib/collection/maps.dart
@@ -0,0 +1,378 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.collection;
+
+/// Base class for implementing a [Map].
+///
+/// This class has a basic implementation of all but five of the members of
+/// [Map].
+/// A basic `Map` class can be implemented by extending this class and
+/// implementing `keys`, `operator[]`, `operator[]=`, `remove` and `clear`.
+/// The remaining operations are implemented in terms of these five.
+///
+/// The `keys` iterable should have efficient [Iterable.length] and
+/// [Iterable.contains] operations, and it should catch concurrent modifications
+/// of the keys while iterating.
+///
+/// A more efficient implementation is usually possible by overriding
+/// some of the other members as well.
+abstract class MapBase<K, V> extends MapMixin<K, V> {
+  static String mapToString(Map m) {
+    // Reuses the list in IterableBase for detecting toString cycles.
+    if (_isToStringVisiting(m)) {
+      return '{...}';
+    }
+
+    var result = StringBuffer();
+    try {
+      _toStringVisiting.add(m);
+      result.write('{');
+      bool first = true;
+      m.forEach((k, v) {
+        if (!first) {
+          result.write(', ');
+        }
+        first = false;
+        result.write(k);
+        result.write(': ');
+        result.write(v);
+      });
+      result.write('}');
+    } finally {
+      assert(identical(_toStringVisiting.last, m));
+      _toStringVisiting.removeLast();
+    }
+
+    return result.toString();
+  }
+
+  static _id(x) => x;
+
+  /// Fills a [Map] with key/value pairs computed from [iterable].
+  ///
+  /// This method is used by [Map] classes in the named constructor
+  /// `fromIterable`.
+  static void _fillMapWithMappedIterable(
+      Map map, Iterable iterable, key(element), value(element)) {
+    key ??= _id;
+    value ??= _id;
+
+    for (var element in iterable) {
+      map[key(element)] = value(element);
+    }
+  }
+
+  /// Fills a map by associating the [keys] to [values].
+  ///
+  /// This method is used by [Map] classes in the named constructor
+  /// `fromIterables`.
+  static void _fillMapWithIterables(Map map, Iterable keys, Iterable values) {
+    Iterator keyIterator = keys.iterator;
+    Iterator valueIterator = values.iterator;
+
+    bool hasNextKey = keyIterator.moveNext();
+    bool hasNextValue = valueIterator.moveNext();
+
+    while (hasNextKey && hasNextValue) {
+      map[keyIterator.current] = valueIterator.current;
+      hasNextKey = keyIterator.moveNext();
+      hasNextValue = valueIterator.moveNext();
+    }
+
+    if (hasNextKey || hasNextValue) {
+      throw ArgumentError("Iterables do not have same length.");
+    }
+  }
+}
+
+/// Mixin implementing a [Map].
+///
+/// This mixin has a basic implementation of all but five of the members of
+/// [Map].
+/// A basic `Map` class can be implemented by mixin in this class and
+/// implementing `keys`, `operator[]`, `operator[]=`, `remove` and `clear`.
+/// The remaining operations are implemented in terms of these five.
+///
+/// The `keys` iterable should have efficient [Iterable.length] and
+/// [Iterable.contains] operations, and it should catch concurrent modifications
+/// of the keys while iterating.
+///
+/// A more efficient implementation is usually possible by overriding
+/// some of the other members as well.
+abstract class MapMixin<K, V> implements Map<K, V> {
+  Iterable<K> get keys;
+  V operator [](Object key);
+  operator []=(K key, V value);
+  V remove(Object key);
+  // The `clear` operation should not be based on `remove`.
+  // It should clear the map even if some keys are not equal to themselves.
+  void clear();
+
+  Map<RK, RV> cast<RK, RV>() => Map.castFrom<K, V, RK, RV>(this);
+  void forEach(void action(K key, V value)) {
+    for (K key in keys) {
+      action(key, this[key]);
+    }
+  }
+
+  void addAll(Map<K, V> other) {
+    for (K key in other.keys) {
+      this[key] = other[key];
+    }
+  }
+
+  bool containsValue(Object value) {
+    for (K key in keys) {
+      if (this[key] == value) return true;
+    }
+    return false;
+  }
+
+  V putIfAbsent(K key, V ifAbsent()) {
+    if (containsKey(key)) {
+      return this[key];
+    }
+    return this[key] = ifAbsent();
+  }
+
+  V update(K key, V update(V value), {V ifAbsent()}) {
+    if (this.containsKey(key)) {
+      return this[key] = update(this[key]);
+    }
+    if (ifAbsent != null) {
+      return this[key] = ifAbsent();
+    }
+    throw ArgumentError.value(key, "key", "Key not in map.");
+  }
+
+  void updateAll(V update(K key, V value)) {
+    for (var key in this.keys) {
+      this[key] = update(key, this[key]);
+    }
+  }
+
+  Iterable<MapEntry<K, V>> get entries {
+    return keys.map((K key) => MapEntry<K, V>(key, this[key]));
+  }
+
+  Map<K2, V2> map<K2, V2>(MapEntry<K2, V2> transform(K key, V value)) {
+    var result = <K2, V2>{};
+    for (var key in this.keys) {
+      var entry = transform(key, this[key]);
+      result[entry.key] = entry.value;
+    }
+    return result;
+  }
+
+  void addEntries(Iterable<MapEntry<K, V>> newEntries) {
+    for (var entry in newEntries) {
+      this[entry.key] = entry.value;
+    }
+  }
+
+  void removeWhere(bool test(K key, V value)) {
+    var keysToRemove = <K>[];
+    for (var key in keys) {
+      if (test(key, this[key])) keysToRemove.add(key);
+    }
+    for (var key in keysToRemove) {
+      this.remove(key);
+    }
+  }
+
+  bool containsKey(Object key) => keys.contains(key);
+  int get length => keys.length;
+  bool get isEmpty => keys.isEmpty;
+  bool get isNotEmpty => keys.isNotEmpty;
+  Iterable<V> get values => _MapBaseValueIterable<K, V>(this);
+  String toString() => MapBase.mapToString(this);
+}
+
+/// Basic implementation of an unmodifiable [Map].
+///
+/// This class has a basic implementation of all but two of the members of
+/// an umodifiable [Map].
+/// A simple unmodifiable `Map` class can be implemented by extending this
+/// class and implementing `keys` and `operator[]`.
+///
+/// Modifying operations throw when used.
+/// The remaining non-modifying operations are implemented in terms of `keys`
+/// and `operator[]`.
+///
+/// The `keys` iterable should have efficient [Iterable.length] and
+/// [Iterable.contains] operations, and it should catch concurrent modifications
+/// of the keys while iterating.
+///
+/// A more efficient implementation is usually possible by overriding
+/// some of the other members as well.
+abstract class UnmodifiableMapBase<K, V> = MapBase<K, V>
+    with _UnmodifiableMapMixin<K, V>;
+
+/// Implementation of [Map.values] based on the map and its [Map.keys] iterable.
+///
+/// Iterable that iterates over the values of a `Map`.
+/// It accesses the values by iterating over the keys of the map, and using the
+/// map's `operator[]` to lookup the keys.
+class _MapBaseValueIterable<K, V> extends EfficientLengthIterable<V> {
+  final Map<K, V> _map;
+  _MapBaseValueIterable(this._map);
+
+  int get length => _map.length;
+  bool get isEmpty => _map.isEmpty;
+  bool get isNotEmpty => _map.isNotEmpty;
+  V get first => _map[_map.keys.first];
+  V get single => _map[_map.keys.single];
+  V get last => _map[_map.keys.last];
+
+  Iterator<V> get iterator => _MapBaseValueIterator<K, V>(_map);
+}
+
+/// Iterator created by [_MapBaseValueIterable].
+///
+/// Iterates over the values of a map by iterating its keys and lookup up the
+/// values.
+class _MapBaseValueIterator<K, V> implements Iterator<V> {
+  final Iterator<K> _keys;
+  final Map<K, V> _map;
+  V _current;
+
+  _MapBaseValueIterator(Map<K, V> map)
+      : _map = map,
+        _keys = map.keys.iterator;
+
+  bool moveNext() {
+    if (_keys.moveNext()) {
+      _current = _map[_keys.current];
+      return true;
+    }
+    _current = null;
+    return false;
+  }
+
+  V get current => _current;
+}
+
+/// Mixin that overrides mutating map operations with implementations that
+/// throw.
+abstract class _UnmodifiableMapMixin<K, V> implements Map<K, V> {
+  /// This operation is not supported by an unmodifiable map.
+  void operator []=(K key, V value) {
+    throw UnsupportedError("Cannot modify unmodifiable map");
+  }
+
+  /// This operation is not supported by an unmodifiable map.
+  void addAll(Map<K, V> other) {
+    throw UnsupportedError("Cannot modify unmodifiable map");
+  }
+
+  /// This operation is not supported by an unmodifiable map.
+  void addEntries(Iterable<MapEntry<K, V>> entries) {
+    throw UnsupportedError("Cannot modify unmodifiable map");
+  }
+
+  /// This operation is not supported by an unmodifiable map.
+  void clear() {
+    throw UnsupportedError("Cannot modify unmodifiable map");
+  }
+
+  /// This operation is not supported by an unmodifiable map.
+  V remove(Object key) {
+    throw UnsupportedError("Cannot modify unmodifiable map");
+  }
+
+  /// This operation is not supported by an unmodifiable map.
+  void removeWhere(bool test(K key, V value)) {
+    throw UnsupportedError("Cannot modify unmodifiable map");
+  }
+
+  /// This operation is not supported by an unmodifiable map.
+  V putIfAbsent(K key, V ifAbsent()) {
+    throw UnsupportedError("Cannot modify unmodifiable map");
+  }
+
+  /// This operation is not supported by an unmodifiable map.
+  V update(K key, V update(V value), {V ifAbsent()}) {
+    throw UnsupportedError("Cannot modify unmodifiable map");
+  }
+
+  /// This operation is not supported by an unmodifiable map.
+  void updateAll(V update(K key, V value)) {
+    throw UnsupportedError("Cannot modify unmodifiable map");
+  }
+}
+
+/// Wrapper around a class that implements [Map] that only exposes `Map`
+/// members.
+///
+/// A simple wrapper that delegates all `Map` members to the map provided in the
+/// constructor.
+///
+/// Base for delegating map implementations like [UnmodifiableMapView].
+class MapView<K, V> implements Map<K, V> {
+  final Map<K, V> _map;
+  const MapView(Map<K, V> map) : _map = map;
+
+  Map<RK, RV> cast<RK, RV>() => _map.cast<RK, RV>();
+  V operator [](Object key) => _map[key];
+  void operator []=(K key, V value) {
+    _map[key] = value;
+  }
+
+  void addAll(Map<K, V> other) {
+    _map.addAll(other);
+  }
+
+  void clear() {
+    _map.clear();
+  }
+
+  V putIfAbsent(K key, V ifAbsent()) => _map.putIfAbsent(key, ifAbsent);
+  bool containsKey(Object key) => _map.containsKey(key);
+  bool containsValue(Object value) => _map.containsValue(value);
+  void forEach(void action(K key, V value)) {
+    _map.forEach(action);
+  }
+
+  bool get isEmpty => _map.isEmpty;
+  bool get isNotEmpty => _map.isNotEmpty;
+  int get length => _map.length;
+  Iterable<K> get keys => _map.keys;
+  V remove(Object key) => _map.remove(key);
+  String toString() => _map.toString();
+  Iterable<V> get values => _map.values;
+
+  Iterable<MapEntry<K, V>> get entries => _map.entries;
+
+  void addEntries(Iterable<MapEntry<K, V>> entries) {
+    _map.addEntries(entries);
+  }
+
+  Map<K2, V2> map<K2, V2>(MapEntry<K2, V2> transform(K key, V value)) =>
+      _map.map<K2, V2>(transform);
+
+  V update(K key, V update(V value), {V ifAbsent()}) =>
+      _map.update(key, update, ifAbsent: ifAbsent);
+
+  void updateAll(V update(K key, V value)) {
+    _map.updateAll(update);
+  }
+
+  void removeWhere(bool test(K key, V value)) {
+    _map.removeWhere(test);
+  }
+}
+
+/// View of a [Map] that disallow modifying the map.
+///
+/// A wrapper around a `Map` that forwards all members to the map provided in
+/// the constructor, except for operations that modify the map.
+/// Modifying operations throw instead.
+class UnmodifiableMapView<K, V> extends MapView<K, V>
+    with _UnmodifiableMapMixin<K, V> {
+  UnmodifiableMapView(Map<K, V> map) : super(map);
+
+  Map<RK, RV> cast<RK, RV>() =>
+      UnmodifiableMapView<RK, RV>(_map.cast<RK, RV>());
+}
diff --git a/sdk_nnbd/lib/collection/queue.dart b/sdk_nnbd/lib/collection/queue.dart
new file mode 100644
index 0000000..62994b9
--- /dev/null
+++ b/sdk_nnbd/lib/collection/queue.dart
@@ -0,0 +1,887 @@
+// Copyright (c) 2011, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.collection;
+
+/// A [Queue] is a collection that can be manipulated at both ends. One
+/// can iterate over the elements of a queue through [forEach] or with
+/// an [Iterator].
+///
+/// It is generally not allowed to modify the queue (add or remove entries)
+/// while an operation on the queue is being performed, for example during a
+/// call to [forEach].
+/// Modifying the queue while it is being iterated will most likely break the
+/// iteration.
+/// This goes both for using the [iterator] directly, or for iterating an
+/// `Iterable` returned by a method like [map] or [where].
+abstract class Queue<E> implements EfficientLengthIterable<E> {
+  /// Creates a queue.
+  factory Queue() = ListQueue<E>;
+
+  /// Creates a queue containing all [elements].
+  ///
+  /// The element order in the queue is as if the elements were added using
+  /// [addLast] in the order provided by [elements.iterator].
+  ///
+  /// All the [elements] should be instances of [E].
+  /// The `elements` iterable itself may have any element type, so this
+  /// constructor can be used to down-cast a `Queue`, for example as:
+  /// ```dart
+  /// Queue<SuperType> superQueue = ...;
+  /// Queue<SubType> subQueue =
+  ///     new Queue<SubType>.from(superSet.whereType<SubType>());
+  /// ```
+  factory Queue.from(Iterable elements) = ListQueue<E>.from;
+
+  /// Creates a queue from [elements].
+  ///
+  /// The element order in the queue is as if the elements were added using
+  /// [addLast] in the order provided by [elements.iterator].
+  factory Queue.of(Iterable<E> elements) = ListQueue<E>.of;
+
+  /// Adapts [source] to be a `Queue<T>`.
+  ///
+  /// Any time the queue would produce an element that is not a [T],
+  /// the element access will throw.
+  ///
+  /// Any time a [T] value is attempted stored into the adapted queue,
+  /// the store will throw unless the value is also an instance of [S].
+  ///
+  /// If all accessed elements of [source] are actually instances of [T],
+  /// and if all elements stored into the returned queue are actually instance
+  /// of [S],
+  /// then the returned queue can be used as a `Queue<T>`.
+  static Queue<T> castFrom<S, T>(Queue<S> source) => CastQueue<S, T>(source);
+
+  /// Provides a view of this queue as a queue of [R] instances, if necessary.
+  ///
+  /// If this queue contains only instances of [R], all read operations
+  /// will work correctly. If any operation tries to access an element
+  /// that is not an instance of [R], the access will throw instead.
+  ///
+  /// Elements added to the queue (e.g., by using [addFirst] or [addAll])
+  /// must be instance of [R] to be valid arguments to the adding function,
+  /// and they must be instances of [E] as well to be accepted by
+  /// this queue as well.
+  Queue<R> cast<R>();
+
+  /// Removes and returns the first element of this queue.
+  ///
+  /// The queue must not be empty when this method is called.
+  E removeFirst();
+
+  /// Removes and returns the last element of the queue.
+  ///
+  /// The queue must not be empty when this method is called.
+  E removeLast();
+
+  /// Adds [value] at the beginning of the queue.
+  void addFirst(E value);
+
+  /// Adds [value] at the end of the queue.
+  void addLast(E value);
+
+  /// Adds [value] at the end of the queue.
+  void add(E value);
+
+  /// Remove a single instance of [value] from the queue.
+  ///
+  /// Returns `true` if a value was removed, or `false` if the queue
+  /// contained no element equal to [value].
+  bool remove(Object value);
+
+  /// Adds all elements of [iterable] at the end of the queue. The
+  /// length of the queue is extended by the length of [iterable].
+  void addAll(Iterable<E> iterable);
+
+  /// Removes all elements matched by [test] from the queue.
+  ///
+  /// The `test` function must not throw or modify the queue.
+  void removeWhere(bool test(E element));
+
+  /// Removes all elements not matched by [test] from the queue.
+  ///
+  /// The `test` function must not throw or modify the queue.
+  void retainWhere(bool test(E element));
+
+  /// Removes all elements in the queue. The size of the queue becomes zero.
+  void clear();
+}
+
+class _DoubleLink<Link extends _DoubleLink<Link>> {
+  Link _previousLink;
+  Link _nextLink;
+
+  void _link(Link previous, Link next) {
+    _nextLink = next;
+    _previousLink = previous;
+    if (previous != null) previous._nextLink = this;
+    if (next != null) next._previousLink = this;
+  }
+
+  void _unlink() {
+    if (_previousLink != null) _previousLink._nextLink = _nextLink;
+    if (_nextLink != null) _nextLink._previousLink = _previousLink;
+    _nextLink = null;
+    _previousLink = null;
+  }
+}
+
+/// An entry in a doubly linked list. It contains a pointer to the next
+/// entry, the previous entry, and the boxed element.
+class DoubleLinkedQueueEntry<E> extends _DoubleLink<DoubleLinkedQueueEntry<E>> {
+  /// The element in the queue.
+  E element;
+
+  DoubleLinkedQueueEntry(this.element);
+
+  /// Appends the given [e] as entry just after this entry.
+  void append(E e) {
+    DoubleLinkedQueueEntry<E>(e)._link(this, _nextLink);
+  }
+
+  /// Prepends the given [e] as entry just before this entry.
+  void prepend(E e) {
+    DoubleLinkedQueueEntry<E>(e)._link(_previousLink, this);
+  }
+
+  E remove() {
+    _unlink();
+    return element;
+  }
+
+  /// Returns the previous entry or `null` if there is none.
+  DoubleLinkedQueueEntry<E> previousEntry() => _previousLink;
+
+  /// Returns the next entry or `null` if there is none.
+  DoubleLinkedQueueEntry<E> nextEntry() => _nextLink;
+}
+
+/// Interface for the link classes used by [DoubleLinkedQueue].
+///
+/// Both the [_DoubleLinkedQueueElement] and [_DoubleLinkedQueueSentinel]
+/// implement this interface.
+/// The entry contains a link back to the queue, so calling `append`
+/// or `prepend` can correctly update the element count.
+abstract class _DoubleLinkedQueueEntry<E> extends DoubleLinkedQueueEntry<E> {
+  DoubleLinkedQueue<E> _queue;
+  _DoubleLinkedQueueEntry(E element, this._queue) : super(element);
+
+  DoubleLinkedQueueEntry<E> _asNonSentinelEntry();
+
+  void _append(E e) {
+    _DoubleLinkedQueueElement<E>(e, _queue)._link(this, _nextLink);
+  }
+
+  void _prepend(E e) {
+    _DoubleLinkedQueueElement<E>(e, _queue)._link(_previousLink, this);
+  }
+
+  E _remove();
+
+  E get _element => element;
+
+  DoubleLinkedQueueEntry<E> nextEntry() {
+    _DoubleLinkedQueueEntry<E> entry = _nextLink;
+    return entry._asNonSentinelEntry();
+  }
+
+  DoubleLinkedQueueEntry<E> previousEntry() {
+    _DoubleLinkedQueueEntry<E> entry = _previousLink;
+    return entry._asNonSentinelEntry();
+  }
+}
+
+/// The actual entry type used by the [DoubleLinkedQueue].
+///
+/// The entry contains a reference to the queue, allowing
+/// [append]/[prepend] to update the list length.
+class _DoubleLinkedQueueElement<E> extends _DoubleLinkedQueueEntry<E> {
+  _DoubleLinkedQueueElement(E element, DoubleLinkedQueue<E> queue)
+      : super(element, queue);
+
+  void append(E e) {
+    _append(e);
+    if (_queue != null) _queue._elementCount++;
+  }
+
+  void prepend(E e) {
+    _prepend(e);
+    if (_queue != null) _queue._elementCount++;
+  }
+
+  E _remove() {
+    _queue = null;
+    _unlink();
+    return element;
+  }
+
+  E remove() {
+    if (_queue != null) _queue._elementCount--;
+    return _remove();
+  }
+
+  _DoubleLinkedQueueElement<E> _asNonSentinelEntry() {
+    return this;
+  }
+}
+
+/// A sentinel in a double linked list is used to manipulate the list
+/// at both ends.
+/// A double linked list has exactly one sentinel,
+/// which is the only entry when the list is constructed.
+/// Initially, a sentinel has its next and previous entry point to itself.
+/// A sentinel does not box any user element.
+class _DoubleLinkedQueueSentinel<E> extends _DoubleLinkedQueueEntry<E> {
+  _DoubleLinkedQueueSentinel(DoubleLinkedQueue<E> queue) : super(null, queue) {
+    _previousLink = this;
+    _nextLink = this;
+  }
+
+  DoubleLinkedQueueEntry<E> _asNonSentinelEntry() {
+    return null;
+  }
+
+  /// Hit by, e.g., [DoubleLinkedQueue.removeFirst] if the queue is empty.
+  E _remove() {
+    throw IterableElementError.noElement();
+  }
+
+  /// Hit by, e.g., [DoubleLinkedQueue.first] if the queue is empty.
+  E get _element {
+    throw IterableElementError.noElement();
+  }
+}
+
+/// A [Queue] implementation based on a double-linked list.
+///
+/// Allows constant time add, remove-at-ends and peek operations.
+class DoubleLinkedQueue<E> extends Iterable<E> implements Queue<E> {
+  _DoubleLinkedQueueSentinel<E> _sentinel;
+  int _elementCount = 0;
+
+  DoubleLinkedQueue() {
+    _sentinel = _DoubleLinkedQueueSentinel<E>(this);
+  }
+
+  /// Creates a double-linked queue containing all [elements].
+  ///
+  /// The element order in the queue is as if the elements were added using
+  /// [addLast] in the order provided by [elements.iterator].
+  ///
+  /// All the [elements] should be instances of [E].
+  /// The `elements` iterable itself may have any element type, so this
+  /// constructor can be used to down-cast a `Queue`, for example as:
+  /// ```dart
+  /// Queue<SuperType> superQueue = ...;
+  /// Queue<SubType> subQueue =
+  ///     new DoubleLinkedQueue<SubType>.from(superQueue.whereType<SubType>());
+  /// ```
+  factory DoubleLinkedQueue.from(Iterable elements) {
+    Queue<E> list = DoubleLinkedQueue<E>();
+    for (final e in elements) {
+      list.addLast(e);
+    }
+    return list;
+  }
+
+  /// Creates a double-linked queue from [elements].
+  ///
+  /// The element order in the queue is as if the elements were added using
+  /// [addLast] in the order provided by [elements.iterator].
+  factory DoubleLinkedQueue.of(Iterable<E> elements) =>
+      DoubleLinkedQueue<E>()..addAll(elements);
+
+  Queue<R> cast<R>() => Queue.castFrom<E, R>(this);
+  int get length => _elementCount;
+
+  void addLast(E value) {
+    _sentinel._prepend(value);
+    _elementCount++;
+  }
+
+  void addFirst(E value) {
+    _sentinel._append(value);
+    _elementCount++;
+  }
+
+  void add(E value) {
+    _sentinel._prepend(value);
+    _elementCount++;
+  }
+
+  void addAll(Iterable<E> iterable) {
+    for (final E value in iterable) {
+      _sentinel._prepend(value);
+      _elementCount++;
+    }
+  }
+
+  E removeLast() {
+    _DoubleLinkedQueueEntry<E> lastEntry = _sentinel._previousLink;
+    E result = lastEntry._remove();
+    _elementCount--;
+    return result;
+  }
+
+  E removeFirst() {
+    _DoubleLinkedQueueEntry<E> firstEntry = _sentinel._nextLink;
+    E result = firstEntry._remove();
+    _elementCount--;
+    return result;
+  }
+
+  bool remove(Object o) {
+    _DoubleLinkedQueueEntry<E> entry = _sentinel._nextLink;
+    while (!identical(entry, _sentinel)) {
+      bool equals = (entry._element == o);
+      if (!identical(this, entry._queue)) {
+        // Entry must still be in the queue.
+        throw ConcurrentModificationError(this);
+      }
+      if (equals) {
+        entry._remove();
+        _elementCount--;
+        return true;
+      }
+      entry = entry._nextLink;
+    }
+    return false;
+  }
+
+  void _filter(bool test(E element), bool removeMatching) {
+    _DoubleLinkedQueueEntry<E> entry = _sentinel._nextLink;
+    while (!identical(entry, _sentinel)) {
+      bool matches = test(entry._element);
+      if (!identical(this, entry._queue)) {
+        // Entry must still be in the queue.
+        throw ConcurrentModificationError(this);
+      }
+      _DoubleLinkedQueueEntry<E> next = entry._nextLink; // Cannot be null.
+      if (identical(removeMatching, matches)) {
+        entry._remove();
+        _elementCount--;
+      }
+      entry = next;
+    }
+  }
+
+  void removeWhere(bool test(E element)) {
+    _filter(test, true);
+  }
+
+  void retainWhere(bool test(E element)) {
+    _filter(test, false);
+  }
+
+  E get first {
+    _DoubleLinkedQueueEntry<E> firstEntry = _sentinel._nextLink;
+    return firstEntry._element;
+  }
+
+  E get last {
+    _DoubleLinkedQueueEntry<E> lastEntry = _sentinel._previousLink;
+    return lastEntry._element;
+  }
+
+  E get single {
+    // Note that this throws correctly if the queue is empty
+    // because reading the element of the sentinel throws.
+    if (identical(_sentinel._nextLink, _sentinel._previousLink)) {
+      _DoubleLinkedQueueEntry<E> entry = _sentinel._nextLink;
+      return entry._element;
+    }
+    throw IterableElementError.tooMany();
+  }
+
+  /// The entry object of the first element in the queue.
+  ///
+  /// Each element of the queue has an associated [DoubleLinkedQueueEntry].
+  /// Returns the entry object corresponding to the first element of the queue.
+  ///
+  /// The entry objects can also be accessed using [lastEntry],
+  /// and they can be iterated using [DoubleLinkedQueueEntry.nextEntry()] and
+  /// [DoubleLinkedQueueEntry.previousEntry()].
+  DoubleLinkedQueueEntry<E> firstEntry() {
+    return _sentinel.nextEntry();
+  }
+
+  /// The entry object of the last element in the queue.
+  ///
+  /// Each element of the queue has an associated [DoubleLinkedQueueEntry].
+  /// Returns the entry object corresponding to the last element of the queue.
+  ///
+  /// The entry objects can also be accessed using [firstEntry],
+  /// and they can be iterated using [DoubleLinkedQueueEntry.nextEntry()] and
+  /// [DoubleLinkedQueueEntry.previousEntry()].
+  DoubleLinkedQueueEntry<E> lastEntry() {
+    return _sentinel.previousEntry();
+  }
+
+  bool get isEmpty {
+    return (identical(_sentinel._nextLink, _sentinel));
+  }
+
+  void clear() {
+    _sentinel._nextLink = _sentinel;
+    _sentinel._previousLink = _sentinel;
+    _elementCount = 0;
+  }
+
+  /// Calls [action] for each entry object of this double-linked queue.
+  ///
+  /// Each element of the queue has an associated [DoubleLinkedQueueEntry].
+  /// This method iterates the entry objects from first to last and calls
+  /// [action] with each object in turn.
+  ///
+  /// The entry objects can also be accessed using [firstEntry] and [lastEntry],
+  /// and iterated using [DoubleLinkedQueueEntry.nextEntry()] and
+  /// [DoubleLinkedQueueEntry.previousEntry()].
+  ///
+  /// The [action] function can use methods on [DoubleLinkedQueueEntry] to
+  /// remove the entry or it can insert elements before or after then entry.
+  /// If the current entry is removed, iteration continues with the entry that
+  /// was following the current entry when [action] was called. Any elements
+  /// inserted after the current element before it is removed will not be
+  /// visited by the iteration.
+  void forEachEntry(void action(DoubleLinkedQueueEntry<E> element)) {
+    _DoubleLinkedQueueEntry<E> entry = _sentinel._nextLink;
+    while (!identical(entry, _sentinel)) {
+      _DoubleLinkedQueueElement<E> element = entry;
+      _DoubleLinkedQueueEntry<E> next = element._nextLink;
+      // Remember both entry and entry._nextLink.
+      // If someone calls `element.remove()` we continue from `next`.
+      // Otherwise we use the value of entry._nextLink which may have been
+      // updated.
+      action(element);
+      if (identical(this, entry._queue)) {
+        next = entry._nextLink;
+      } else if (!identical(this, next._queue)) {
+        throw ConcurrentModificationError(this);
+      }
+      entry = next;
+    }
+  }
+
+  _DoubleLinkedQueueIterator<E> get iterator {
+    return _DoubleLinkedQueueIterator<E>(_sentinel);
+  }
+
+  String toString() => IterableBase.iterableToFullString(this, '{', '}');
+}
+
+class _DoubleLinkedQueueIterator<E> implements Iterator<E> {
+  _DoubleLinkedQueueSentinel<E> _sentinel;
+  _DoubleLinkedQueueEntry<E> _nextEntry;
+  E _current;
+
+  _DoubleLinkedQueueIterator(_DoubleLinkedQueueSentinel<E> sentinel)
+      : _sentinel = sentinel,
+        _nextEntry = sentinel._nextLink;
+
+  bool moveNext() {
+    if (identical(_nextEntry, _sentinel)) {
+      _current = null;
+      _nextEntry = null;
+      _sentinel = null;
+      return false;
+    }
+    _DoubleLinkedQueueElement<E> elementEntry = _nextEntry;
+    if (!identical(_sentinel._queue, elementEntry._queue)) {
+      throw ConcurrentModificationError(_sentinel._queue);
+    }
+    _current = elementEntry._element;
+    _nextEntry = elementEntry._nextLink;
+    return true;
+  }
+
+  E get current => _current;
+}
+
+/// List based [Queue].
+///
+/// Keeps a cyclic buffer of elements, and grows to a larger buffer when
+/// it fills up. This guarantees constant time peek and remove operations, and
+/// amortized constant time add operations.
+///
+/// The structure is efficient for any queue or stack usage.
+class ListQueue<E> extends ListIterable<E> implements Queue<E> {
+  static const int _INITIAL_CAPACITY = 8;
+  List<E> _table;
+  int _head;
+  int _tail;
+  int _modificationCount = 0;
+
+  /// Create an empty queue.
+  ///
+  /// If [initialCapacity] is given, prepare the queue for at least that many
+  /// elements.
+  ListQueue([int initialCapacity])
+      : _head = 0,
+        _tail = 0 {
+    if (initialCapacity == null || initialCapacity < _INITIAL_CAPACITY) {
+      initialCapacity = _INITIAL_CAPACITY;
+    } else if (!_isPowerOf2(initialCapacity)) {
+      initialCapacity = _nextPowerOf2(initialCapacity);
+    }
+    assert(_isPowerOf2(initialCapacity));
+    _table = List<E>(initialCapacity);
+  }
+
+  /// Create a `ListQueue` containing all [elements].
+  ///
+  /// The elements are added to the queue, as by [addLast], in the order given
+  /// by `elements.iterator`.
+  ///
+  /// All the [elements] should be instances of [E].
+  /// The `elements` iterable itself may have any element type, so this
+  /// constructor can be used to down-cast a `Queue`, for example as:
+  /// ```dart
+  /// Queue<SuperType> superQueue = ...;
+  /// Queue<SubType> subQueue =
+  ///     new ListQueue<SubType>.from(superQueue.whereType<SubType>());
+  /// ```
+  factory ListQueue.from(Iterable elements) {
+    if (elements is List) {
+      int length = elements.length;
+      ListQueue<E> queue = ListQueue<E>(length + 1);
+      assert(queue._table.length > length);
+      for (int i = 0; i < length; i++) {
+        queue._table[i] = elements[i];
+      }
+      queue._tail = length;
+      return queue;
+    } else {
+      int capacity = _INITIAL_CAPACITY;
+      if (elements is EfficientLengthIterable) {
+        capacity = elements.length;
+      }
+      ListQueue<E> result = ListQueue<E>(capacity);
+      for (final element in elements) {
+        result.addLast(element);
+      }
+      return result;
+    }
+  }
+
+  /// Create a `ListQueue` from [elements].
+  ///
+  /// The elements are added to the queue, as by [addLast], in the order given
+  /// by `elements.iterator`.
+  factory ListQueue.of(Iterable<E> elements) =>
+      ListQueue<E>()..addAll(elements);
+
+  // Iterable interface.
+
+  Queue<R> cast<R>() => Queue.castFrom<E, R>(this);
+  Iterator<E> get iterator => _ListQueueIterator<E>(this);
+
+  void forEach(void f(E element)) {
+    int modificationCount = _modificationCount;
+    for (int i = _head; i != _tail; i = (i + 1) & (_table.length - 1)) {
+      f(_table[i]);
+      _checkModification(modificationCount);
+    }
+  }
+
+  bool get isEmpty => _head == _tail;
+
+  int get length => (_tail - _head) & (_table.length - 1);
+
+  E get first {
+    if (_head == _tail) throw IterableElementError.noElement();
+    return _table[_head];
+  }
+
+  E get last {
+    if (_head == _tail) throw IterableElementError.noElement();
+    return _table[(_tail - 1) & (_table.length - 1)];
+  }
+
+  E get single {
+    if (_head == _tail) throw IterableElementError.noElement();
+    if (length > 1) throw IterableElementError.tooMany();
+    return _table[_head];
+  }
+
+  E elementAt(int index) {
+    RangeError.checkValidIndex(index, this);
+    return _table[(_head + index) & (_table.length - 1)];
+  }
+
+  List<E> toList({bool growable = true}) {
+    List<E> list;
+    if (growable) {
+      list = <E>[]..length = length;
+    } else {
+      list = List<E>(length);
+    }
+    _writeToList(list);
+    return list;
+  }
+
+  // Collection interface.
+
+  void add(E value) {
+    _add(value);
+  }
+
+  void addAll(Iterable<E> elements) {
+    if (elements is List<E>) {
+      List<E> list = elements;
+      int addCount = list.length;
+      int length = this.length;
+      if (length + addCount >= _table.length) {
+        _preGrow(length + addCount);
+        // After preGrow, all elements are at the start of the list.
+        _table.setRange(length, length + addCount, list, 0);
+        _tail += addCount;
+      } else {
+        // Adding addCount elements won't reach _head.
+        int endSpace = _table.length - _tail;
+        if (addCount < endSpace) {
+          _table.setRange(_tail, _tail + addCount, list, 0);
+          _tail += addCount;
+        } else {
+          int preSpace = addCount - endSpace;
+          _table.setRange(_tail, _tail + endSpace, list, 0);
+          _table.setRange(0, preSpace, list, endSpace);
+          _tail = preSpace;
+        }
+      }
+      _modificationCount++;
+    } else {
+      for (E element in elements) _add(element);
+    }
+  }
+
+  bool remove(Object value) {
+    for (int i = _head; i != _tail; i = (i + 1) & (_table.length - 1)) {
+      E element = _table[i];
+      if (element == value) {
+        _remove(i);
+        _modificationCount++;
+        return true;
+      }
+    }
+    return false;
+  }
+
+  void _filterWhere(bool test(E element), bool removeMatching) {
+    int modificationCount = _modificationCount;
+    int i = _head;
+    while (i != _tail) {
+      E element = _table[i];
+      bool remove = identical(removeMatching, test(element));
+      _checkModification(modificationCount);
+      if (remove) {
+        i = _remove(i);
+        modificationCount = ++_modificationCount;
+      } else {
+        i = (i + 1) & (_table.length - 1);
+      }
+    }
+  }
+
+  /// Remove all elements matched by [test].
+  ///
+  /// This method is inefficient since it works by repeatedly removing single
+  /// elements, each of which can take linear time.
+  void removeWhere(bool test(E element)) {
+    _filterWhere(test, true);
+  }
+
+  /// Remove all elements not matched by [test].
+  ///
+  /// This method is inefficient since it works by repeatedly removing single
+  /// elements, each of which can take linear time.
+  void retainWhere(bool test(E element)) {
+    _filterWhere(test, false);
+  }
+
+  void clear() {
+    if (_head != _tail) {
+      for (int i = _head; i != _tail; i = (i + 1) & (_table.length - 1)) {
+        _table[i] = null;
+      }
+      _head = _tail = 0;
+      _modificationCount++;
+    }
+  }
+
+  String toString() => IterableBase.iterableToFullString(this, "{", "}");
+
+  // Queue interface.
+
+  void addLast(E value) {
+    _add(value);
+  }
+
+  void addFirst(E value) {
+    _head = (_head - 1) & (_table.length - 1);
+    _table[_head] = value;
+    if (_head == _tail) _grow();
+    _modificationCount++;
+  }
+
+  E removeFirst() {
+    if (_head == _tail) throw IterableElementError.noElement();
+    _modificationCount++;
+    E result = _table[_head];
+    _table[_head] = null;
+    _head = (_head + 1) & (_table.length - 1);
+    return result;
+  }
+
+  E removeLast() {
+    if (_head == _tail) throw IterableElementError.noElement();
+    _modificationCount++;
+    _tail = (_tail - 1) & (_table.length - 1);
+    E result = _table[_tail];
+    _table[_tail] = null;
+    return result;
+  }
+
+  // Internal helper functions.
+
+  /// Whether [number] is a power of two.
+  ///
+  /// Only works for positive numbers.
+  static bool _isPowerOf2(int number) => (number & (number - 1)) == 0;
+
+  /// Rounds [number] up to the nearest power of 2.
+  ///
+  /// If [number] is a power of 2 already, it is returned.
+  ///
+  /// Only works for positive numbers.
+  static int _nextPowerOf2(int number) {
+    assert(number > 0);
+    number = (number << 1) - 1;
+    for (;;) {
+      int nextNumber = number & (number - 1);
+      if (nextNumber == 0) return number;
+      number = nextNumber;
+    }
+  }
+
+  /// Check if the queue has been modified during iteration.
+  void _checkModification(int expectedModificationCount) {
+    if (expectedModificationCount != _modificationCount) {
+      throw ConcurrentModificationError(this);
+    }
+  }
+
+  /// Adds element at end of queue. Used by both [add] and [addAll].
+  void _add(E element) {
+    _table[_tail] = element;
+    _tail = (_tail + 1) & (_table.length - 1);
+    if (_head == _tail) _grow();
+    _modificationCount++;
+  }
+
+  /// Removes the element at [offset] into [_table].
+  ///
+  /// Removal is performed by linearly moving elements either before or after
+  /// [offset] by one position.
+  ///
+  /// Returns the new offset of the following element. This may be the same
+  /// offset or the following offset depending on how elements are moved
+  /// to fill the hole.
+  int _remove(int offset) {
+    int mask = _table.length - 1;
+    int startDistance = (offset - _head) & mask;
+    int endDistance = (_tail - offset) & mask;
+    if (startDistance < endDistance) {
+      // Closest to start.
+      int i = offset;
+      while (i != _head) {
+        int prevOffset = (i - 1) & mask;
+        _table[i] = _table[prevOffset];
+        i = prevOffset;
+      }
+      _table[_head] = null;
+      _head = (_head + 1) & mask;
+      return (offset + 1) & mask;
+    } else {
+      _tail = (_tail - 1) & mask;
+      int i = offset;
+      while (i != _tail) {
+        int nextOffset = (i + 1) & mask;
+        _table[i] = _table[nextOffset];
+        i = nextOffset;
+      }
+      _table[_tail] = null;
+      return offset;
+    }
+  }
+
+  /// Grow the table when full.
+  void _grow() {
+    List<E> newTable = List<E>(_table.length * 2);
+    int split = _table.length - _head;
+    newTable.setRange(0, split, _table, _head);
+    newTable.setRange(split, split + _head, _table, 0);
+    _head = 0;
+    _tail = _table.length;
+    _table = newTable;
+  }
+
+  int _writeToList(List<E> target) {
+    assert(target.length >= length);
+    if (_head <= _tail) {
+      int length = _tail - _head;
+      target.setRange(0, length, _table, _head);
+      return length;
+    } else {
+      int firstPartSize = _table.length - _head;
+      target.setRange(0, firstPartSize, _table, _head);
+      target.setRange(firstPartSize, firstPartSize + _tail, _table, 0);
+      return _tail + firstPartSize;
+    }
+  }
+
+  /// Grows the table even if it is not full.
+  void _preGrow(int newElementCount) {
+    assert(newElementCount >= length);
+
+    // Add some extra room to ensure that there's room for more elements after
+    // expansion.
+    newElementCount += newElementCount >> 1;
+    int newCapacity = _nextPowerOf2(newElementCount);
+    List<E> newTable = List<E>(newCapacity);
+    _tail = _writeToList(newTable);
+    _table = newTable;
+    _head = 0;
+  }
+}
+
+/// Iterator for a [ListQueue].
+///
+/// Considers any add or remove operation a concurrent modification.
+class _ListQueueIterator<E> implements Iterator<E> {
+  final ListQueue<E> _queue;
+  final int _end;
+  final int _modificationCount;
+  int _position;
+  E _current;
+
+  _ListQueueIterator(ListQueue<E> queue)
+      : _queue = queue,
+        _end = queue._tail,
+        _modificationCount = queue._modificationCount,
+        _position = queue._head;
+
+  E get current => _current;
+
+  bool moveNext() {
+    _queue._checkModification(_modificationCount);
+    if (_position == _end) {
+      _current = null;
+      return false;
+    }
+    _current = _queue._table[_position];
+    _position = (_position + 1) & (_queue._table.length - 1);
+    return true;
+  }
+}
diff --git a/sdk_nnbd/lib/collection/set.dart b/sdk_nnbd/lib/collection/set.dart
new file mode 100644
index 0000000..7508b23
--- /dev/null
+++ b/sdk_nnbd/lib/collection/set.dart
@@ -0,0 +1,630 @@
+// Copyright (c) 2014, 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.
+
+/// Base implementations of [Set].
+part of dart.collection;
+
+/// Mixin implementation of [Set].
+///
+/// This class provides a base implementation of a `Set` that depends only
+/// on the abstract members: [add], [contains], [lookup], [remove],
+/// [iterator], [length] and [toSet].
+///
+/// Some of the methods assume that `toSet` creates a modifiable set.
+/// If using this mixin for an unmodifiable set,
+/// where `toSet` should return an unmodifiable set,
+/// it's necessary to reimplement
+/// [retainAll], [union], [intersection] and [difference].
+///
+/// Implementations of `Set` using this mixin should consider also implementing
+/// `clear` in constant time. The default implementation works by removing every
+/// element.
+abstract class SetMixin<E> implements Set<E> {
+  // This class reimplements all of [IterableMixin].
+  // If/when Dart mixins get more powerful, we should just create a single
+  // Mixin class from IterableMixin and the new methods of this class.
+
+  bool add(E value);
+
+  bool contains(Object element);
+
+  E lookup(Object element);
+
+  bool remove(Object value);
+
+  Iterator<E> get iterator;
+
+  Set<E> toSet();
+
+  int get length;
+
+  bool get isEmpty => length == 0;
+
+  bool get isNotEmpty => length != 0;
+
+  Set<R> cast<R>() => Set.castFrom<E, R>(this);
+  Iterable<E> followedBy(Iterable<E> other) =>
+      FollowedByIterable<E>.firstEfficient(this, other);
+
+  Iterable<T> whereType<T>() => WhereTypeIterable<T>(this);
+
+  void clear() {
+    removeAll(toList());
+  }
+
+  void addAll(Iterable<E> elements) {
+    for (E element in elements) add(element);
+  }
+
+  void removeAll(Iterable<Object> elements) {
+    for (Object element in elements) remove(element);
+  }
+
+  void retainAll(Iterable<Object> elements) {
+    // Create a copy of the set, remove all of elements from the copy,
+    // then remove all remaining elements in copy from this.
+    Set<E> toRemove = toSet();
+    for (Object o in elements) {
+      toRemove.remove(o);
+    }
+    removeAll(toRemove);
+  }
+
+  void removeWhere(bool test(E element)) {
+    List toRemove = [];
+    for (E element in this) {
+      if (test(element)) toRemove.add(element);
+    }
+    removeAll(toRemove);
+  }
+
+  void retainWhere(bool test(E element)) {
+    List toRemove = [];
+    for (E element in this) {
+      if (!test(element)) toRemove.add(element);
+    }
+    removeAll(toRemove);
+  }
+
+  bool containsAll(Iterable<Object> other) {
+    for (Object o in other) {
+      if (!contains(o)) return false;
+    }
+    return true;
+  }
+
+  Set<E> union(Set<E> other) {
+    return toSet()..addAll(other);
+  }
+
+  Set<E> intersection(Set<Object> other) {
+    Set<E> result = toSet();
+    for (E element in this) {
+      if (!other.contains(element)) result.remove(element);
+    }
+    return result;
+  }
+
+  Set<E> difference(Set<Object> other) {
+    Set<E> result = toSet();
+    for (E element in this) {
+      if (other.contains(element)) result.remove(element);
+    }
+    return result;
+  }
+
+  List<E> toList({bool growable = true}) {
+    List<E> result = growable ? (<E>[]..length = length) : List<E>(length);
+    int i = 0;
+    for (E element in this) result[i++] = element;
+    return result;
+  }
+
+  Iterable<T> map<T>(T f(E element)) =>
+      EfficientLengthMappedIterable<E, T>(this, f);
+
+  E get single {
+    if (length > 1) throw IterableElementError.tooMany();
+    Iterator<E> it = iterator;
+    if (!it.moveNext()) throw IterableElementError.noElement();
+    E result = it.current;
+    return result;
+  }
+
+  String toString() => IterableBase.iterableToFullString(this, '{', '}');
+
+  // Copied from IterableMixin.
+  // Should be inherited if we had multi-level mixins.
+
+  Iterable<E> where(bool f(E element)) => WhereIterable<E>(this, f);
+
+  Iterable<T> expand<T>(Iterable<T> f(E element)) =>
+      ExpandIterable<E, T>(this, f);
+
+  void forEach(void f(E element)) {
+    for (E element in this) f(element);
+  }
+
+  E reduce(E combine(E value, E element)) {
+    Iterator<E> iterator = this.iterator;
+    if (!iterator.moveNext()) {
+      throw IterableElementError.noElement();
+    }
+    E value = iterator.current;
+    while (iterator.moveNext()) {
+      value = combine(value, iterator.current);
+    }
+    return value;
+  }
+
+  T fold<T>(T initialValue, T combine(T previousValue, E element)) {
+    var value = initialValue;
+    for (E element in this) value = combine(value, element);
+    return value;
+  }
+
+  bool every(bool f(E element)) {
+    for (E element in this) {
+      if (!f(element)) return false;
+    }
+    return true;
+  }
+
+  String join([String separator = ""]) {
+    Iterator<E> iterator = this.iterator;
+    if (!iterator.moveNext()) return "";
+    StringBuffer buffer = StringBuffer();
+    if (separator == null || separator == "") {
+      do {
+        buffer.write(iterator.current);
+      } while (iterator.moveNext());
+    } else {
+      buffer.write(iterator.current);
+      while (iterator.moveNext()) {
+        buffer.write(separator);
+        buffer.write(iterator.current);
+      }
+    }
+    return buffer.toString();
+  }
+
+  bool any(bool test(E element)) {
+    for (E element in this) {
+      if (test(element)) return true;
+    }
+    return false;
+  }
+
+  Iterable<E> take(int n) {
+    return TakeIterable<E>(this, n);
+  }
+
+  Iterable<E> takeWhile(bool test(E value)) {
+    return TakeWhileIterable<E>(this, test);
+  }
+
+  Iterable<E> skip(int n) {
+    return SkipIterable<E>(this, n);
+  }
+
+  Iterable<E> skipWhile(bool test(E value)) {
+    return SkipWhileIterable<E>(this, test);
+  }
+
+  E get first {
+    Iterator<E> it = iterator;
+    if (!it.moveNext()) {
+      throw IterableElementError.noElement();
+    }
+    return it.current;
+  }
+
+  E get last {
+    Iterator<E> it = iterator;
+    if (!it.moveNext()) {
+      throw IterableElementError.noElement();
+    }
+    E result;
+    do {
+      result = it.current;
+    } while (it.moveNext());
+    return result;
+  }
+
+  E firstWhere(bool test(E value), {E orElse()}) {
+    for (E element in this) {
+      if (test(element)) return element;
+    }
+    if (orElse != null) return orElse();
+    throw IterableElementError.noElement();
+  }
+
+  E lastWhere(bool test(E value), {E orElse()}) {
+    E result;
+    bool foundMatching = false;
+    for (E element in this) {
+      if (test(element)) {
+        result = element;
+        foundMatching = true;
+      }
+    }
+    if (foundMatching) return result;
+    if (orElse != null) return orElse();
+    throw IterableElementError.noElement();
+  }
+
+  E singleWhere(bool test(E value), {E orElse()}) {
+    E result;
+    bool foundMatching = false;
+    for (E element in this) {
+      if (test(element)) {
+        if (foundMatching) {
+          throw IterableElementError.tooMany();
+        }
+        result = element;
+        foundMatching = true;
+      }
+    }
+    if (foundMatching) return result;
+    if (orElse != null) return orElse();
+    throw IterableElementError.noElement();
+  }
+
+  E elementAt(int index) {
+    ArgumentError.checkNotNull(index, "index");
+    RangeError.checkNotNegative(index, "index");
+    int elementIndex = 0;
+    for (E element in this) {
+      if (index == elementIndex) return element;
+      elementIndex++;
+    }
+    throw RangeError.index(index, this, "index", null, elementIndex);
+  }
+}
+
+/// Base implementation of [Set].
+///
+/// This class provides a base implementation of a `Set` that depends only
+/// on the abstract members: [add], [contains], [lookup], [remove],
+/// [iterator], [length] and [toSet].
+///
+/// Some of the methods assume that `toSet` creates a modifiable set.
+/// If using this base class for an unmodifiable set,
+/// where `toSet` should return an unmodifiable set,
+/// it's necessary to reimplement
+/// [retainAll], [union], [intersection] and [difference].
+///
+/// Implementations of `Set` using this base should consider also implementing
+/// `clear` in constant time. The default implementation works by removing every
+/// element.
+abstract class SetBase<E> extends Object with SetMixin<E> {
+  /// Convert a `Set` to a string as `{each, element, as, string}`.
+  ///
+  /// Handles circular references where converting one of the elements
+  /// to a string ends up converting [set] to a string again.
+  static String setToString(Set set) =>
+      IterableBase.iterableToFullString(set, '{', '}');
+}
+
+/// Common internal implementation of some [Set] methods.
+// TODO(35548): Make this mix-in SetMixin, by adding `with SetMixin<E>`
+// and removing the copied members below,
+// when analyzer supports const constructors for mixin applications.
+abstract class _SetBase<E> implements Set<E> {
+  // The following two methods override the ones in SetBase.
+  // It's possible to be more efficient if we have a way to create an empty
+  // set of the correct type.
+  const _SetBase();
+
+  Set<E> _newSet();
+
+  Set<R> _newSimilarSet<R>();
+
+  Set<R> cast<R>() => Set.castFrom<E, R>(this, newSet: _newSimilarSet);
+
+  Set<E> difference(Set<Object> other) {
+    Set<E> result = _newSet();
+    for (var element in this) {
+      if (!other.contains(element)) result.add(element);
+    }
+    return result;
+  }
+
+  Set<E> intersection(Set<Object> other) {
+    Set<E> result = _newSet();
+    for (var element in this) {
+      if (other.contains(element)) result.add(element);
+    }
+    return result;
+  }
+
+  // Subclasses can optimize this further.
+  Set<E> toSet() => _newSet()..addAll(this);
+
+  /// TODO(35548): Remove the following declarations again when the analyzer
+  /// supports mixins with const constructors, and mix in `SetMixin` instead.
+
+  bool get isEmpty => length == 0;
+
+  bool get isNotEmpty => length != 0;
+
+  Iterable<E> followedBy(Iterable<E> other) =>
+      FollowedByIterable<E>.firstEfficient(this, other);
+
+  Iterable<T> whereType<T>() => WhereTypeIterable<T>(this);
+
+  void clear() {
+    removeAll(toList());
+  }
+
+  void addAll(Iterable<E> elements) {
+    for (E element in elements) add(element);
+  }
+
+  void removeAll(Iterable<Object> elements) {
+    for (Object element in elements) remove(element);
+  }
+
+  void retainAll(Iterable<Object> elements) {
+    // Create a copy of the set, remove all of elements from the copy,
+    // then remove all remaining elements in copy from this.
+    Set<E> toRemove = toSet();
+    for (Object o in elements) {
+      toRemove.remove(o);
+    }
+    removeAll(toRemove);
+  }
+
+  void removeWhere(bool test(E element)) {
+    List toRemove = [];
+    for (E element in this) {
+      if (test(element)) toRemove.add(element);
+    }
+    removeAll(toRemove);
+  }
+
+  void retainWhere(bool test(E element)) {
+    List toRemove = [];
+    for (E element in this) {
+      if (!test(element)) toRemove.add(element);
+    }
+    removeAll(toRemove);
+  }
+
+  bool containsAll(Iterable<Object> other) {
+    for (Object o in other) {
+      if (!contains(o)) return false;
+    }
+    return true;
+  }
+
+  Set<E> union(Set<E> other) {
+    return toSet()..addAll(other);
+  }
+
+  List<E> toList({bool growable = true}) {
+    List<E> result = growable ? (<E>[]..length = length) : List<E>(length);
+    int i = 0;
+    for (E element in this) result[i++] = element;
+    return result;
+  }
+
+  Iterable<T> map<T>(T f(E element)) =>
+      EfficientLengthMappedIterable<E, T>(this, f);
+
+  E get single {
+    if (length > 1) throw IterableElementError.tooMany();
+    Iterator<E> it = iterator;
+    if (!it.moveNext()) throw IterableElementError.noElement();
+    E result = it.current;
+    return result;
+  }
+
+  String toString() => IterableBase.iterableToFullString(this, '{', '}');
+
+  Iterable<E> where(bool f(E element)) => WhereIterable<E>(this, f);
+
+  Iterable<T> expand<T>(Iterable<T> f(E element)) =>
+      ExpandIterable<E, T>(this, f);
+
+  void forEach(void f(E element)) {
+    for (E element in this) f(element);
+  }
+
+  E reduce(E combine(E value, E element)) {
+    Iterator<E> iterator = this.iterator;
+    if (!iterator.moveNext()) {
+      throw IterableElementError.noElement();
+    }
+    E value = iterator.current;
+    while (iterator.moveNext()) {
+      value = combine(value, iterator.current);
+    }
+    return value;
+  }
+
+  T fold<T>(T initialValue, T combine(T previousValue, E element)) {
+    var value = initialValue;
+    for (E element in this) value = combine(value, element);
+    return value;
+  }
+
+  bool every(bool f(E element)) {
+    for (E element in this) {
+      if (!f(element)) return false;
+    }
+    return true;
+  }
+
+  String join([String separator = ""]) {
+    Iterator<E> iterator = this.iterator;
+    if (!iterator.moveNext()) return "";
+    StringBuffer buffer = StringBuffer();
+    if (separator == null || separator == "") {
+      do {
+        buffer.write(iterator.current);
+      } while (iterator.moveNext());
+    } else {
+      buffer.write(iterator.current);
+      while (iterator.moveNext()) {
+        buffer.write(separator);
+        buffer.write(iterator.current);
+      }
+    }
+    return buffer.toString();
+  }
+
+  bool any(bool test(E element)) {
+    for (E element in this) {
+      if (test(element)) return true;
+    }
+    return false;
+  }
+
+  Iterable<E> take(int n) {
+    return TakeIterable<E>(this, n);
+  }
+
+  Iterable<E> takeWhile(bool test(E value)) {
+    return TakeWhileIterable<E>(this, test);
+  }
+
+  Iterable<E> skip(int n) {
+    return SkipIterable<E>(this, n);
+  }
+
+  Iterable<E> skipWhile(bool test(E value)) {
+    return SkipWhileIterable<E>(this, test);
+  }
+
+  E get first {
+    Iterator<E> it = iterator;
+    if (!it.moveNext()) {
+      throw IterableElementError.noElement();
+    }
+    return it.current;
+  }
+
+  E get last {
+    Iterator<E> it = iterator;
+    if (!it.moveNext()) {
+      throw IterableElementError.noElement();
+    }
+    E result;
+    do {
+      result = it.current;
+    } while (it.moveNext());
+    return result;
+  }
+
+  E firstWhere(bool test(E value), {E orElse()}) {
+    for (E element in this) {
+      if (test(element)) return element;
+    }
+    if (orElse != null) return orElse();
+    throw IterableElementError.noElement();
+  }
+
+  E lastWhere(bool test(E value), {E orElse()}) {
+    E result;
+    bool foundMatching = false;
+    for (E element in this) {
+      if (test(element)) {
+        result = element;
+        foundMatching = true;
+      }
+    }
+    if (foundMatching) return result;
+    if (orElse != null) return orElse();
+    throw IterableElementError.noElement();
+  }
+
+  E singleWhere(bool test(E value), {E orElse()}) {
+    E result;
+    bool foundMatching = false;
+    for (E element in this) {
+      if (test(element)) {
+        if (foundMatching) {
+          throw IterableElementError.tooMany();
+        }
+        result = element;
+        foundMatching = true;
+      }
+    }
+    if (foundMatching) return result;
+    if (orElse != null) return orElse();
+    throw IterableElementError.noElement();
+  }
+
+  E elementAt(int index) {
+    ArgumentError.checkNotNull(index, "index");
+    RangeError.checkNotNegative(index, "index");
+    int elementIndex = 0;
+    for (E element in this) {
+      if (index == elementIndex) return element;
+      elementIndex++;
+    }
+    throw RangeError.index(index, this, "index", null, elementIndex);
+  }
+}
+
+/// Class used to implement const sets.
+class _UnmodifiableSet<E> extends _SetBase<E> {
+  final Map<E, Null> _map;
+
+  const _UnmodifiableSet(this._map);
+
+  Set<E> _newSet() => LinkedHashSet<E>();
+
+  Set<R> _newSimilarSet<R>() => LinkedHashSet<R>();
+
+  // Lookups use map methods.
+
+  bool contains(Object element) => _map.containsKey(element);
+
+  Iterator<E> get iterator => _map.keys.iterator;
+
+  int get length => _map.length;
+
+  E lookup(Object element) {
+    for (var key in _map.keys) {
+      if (key == element) return key;
+    }
+    return null;
+  }
+
+  // Mutating methods throw.
+
+  bool add(E value) {
+    throw UnsupportedError("Cannot change unmodifiable set");
+  }
+
+  void clear() {
+    throw UnsupportedError("Cannot change unmodifiable set");
+  }
+
+  void addAll(Iterable<E> elements) {
+    throw UnsupportedError("Cannot change unmodifiable set");
+  }
+
+  void removeAll(Iterable<Object> elements) {
+    throw UnsupportedError("Cannot change unmodifiable set");
+  }
+
+  void retainAll(Iterable<Object> elements) {
+    throw UnsupportedError("Cannot change unmodifiable set");
+  }
+
+  void removeWhere(bool test(E element)) {
+    throw UnsupportedError("Cannot change unmodifiable set");
+  }
+
+  void retainWhere(bool test(E element)) {
+    throw UnsupportedError("Cannot change unmodifiable set");
+  }
+
+  bool remove(Object value) {
+    throw UnsupportedError("Cannot change unmodifiable set");
+  }
+}
diff --git a/sdk_nnbd/lib/collection/splay_tree.dart b/sdk_nnbd/lib/collection/splay_tree.dart
new file mode 100644
index 0000000..5f71934
--- /dev/null
+++ b/sdk_nnbd/lib/collection/splay_tree.dart
@@ -0,0 +1,831 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.collection;
+
+typedef _Predicate<T> = bool Function(T value);
+
+/// A node in a splay tree. It holds the sorting key and the left
+/// and right children in the tree.
+class _SplayTreeNode<K> {
+  final K key;
+  _SplayTreeNode<K> left;
+  _SplayTreeNode<K> right;
+
+  _SplayTreeNode(this.key);
+}
+
+/// A node in a splay tree based map.
+///
+/// A [_SplayTreeNode] that also contains a value
+class _SplayTreeMapNode<K, V> extends _SplayTreeNode<K> {
+  V value;
+  _SplayTreeMapNode(K key, this.value) : super(key);
+}
+
+/// A splay tree is a self-balancing binary search tree.
+///
+/// It has the additional property that recently accessed elements
+/// are quick to access again.
+/// It performs basic operations such as insertion, look-up and
+/// removal, in O(log(n)) amortized time.
+abstract class _SplayTree<K, Node extends _SplayTreeNode<K>> {
+  // The root node of the splay tree. It will contain either the last
+  // element inserted or the last element looked up.
+  Node get _root;
+  set _root(Node newValue);
+
+  // The dummy node used when performing a splay on the tree. Reusing it
+  // avoids allocating a node each time a splay is performed.
+  Node get _dummy;
+
+  // Number of elements in the splay tree.
+  int _count = 0;
+
+  /// Counter incremented whenever the keys in the map changes.
+  ///
+  /// Used to detect concurrent modifications.
+  int _modificationCount = 0;
+
+  /// Counter incremented whenever the tree structure changes.
+  ///
+  /// Used to detect that an in-place traversal cannot use
+  /// cached information that relies on the tree structure.
+  int _splayCount = 0;
+
+  /// The comparator that is used for this splay tree.
+  Comparator<K> get _comparator;
+
+  /// The predicate to determine that a given object is a valid key.
+  _Predicate get _validKey;
+
+  /// Comparison used to compare keys.
+  int _compare(K key1, K key2);
+
+  /// Perform the splay operation for the given key. Moves the node with
+  /// the given key to the top of the tree.  If no node has the given
+  /// key, the last node on the search path is moved to the top of the
+  /// tree. This is the simplified top-down splaying algorithm from:
+  /// "Self-adjusting Binary Search Trees" by Sleator and Tarjan.
+  ///
+  /// Returns the result of comparing the new root of the tree to [key].
+  /// Returns -1 if the table is empty.
+  int _splay(K key) {
+    if (_root == null) return -1;
+
+    // The right child of the dummy node will hold
+    // the L tree of the algorithm.  The left child of the dummy node
+    // will hold the R tree of the algorithm.  Using a dummy node, left
+    // and right will always be nodes and we avoid special cases.
+    Node left = _dummy;
+    Node right = _dummy;
+    Node current = _root;
+    int comp;
+    while (true) {
+      comp = _compare(current.key, key);
+      if (comp > 0) {
+        if (current.left == null) break;
+        comp = _compare(current.left.key, key);
+        if (comp > 0) {
+          // Rotate right.
+          _SplayTreeNode<K> tmp = current.left;
+          current.left = tmp.right;
+          tmp.right = current;
+          current = tmp;
+          if (current.left == null) break;
+        }
+        // Link right.
+        right.left = current;
+        right = current;
+        current = current.left;
+      } else if (comp < 0) {
+        if (current.right == null) break;
+        comp = _compare(current.right.key, key);
+        if (comp < 0) {
+          // Rotate left.
+          Node tmp = current.right;
+          current.right = tmp.left;
+          tmp.left = current;
+          current = tmp;
+          if (current.right == null) break;
+        }
+        // Link left.
+        left.right = current;
+        left = current;
+        current = current.right;
+      } else {
+        break;
+      }
+    }
+    // Assemble.
+    left.right = current.left;
+    right.left = current.right;
+    current.left = _dummy.right;
+    current.right = _dummy.left;
+    _root = current;
+
+    _dummy.right = null;
+    _dummy.left = null;
+    _splayCount++;
+    return comp;
+  }
+
+  // Emulates splaying with a key that is smaller than any in the subtree
+  // anchored at [node].
+  // and that node is returned. It should replace the reference to [node]
+  // in any parent tree or root pointer.
+  external Node _splayMin(Node node);
+
+  // Emulates splaying with a key that is greater than any in the subtree
+  // anchored at [node].
+  // After this, the largest element in the tree is the root of the subtree,
+  // and that node is returned. It should replace the reference to [node]
+  // in any parent tree or root pointer.
+  external Node _splayMax(Node node);
+
+  Node _remove(K key) {
+    if (_root == null) return null;
+    int comp = _splay(key);
+    if (comp != 0) return null;
+    Node result = _root;
+    _count--;
+    // assert(_count >= 0);
+    if (_root.left == null) {
+      _root = _root.right;
+    } else {
+      Node right = _root.right;
+      // Splay to make sure that the new root has an empty right child.
+      _root = _splayMax(_root.left);
+      // Insert the original right child as the right child of the new
+      // root.
+      _root.right = right;
+    }
+    _modificationCount++;
+    return result;
+  }
+
+  /// Adds a new root node with the given [key] or [value].
+  ///
+  /// The [comp] value is the result of comparing the existing root's key
+  /// with key.
+  void _addNewRoot(Node node, int comp) {
+    _count++;
+    _modificationCount++;
+    if (_root == null) {
+      _root = node;
+      return;
+    }
+    // assert(_count >= 0);
+    if (comp < 0) {
+      node.left = _root;
+      node.right = _root.right;
+      _root.right = null;
+    } else {
+      node.right = _root;
+      node.left = _root.left;
+      _root.left = null;
+    }
+    _root = node;
+  }
+
+  Node get _first {
+    if (_root == null) return null;
+    _root = _splayMin(_root);
+    return _root;
+  }
+
+  Node get _last {
+    if (_root == null) return null;
+    _root = _splayMax(_root);
+    return _root;
+  }
+
+  void _clear() {
+    _root = null;
+    _count = 0;
+    _modificationCount++;
+  }
+}
+
+class _TypeTest<T> {
+  bool test(v) => v is T;
+}
+
+int _dynamicCompare(dynamic a, dynamic b) => Comparable.compare(a, b);
+
+Comparator<K> _defaultCompare<K>() {
+  // If K <: Comparable, then we can just use Comparable.compare
+  // with no casts.
+  Object compare = Comparable.compare;
+  if (compare is Comparator<K>) {
+    return compare;
+  }
+  // Otherwise wrap and cast the arguments on each call.
+  return _dynamicCompare;
+}
+
+/// A [Map] of objects that can be ordered relative to each other.
+///
+/// The map is based on a self-balancing binary tree. It allows most operations
+/// in amortized logarithmic time.
+///
+/// Keys of the map are compared using the `compare` function passed in
+/// the constructor, both for ordering and for equality.
+/// If the map contains only the key `a`, then `map.containsKey(b)`
+/// will return `true` if and only if `compare(a, b) == 0`,
+/// and the value of `a == b` is not even checked.
+/// If the compare function is omitted, the objects are assumed to be
+/// [Comparable], and are compared using their [Comparable.compareTo] method.
+/// Non-comparable objects (including `null`) will not work as keys
+/// in that case.
+///
+/// To allow calling [operator []], [remove] or [containsKey] with objects
+/// that are not supported by the `compare` function, an extra `isValidKey`
+/// predicate function can be supplied. This function is tested before
+/// using the `compare` function on an argument value that may not be a [K]
+/// value. If omitted, the `isValidKey` function defaults to testing if the
+/// value is a [K].
+class SplayTreeMap<K, V> extends _SplayTree<K, _SplayTreeMapNode<K, V>>
+    with MapMixin<K, V> {
+  _SplayTreeMapNode<K, V> _root;
+  final _SplayTreeMapNode<K, V> _dummy = _SplayTreeMapNode<K, V>(null, null);
+
+  Comparator<K> _comparator;
+  _Predicate _validKey;
+
+  SplayTreeMap([int compare(K key1, K key2), bool isValidKey(potentialKey)])
+      : _comparator = compare ?? _defaultCompare<K>(),
+        _validKey = isValidKey ?? ((v) => v is K);
+
+  /// Creates a [SplayTreeMap] that contains all key/value pairs of [other].
+  ///
+  /// The keys must all be instances of [K] and the values of [V].
+  /// The [other] map itself can have any type.
+  factory SplayTreeMap.from(Map other,
+      [int compare(K key1, K key2), bool isValidKey(potentialKey)]) {
+    SplayTreeMap<K, V> result = SplayTreeMap<K, V>(compare, isValidKey);
+    other.forEach((k, v) {
+      result[k] = v;
+    });
+    return result;
+  }
+
+  /// Creates a [SplayTreeMap] that contains all key/value pairs of [other].
+  factory SplayTreeMap.of(Map<K, V> other,
+          [int compare(K key1, K key2), bool isValidKey(potentialKey)]) =>
+      SplayTreeMap<K, V>(compare, isValidKey)..addAll(other);
+
+  /// Creates a [SplayTreeMap] where the keys and values are computed from the
+  /// [iterable].
+  ///
+  /// For each element of the [iterable] this constructor computes a key/value
+  /// pair, by applying [key] and [value] respectively.
+  ///
+  /// The keys of the key/value pairs do not need to be unique. The last
+  /// occurrence of a key will simply overwrite any previous value.
+  ///
+  /// If no functions are specified for [key] and [value] the default is to
+  /// use the iterable value itself.
+  factory SplayTreeMap.fromIterable(Iterable iterable,
+      {K key(element),
+      V value(element),
+      int compare(K key1, K key2),
+      bool isValidKey(potentialKey)}) {
+    SplayTreeMap<K, V> map = SplayTreeMap<K, V>(compare, isValidKey);
+    MapBase._fillMapWithMappedIterable(map, iterable, key, value);
+    return map;
+  }
+
+  /// Creates a [SplayTreeMap] associating the given [keys] to [values].
+  ///
+  /// This constructor iterates over [keys] and [values] and maps each element
+  /// of [keys] to the corresponding element of [values].
+  ///
+  /// If [keys] contains the same object multiple times, the last occurrence
+  /// overwrites the previous value.
+  ///
+  /// It is an error if the two [Iterable]s don't have the same length.
+  factory SplayTreeMap.fromIterables(Iterable<K> keys, Iterable<V> values,
+      [int compare(K key1, K key2), bool isValidKey(potentialKey)]) {
+    SplayTreeMap<K, V> map = SplayTreeMap<K, V>(compare, isValidKey);
+    MapBase._fillMapWithIterables(map, keys, values);
+    return map;
+  }
+
+  int _compare(K key1, K key2) => _comparator(key1, key2);
+
+  SplayTreeMap._internal();
+
+  V operator [](Object key) {
+    if (!_validKey(key)) return null;
+    if (_root != null) {
+      int comp = _splay(key);
+      if (comp == 0) {
+        return _root.value;
+      }
+    }
+    return null;
+  }
+
+  V remove(Object key) {
+    if (!_validKey(key)) return null;
+    _SplayTreeMapNode<K, V> mapRoot = _remove(key);
+    if (mapRoot != null) return mapRoot.value;
+    return null;
+  }
+
+  void operator []=(K key, V value) {
+    if (key == null) throw ArgumentError(key);
+    // Splay on the key to move the last node on the search path for
+    // the key to the root of the tree.
+    int comp = _splay(key);
+    if (comp == 0) {
+      _root.value = value;
+      return;
+    }
+    _addNewRoot(_SplayTreeMapNode(key, value), comp);
+  }
+
+  V putIfAbsent(K key, V ifAbsent()) {
+    if (key == null) throw ArgumentError(key);
+    int comp = _splay(key);
+    if (comp == 0) {
+      return _root.value;
+    }
+    int modificationCount = _modificationCount;
+    int splayCount = _splayCount;
+    V value = ifAbsent();
+    if (modificationCount != _modificationCount) {
+      throw ConcurrentModificationError(this);
+    }
+    if (splayCount != _splayCount) {
+      comp = _splay(key);
+      // Key is still not there, otherwise _modificationCount would be changed.
+      assert(comp != 0);
+    }
+    _addNewRoot(_SplayTreeMapNode(key, value), comp);
+    return value;
+  }
+
+  void addAll(Map<K, V> other) {
+    other.forEach((K key, V value) {
+      this[key] = value;
+    });
+  }
+
+  bool get isEmpty {
+    return (_root == null);
+  }
+
+  bool get isNotEmpty => !isEmpty;
+
+  void forEach(void f(K key, V value)) {
+    Iterator<_SplayTreeNode<K>> nodes = _SplayTreeNodeIterator<K>(this);
+    while (nodes.moveNext()) {
+      _SplayTreeMapNode<K, V> node = nodes.current;
+      f(node.key, node.value);
+    }
+  }
+
+  int get length {
+    return _count;
+  }
+
+  void clear() {
+    _clear();
+  }
+
+  bool containsKey(Object key) {
+    return _validKey(key) && _splay(key) == 0;
+  }
+
+  bool containsValue(Object value) {
+    int initialSplayCount = _splayCount;
+    bool visit(_SplayTreeMapNode node) {
+      while (node != null) {
+        if (node.value == value) return true;
+        if (initialSplayCount != _splayCount) {
+          throw ConcurrentModificationError(this);
+        }
+        if (node.right != null && visit(node.right)) return true;
+        node = node.left;
+      }
+      return false;
+    }
+
+    return visit(_root);
+  }
+
+  Iterable<K> get keys => _SplayTreeKeyIterable<K>(this);
+
+  Iterable<V> get values => _SplayTreeValueIterable<K, V>(this);
+
+  /// Get the first key in the map. Returns [:null:] if the map is empty.
+  K firstKey() {
+    if (_root == null) return null;
+    return _first.key;
+  }
+
+  /// Get the last key in the map. Returns [:null:] if the map is empty.
+  K lastKey() {
+    if (_root == null) return null;
+    return _last.key;
+  }
+
+  /// Get the last key in the map that is strictly smaller than [key]. Returns
+  /// [:null:] if no key was not found.
+  K lastKeyBefore(K key) {
+    if (key == null) throw ArgumentError(key);
+    if (_root == null) return null;
+    int comp = _splay(key);
+    if (comp < 0) return _root.key;
+    _SplayTreeNode<K> node = _root.left;
+    if (node == null) return null;
+    while (node.right != null) {
+      node = node.right;
+    }
+    return node.key;
+  }
+
+  /// Get the first key in the map that is strictly larger than [key]. Returns
+  /// [:null:] if no key was not found.
+  K firstKeyAfter(K key) {
+    if (key == null) throw ArgumentError(key);
+    if (_root == null) return null;
+    int comp = _splay(key);
+    if (comp > 0) return _root.key;
+    _SplayTreeNode<K> node = _root.right;
+    if (node == null) return null;
+    while (node.left != null) {
+      node = node.left;
+    }
+    return node.key;
+  }
+}
+
+abstract class _SplayTreeIterator<K, T> implements Iterator<T> {
+  final _SplayTree<K, _SplayTreeNode<K>> _tree;
+
+  /// Worklist of nodes to visit.
+  ///
+  /// These nodes have been passed over on the way down in a
+  /// depth-first left-to-right traversal. Visiting each node,
+  /// and their right subtrees will visit the remainder of
+  /// the nodes of a full traversal.
+  ///
+  /// Only valid as long as the original tree isn't reordered.
+  final List<_SplayTreeNode<K>> _workList = <_SplayTreeNode<K>>[];
+
+  /// Original modification counter of [_tree].
+  ///
+  /// Incremented on [_tree] when a key is added or removed.
+  /// If it changes, iteration is aborted.
+  ///
+  /// Not final because some iterators may modify the tree knowingly,
+  /// and they update the modification count in that case.
+  int _modificationCount;
+
+  /// Count of splay operations on [_tree] when [_workList] was built.
+  ///
+  /// If the splay count on [_tree] increases, [_workList] becomes invalid.
+  int _splayCount;
+
+  /// Current node.
+  _SplayTreeNode<K> _currentNode;
+
+  _SplayTreeIterator(_SplayTree<K, _SplayTreeNode<K>> tree)
+      : _tree = tree,
+        _modificationCount = tree._modificationCount,
+        _splayCount = tree._splayCount {
+    _findLeftMostDescendent(tree._root);
+  }
+
+  _SplayTreeIterator.startAt(_SplayTree<K, _SplayTreeNode<K>> tree, K startKey)
+      : _tree = tree,
+        _modificationCount = tree._modificationCount {
+    if (tree._root == null) return;
+    int compare = tree._splay(startKey);
+    _splayCount = tree._splayCount;
+    if (compare < 0) {
+      // Don't include the root, start at the next element after the root.
+      _findLeftMostDescendent(tree._root.right);
+    } else {
+      _workList.add(tree._root);
+    }
+  }
+
+  T get current {
+    if (_currentNode == null) return null;
+    return _getValue(_currentNode);
+  }
+
+  void _findLeftMostDescendent(_SplayTreeNode<K> node) {
+    while (node != null) {
+      _workList.add(node);
+      node = node.left;
+    }
+  }
+
+  /// Called when the tree structure of the tree has changed.
+  ///
+  /// This can be caused by a splay operation.
+  /// If the key-set changes, iteration is aborted before getting
+  /// here, so we know that the keys are the same as before, it's
+  /// only the tree that has been reordered.
+  void _rebuildWorkList(_SplayTreeNode<K> currentNode) {
+    assert(_workList.isNotEmpty);
+    _workList.clear();
+    if (currentNode == null) {
+      _findLeftMostDescendent(_tree._root);
+    } else {
+      _tree._splay(currentNode.key);
+      _findLeftMostDescendent(_tree._root.right);
+      assert(_workList.isNotEmpty);
+    }
+  }
+
+  bool moveNext() {
+    if (_modificationCount != _tree._modificationCount) {
+      throw ConcurrentModificationError(_tree);
+    }
+    // Picks the next element in the worklist as current.
+    // Updates the worklist with the left-most path of the current node's
+    // right-hand child.
+    // If the worklist is no longer valid (after a splay), it is rebuild
+    // from scratch.
+    if (_workList.isEmpty) {
+      _currentNode = null;
+      return false;
+    }
+    if (_tree._splayCount != _splayCount && _currentNode != null) {
+      _rebuildWorkList(_currentNode);
+    }
+    _currentNode = _workList.removeLast();
+    _findLeftMostDescendent(_currentNode.right);
+    return true;
+  }
+
+  T _getValue(_SplayTreeNode<K> node);
+}
+
+class _SplayTreeKeyIterable<K> extends EfficientLengthIterable<K> {
+  _SplayTree<K, _SplayTreeNode<K>> _tree;
+  _SplayTreeKeyIterable(this._tree);
+  int get length => _tree._count;
+  bool get isEmpty => _tree._count == 0;
+  Iterator<K> get iterator => _SplayTreeKeyIterator<K>(_tree);
+
+  Set<K> toSet() {
+    SplayTreeSet<K> set = SplayTreeSet<K>(_tree._comparator, _tree._validKey);
+    set._count = _tree._count;
+    set._root = set._copyNode(_tree._root);
+    return set;
+  }
+}
+
+class _SplayTreeValueIterable<K, V> extends EfficientLengthIterable<V> {
+  SplayTreeMap<K, V> _map;
+  _SplayTreeValueIterable(this._map);
+  int get length => _map._count;
+  bool get isEmpty => _map._count == 0;
+  Iterator<V> get iterator => _SplayTreeValueIterator<K, V>(_map);
+}
+
+class _SplayTreeKeyIterator<K> extends _SplayTreeIterator<K, K> {
+  _SplayTreeKeyIterator(_SplayTree<K, _SplayTreeNode<K>> map) : super(map);
+  K _getValue(_SplayTreeNode<K> node) => node.key;
+}
+
+class _SplayTreeValueIterator<K, V> extends _SplayTreeIterator<K, V> {
+  _SplayTreeValueIterator(SplayTreeMap<K, V> map) : super(map);
+  V _getValue(_SplayTreeNode<K> node) {
+    _SplayTreeMapNode<K, V> mapNode = node;
+    return mapNode.value;
+  }
+}
+
+class _SplayTreeNodeIterator<K>
+    extends _SplayTreeIterator<K, _SplayTreeNode<K>> {
+  _SplayTreeNodeIterator(_SplayTree<K, _SplayTreeNode<K>> tree) : super(tree);
+  _SplayTreeNodeIterator.startAt(
+      _SplayTree<K, _SplayTreeNode<K>> tree, K startKey)
+      : super.startAt(tree, startKey);
+  _SplayTreeNode<K> _getValue(_SplayTreeNode<K> node) => node;
+}
+
+/// A [Set] of objects that can be ordered relative to each other.
+///
+/// The set is based on a self-balancing binary tree. It allows most operations
+/// in amortized logarithmic time.
+///
+/// Elements of the set are compared using the `compare` function passed in
+/// the constructor, both for ordering and for equality.
+/// If the set contains only an object `a`, then `set.contains(b)`
+/// will return `true` if and only if `compare(a, b) == 0`,
+/// and the value of `a == b` is not even checked.
+/// If the compare function is omitted, the objects are assumed to be
+/// [Comparable], and are compared using their [Comparable.compareTo] method.
+/// Non-comparable objects (including `null`) will not work as an element
+/// in that case.
+class SplayTreeSet<E> extends _SplayTree<E, _SplayTreeNode<E>>
+    with IterableMixin<E>, SetMixin<E> {
+  _SplayTreeNode<E> _root;
+  final _SplayTreeNode<E> _dummy = _SplayTreeNode<E>(null);
+
+  Comparator<E> _comparator;
+  _Predicate _validKey;
+
+  /// Create a new [SplayTreeSet] with the given compare function.
+  ///
+  /// If the [compare] function is omitted, it defaults to [Comparable.compare],
+  /// and the elements must be comparable.
+  ///
+  /// A provided `compare` function may not work on all objects. It may not even
+  /// work on all `E` instances.
+  ///
+  /// For operations that add elements to the set, the user is supposed to not
+  /// pass in objects that doesn't work with the compare function.
+  ///
+  /// The methods [contains], [remove], [lookup], [removeAll] or [retainAll]
+  /// are typed to accept any object(s), and the [isValidKey] test can used to
+  /// filter those objects before handing them to the `compare` function.
+  ///
+  /// If [isValidKey] is provided, only values satisfying `isValidKey(other)`
+  /// are compared using the `compare` method in the methods mentioned above.
+  /// If the `isValidKey` function returns false for an object, it is assumed to
+  /// not be in the set.
+  ///
+  /// If omitted, the `isValidKey` function defaults to checking against the
+  /// type parameter: `other is E`.
+  SplayTreeSet([int compare(E key1, E key2), bool isValidKey(potentialKey)])
+      : _comparator = compare ?? _defaultCompare<E>(),
+        _validKey = isValidKey ?? ((v) => v is E);
+
+  /// Creates a [SplayTreeSet] that contains all [elements].
+  ///
+  /// The set works as if created by `new SplayTreeSet<E>(compare, isValidKey)`.
+  ///
+  /// All the [elements] should be instances of [E] and valid arguments to
+  /// [compare].
+  /// The `elements` iterable itself may have any element type, so this
+  /// constructor can be used to down-cast a `Set`, for example as:
+  /// ```dart
+  /// Set<SuperType> superSet = ...;
+  /// Set<SubType> subSet =
+  ///     new SplayTreeSet<SubType>.from(superSet.whereType<SubType>());
+  /// ```
+  factory SplayTreeSet.from(Iterable elements,
+      [int compare(E key1, E key2), bool isValidKey(potentialKey)]) {
+    SplayTreeSet<E> result = SplayTreeSet<E>(compare, isValidKey);
+    for (final element in elements) {
+      E e = element;
+      result.add(e);
+    }
+    return result;
+  }
+
+  /// Creates a [SplayTreeSet] from [elements].
+  ///
+  /// The set works as if created by `new SplayTreeSet<E>(compare, isValidKey)`.
+  ///
+  /// All the [elements] should be valid as arguments to the [compare] function.
+  factory SplayTreeSet.of(Iterable<E> elements,
+          [int compare(E key1, E key2), bool isValidKey(potentialKey)]) =>
+      SplayTreeSet(compare, isValidKey)..addAll(elements);
+
+  Set<T> _newSet<T>() =>
+      SplayTreeSet<T>((T a, T b) => _comparator(a as E, b as E), _validKey);
+
+  Set<R> cast<R>() => Set.castFrom<E, R>(this, newSet: _newSet);
+  int _compare(E e1, E e2) => _comparator(e1, e2);
+
+  // From Iterable.
+
+  Iterator<E> get iterator => _SplayTreeKeyIterator<E>(this);
+
+  int get length => _count;
+  bool get isEmpty => _root == null;
+  bool get isNotEmpty => _root != null;
+
+  E get first {
+    if (_count == 0) throw IterableElementError.noElement();
+    return _first.key;
+  }
+
+  E get last {
+    if (_count == 0) throw IterableElementError.noElement();
+    return _last.key;
+  }
+
+  E get single {
+    if (_count == 0) throw IterableElementError.noElement();
+    if (_count > 1) throw IterableElementError.tooMany();
+    return _root.key;
+  }
+
+  // From Set.
+  bool contains(Object element) {
+    return _validKey(element) && _splay(element) == 0;
+  }
+
+  bool add(E element) {
+    int compare = _splay(element);
+    if (compare == 0) return false;
+    _addNewRoot(_SplayTreeNode(element), compare);
+    return true;
+  }
+
+  bool remove(Object object) {
+    if (!_validKey(object)) return false;
+    return _remove(object) != null;
+  }
+
+  void addAll(Iterable<E> elements) {
+    for (E element in elements) {
+      int compare = _splay(element);
+      if (compare != 0) {
+        _addNewRoot(_SplayTreeNode(element), compare);
+      }
+    }
+  }
+
+  void removeAll(Iterable<Object> elements) {
+    for (Object element in elements) {
+      if (_validKey(element)) _remove(element);
+    }
+  }
+
+  void retainAll(Iterable<Object> elements) {
+    // Build a set with the same sense of equality as this set.
+    SplayTreeSet<E> retainSet = SplayTreeSet<E>(_comparator, _validKey);
+    int modificationCount = _modificationCount;
+    for (Object object in elements) {
+      if (modificationCount != _modificationCount) {
+        // The iterator should not have side effects.
+        throw ConcurrentModificationError(this);
+      }
+      // Equivalent to this.contains(object).
+      if (_validKey(object) && _splay(object) == 0) {
+        retainSet.add(_root.key);
+      }
+    }
+    // Take over the elements from the retained set, if it differs.
+    if (retainSet._count != _count) {
+      _root = retainSet._root;
+      _count = retainSet._count;
+      _modificationCount++;
+    }
+  }
+
+  E lookup(Object object) {
+    if (!_validKey(object)) return null;
+    int comp = _splay(object);
+    if (comp != 0) return null;
+    return _root.key;
+  }
+
+  Set<E> intersection(Set<Object> other) {
+    Set<E> result = SplayTreeSet<E>(_comparator, _validKey);
+    for (E element in this) {
+      if (other.contains(element)) result.add(element);
+    }
+    return result;
+  }
+
+  Set<E> difference(Set<Object> other) {
+    Set<E> result = SplayTreeSet<E>(_comparator, _validKey);
+    for (E element in this) {
+      if (!other.contains(element)) result.add(element);
+    }
+    return result;
+  }
+
+  Set<E> union(Set<E> other) {
+    return _clone()..addAll(other);
+  }
+
+  SplayTreeSet<E> _clone() {
+    var set = SplayTreeSet<E>(_comparator, _validKey);
+    set._count = _count;
+    set._root = _copyNode(_root);
+    return set;
+  }
+
+  // Copies the structure of a SplayTree into a new similar structure.
+  // Works on _SplayTreeMapNode as well, but only copies the keys,
+  _SplayTreeNode<E> _copyNode(_SplayTreeNode<E> node) {
+    if (node == null) return null;
+    return _SplayTreeNode<E>(node.key)
+      ..left = _copyNode(node.left)
+      ..right = _copyNode(node.right);
+  }
+
+  void clear() {
+    _clear();
+  }
+
+  Set<E> toSet() => _clone();
+
+  String toString() => IterableBase.iterableToFullString(this, '{', '}');
+}
diff --git a/sdk_nnbd/lib/convert/ascii.dart b/sdk_nnbd/lib/convert/ascii.dart
new file mode 100644
index 0000000..35105ac
--- /dev/null
+++ b/sdk_nnbd/lib/convert/ascii.dart
@@ -0,0 +1,287 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.convert;
+
+/// An instance of the default implementation of the [AsciiCodec].
+///
+/// This instance provides a convenient access to the most common ASCII
+/// use cases.
+///
+/// Examples:
+/// ```dart
+/// var encoded = ascii.encode("This is ASCII!");
+/// var decoded = ascii.decode([0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73,
+///                             0x20, 0x41, 0x53, 0x43, 0x49, 0x49, 0x21]);
+/// ```
+const AsciiCodec ascii = AsciiCodec();
+
+const int _asciiMask = 0x7F;
+
+/// An [AsciiCodec] allows encoding strings as ASCII bytes
+/// and decoding ASCII bytes to strings.
+class AsciiCodec extends Encoding {
+  final bool _allowInvalid;
+
+  /// Instantiates a new [AsciiCodec].
+  ///
+  /// If [allowInvalid] is true, the [decode] method and the converter
+  /// returned by [decoder] will default to allowing invalid values.
+  /// If allowing invalid values, the values will be decoded into the Unicode
+  /// Replacement character (U+FFFD). If not, an exception will be thrown.
+  /// Calls to the [decode] method can choose to override this default.
+  ///
+  /// Encoders will not accept invalid (non ASCII) characters.
+  const AsciiCodec({bool allowInvalid = false}) : _allowInvalid = allowInvalid;
+
+  /// The name of this codec, "us-ascii".
+  String get name => "us-ascii";
+
+  Uint8List encode(String source) => encoder.convert(source);
+
+  /// Decodes the ASCII [bytes] (a list of unsigned 7-bit integers) to the
+  /// corresponding string.
+  ///
+  /// If [bytes] contains values that are not in the range 0 .. 127, the decoder
+  /// will eventually throw a [FormatException].
+  ///
+  /// If [allowInvalid] is not provided, it defaults to the value used to create
+  /// this [AsciiCodec].
+  String decode(List<int> bytes, {bool allowInvalid}) {
+    allowInvalid ??= _allowInvalid;
+    if (allowInvalid) {
+      return const AsciiDecoder(allowInvalid: true).convert(bytes);
+    } else {
+      return const AsciiDecoder(allowInvalid: false).convert(bytes);
+    }
+  }
+
+  AsciiEncoder get encoder => const AsciiEncoder();
+
+  AsciiDecoder get decoder => _allowInvalid
+      ? const AsciiDecoder(allowInvalid: true)
+      : const AsciiDecoder(allowInvalid: false);
+}
+
+// Superclass for [AsciiEncoder] and [Latin1Encoder].
+// Generalizes common operations that only differ by a mask;
+class _UnicodeSubsetEncoder extends Converter<String, List<int>> {
+  final int _subsetMask;
+
+  const _UnicodeSubsetEncoder(this._subsetMask);
+
+  /// Converts the [String] into a list of its code units.
+  ///
+  /// If [start] and [end] are provided, only the substring
+  /// `string.substring(start, end)` is used as input to the conversion.
+  Uint8List convert(String string, [int start = 0, int end]) {
+    var stringLength = string.length;
+    end = RangeError.checkValidRange(start, end, stringLength);
+    var length = end - start;
+    var result = Uint8List(length);
+    for (var i = 0; i < length; i++) {
+      var codeUnit = string.codeUnitAt(start + i);
+      if ((codeUnit & ~_subsetMask) != 0) {
+        throw ArgumentError.value(
+            string, "string", "Contains invalid characters.");
+      }
+      result[i] = codeUnit;
+    }
+    return result;
+  }
+
+  /// Starts a chunked conversion.
+  ///
+  /// The converter works more efficiently if the given [sink] is a
+  /// [ByteConversionSink].
+  StringConversionSink startChunkedConversion(Sink<List<int>> sink) {
+    return _UnicodeSubsetEncoderSink(_subsetMask,
+        sink is ByteConversionSink ? sink : ByteConversionSink.from(sink));
+  }
+
+  // Override the base-class' bind, to provide a better type.
+  Stream<List<int>> bind(Stream<String> stream) => super.bind(stream);
+}
+
+/// This class converts strings of only ASCII characters to bytes.
+class AsciiEncoder extends _UnicodeSubsetEncoder {
+  const AsciiEncoder() : super(_asciiMask);
+}
+
+/// This class encodes chunked strings to bytes (unsigned 8-bit
+/// integers).
+class _UnicodeSubsetEncoderSink extends StringConversionSinkBase {
+  final ByteConversionSink _sink;
+  final int _subsetMask;
+
+  _UnicodeSubsetEncoderSink(this._subsetMask, this._sink);
+
+  void close() {
+    _sink.close();
+  }
+
+  void addSlice(String source, int start, int end, bool isLast) {
+    RangeError.checkValidRange(start, end, source.length);
+    for (var i = start; i < end; i++) {
+      var codeUnit = source.codeUnitAt(i);
+      if ((codeUnit & ~_subsetMask) != 0) {
+        throw ArgumentError(
+            "Source contains invalid character with code point: $codeUnit.");
+      }
+    }
+    _sink.add(source.codeUnits.sublist(start, end));
+    if (isLast) {
+      close();
+    }
+  }
+}
+
+/// This class converts Latin-1 bytes (lists of unsigned 8-bit integers)
+/// to a string.
+abstract class _UnicodeSubsetDecoder extends Converter<List<int>, String> {
+  final bool _allowInvalid;
+  final int _subsetMask;
+
+  /// Instantiates a new decoder.
+  ///
+  /// The [_allowInvalid] argument defines how [convert] deals
+  /// with invalid bytes.
+  ///
+  /// The [_subsetMask] argument is a bit mask used to define the subset
+  /// of Unicode being decoded. Use [_LATIN1_MASK] for Latin-1 (8-bit) or
+  /// [_asciiMask] for ASCII (7-bit).
+  ///
+  /// If [_allowInvalid] is `true`, [convert] replaces invalid bytes with the
+  /// Unicode Replacement character `U+FFFD` (�).
+  /// Otherwise it throws a [FormatException].
+  const _UnicodeSubsetDecoder(this._allowInvalid, this._subsetMask);
+
+  /// Converts the [bytes] (a list of unsigned 7- or 8-bit integers) to the
+  /// corresponding string.
+  ///
+  /// If [start] and [end] are provided, only the sub-list of bytes from
+  /// `start` to `end` (`end` not inclusive) is used as input to the conversion.
+  String convert(List<int> bytes, [int start = 0, int end]) {
+    var byteCount = bytes.length;
+    RangeError.checkValidRange(start, end, byteCount);
+    end ??= byteCount;
+
+    for (var i = start; i < end; i++) {
+      var byte = bytes[i];
+      if ((byte & ~_subsetMask) != 0) {
+        if (!_allowInvalid) {
+          throw FormatException("Invalid value in input: $byte");
+        }
+        return _convertInvalid(bytes, start, end);
+      }
+    }
+    return String.fromCharCodes(bytes, start, end);
+  }
+
+  String _convertInvalid(List<int> bytes, int start, int end) {
+    var buffer = StringBuffer();
+    for (var i = start; i < end; i++) {
+      var value = bytes[i];
+      if ((value & ~_subsetMask) != 0) value = 0xFFFD;
+      buffer.writeCharCode(value);
+    }
+    return buffer.toString();
+  }
+
+  /// Starts a chunked conversion.
+  ///
+  /// The converter works more efficiently if the given [sink] is a
+  /// [StringConversionSink].
+  ByteConversionSink startChunkedConversion(Sink<String> sink);
+
+  // Override the base-class's bind, to provide a better type.
+  Stream<String> bind(Stream<List<int>> stream) => super.bind(stream);
+}
+
+class AsciiDecoder extends _UnicodeSubsetDecoder {
+  const AsciiDecoder({bool allowInvalid = false})
+      : super(allowInvalid, _asciiMask);
+
+  /// Starts a chunked conversion.
+  ///
+  /// The converter works more efficiently if the given [sink] is a
+  /// [StringConversionSink].
+  ByteConversionSink startChunkedConversion(Sink<String> sink) {
+    StringConversionSink stringSink;
+    if (sink is StringConversionSink) {
+      stringSink = sink;
+    } else {
+      stringSink = StringConversionSink.from(sink);
+    }
+    // TODO(lrn): Use asUtf16Sink when it becomes available. It
+    // works just as well, is likely to have less decoding overhead,
+    // and make adding U+FFFD easier.
+    // At that time, merge this with _Latin1DecoderSink;
+    if (_allowInvalid) {
+      return _ErrorHandlingAsciiDecoderSink(stringSink.asUtf8Sink(false));
+    } else {
+      return _SimpleAsciiDecoderSink(stringSink);
+    }
+  }
+}
+
+class _ErrorHandlingAsciiDecoderSink extends ByteConversionSinkBase {
+  ByteConversionSink _utf8Sink;
+  _ErrorHandlingAsciiDecoderSink(this._utf8Sink);
+
+  void close() {
+    _utf8Sink.close();
+  }
+
+  void add(List<int> source) {
+    addSlice(source, 0, source.length, false);
+  }
+
+  void addSlice(List<int> source, int start, int end, bool isLast) {
+    RangeError.checkValidRange(start, end, source.length);
+    for (var i = start; i < end; i++) {
+      if ((source[i] & ~_asciiMask) != 0) {
+        if (i > start) _utf8Sink.addSlice(source, start, i, false);
+        // Add UTF-8 encoding of U+FFFD.
+        _utf8Sink.add(const <int>[0xEF, 0xBF, 0xBD]);
+        start = i + 1;
+      }
+    }
+    if (start < end) {
+      _utf8Sink.addSlice(source, start, end, isLast);
+    } else if (isLast) {
+      close();
+    }
+  }
+}
+
+class _SimpleAsciiDecoderSink extends ByteConversionSinkBase {
+  Sink _sink;
+  _SimpleAsciiDecoderSink(this._sink);
+
+  void close() {
+    _sink.close();
+  }
+
+  void add(List<int> source) {
+    for (var i = 0; i < source.length; i++) {
+      if ((source[i] & ~_asciiMask) != 0) {
+        throw FormatException("Source contains non-ASCII bytes.");
+      }
+    }
+    _sink.add(String.fromCharCodes(source));
+  }
+
+  void addSlice(List<int> source, int start, int end, bool isLast) {
+    final length = source.length;
+    RangeError.checkValidRange(start, end, length);
+    if (start < end) {
+      if (start != 0 || end != length) {
+        source = source.sublist(start, end);
+      }
+      add(source);
+    }
+    if (isLast) close();
+  }
+}
diff --git a/sdk_nnbd/lib/convert/base64.dart b/sdk_nnbd/lib/convert/base64.dart
new file mode 100644
index 0000000..ce522be
--- /dev/null
+++ b/sdk_nnbd/lib/convert/base64.dart
@@ -0,0 +1,854 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.convert;
+
+/// A [base64](https://tools.ietf.org/html/rfc4648) encoder and decoder.
+///
+/// It encodes using the default base64 alphabet,
+/// decodes using both the base64 and base64url alphabets,
+/// does not allow invalid characters and requires padding.
+///
+/// Examples:
+///
+///     var encoded = base64.encode([0x62, 0x6c, 0xc3, 0xa5, 0x62, 0xc3, 0xa6,
+///                                  0x72, 0x67, 0x72, 0xc3, 0xb8, 0x64]);
+///     var decoded = base64.decode("YmzDpWLDpnJncsO4ZAo=");
+///
+/// The top-level [base64Encode] and [base64Decode] functions may be used
+/// instead if a local variable shadows the [base64] constant.
+const Base64Codec base64 = Base64Codec();
+
+/// A [base64url](https://tools.ietf.org/html/rfc4648) encoder and decoder.
+///
+/// It encodes and decodes using the base64url alphabet,
+/// decodes using both the base64 and base64url alphabets,
+/// does not allow invalid characters and requires padding.
+///
+/// Examples:
+///
+///     var encoded = base64Url.encode([0x62, 0x6c, 0xc3, 0xa5, 0x62, 0xc3, 0xa6,
+///                                     0x72, 0x67, 0x72, 0xc3, 0xb8, 0x64]);
+///     var decoded = base64Url.decode("YmzDpWLDpnJncsO4ZAo=");
+const Base64Codec base64Url = Base64Codec.urlSafe();
+
+/// Encodes [bytes] using [base64](https://tools.ietf.org/html/rfc4648) encoding.
+///
+/// Shorthand for [base64.encode]. Useful if a local variable shadows the global
+/// [base64] constant.
+String base64Encode(List<int> bytes) => base64.encode(bytes);
+
+/// Encodes [bytes] using [base64url](https://tools.ietf.org/html/rfc4648) encoding.
+///
+/// Shorthand for [base64url.encode].
+String base64UrlEncode(List<int> bytes) => base64Url.encode(bytes);
+
+/// Decodes [base64](https://tools.ietf.org/html/rfc4648) or [base64url](https://tools.ietf.org/html/rfc4648) encoded bytes.
+///
+/// Shorthand for [base64.decode]. Useful if a local variable shadows the
+/// global [base64] constant.
+Uint8List base64Decode(String source) => base64.decode(source);
+
+// Constants used in more than one class.
+const int _paddingChar = 0x3d; // '='.
+
+/// A [base64](https://tools.ietf.org/html/rfc4648) encoder and decoder.
+///
+/// A [Base64Codec] allows base64 encoding bytes into ASCII strings and
+/// decoding valid encodings back to bytes.
+///
+/// This implementation only handles the simplest RFC 4648 base64 and base64url
+/// encodings.
+/// It does not allow invalid characters when decoding and it requires,
+/// and generates, padding so that the input is always a multiple of four
+/// characters.
+class Base64Codec extends Codec<List<int>, String> {
+  final Base64Encoder _encoder;
+  const Base64Codec() : _encoder = const Base64Encoder();
+  const Base64Codec.urlSafe() : _encoder = const Base64Encoder.urlSafe();
+
+  Base64Encoder get encoder => _encoder;
+
+  Base64Decoder get decoder => const Base64Decoder();
+
+  /// Decodes [encoded].
+  ///
+  /// The input is decoded as if by `decoder.convert`.
+  ///
+  /// The returned [Uint8List] contains exactly the decoded bytes,
+  /// so the [Uint8List.length] is precisely the number of decoded bytes.
+  /// The [Uint8List.buffer] may be larger than the decoded bytes.
+  Uint8List decode(String encoded) => decoder.convert(encoded);
+
+  /// Validates and normalizes the base64 encoded data in [source].
+  ///
+  /// Only acts on the substring from [start] to [end], with [end]
+  /// defaulting to the end of the string.
+  ///
+  /// Normalization will:
+  /// * Unescape any `%`-escapes.
+  /// * Only allow valid characters (`A`-`Z`, `a`-`z`, `0`-`9`, `/` and `+`).
+  /// * Normalize a `_` or `-` character to `/` or `+`.
+  /// * Validate that existing padding (trailing `=` characters) is correct.
+  /// * If no padding exists, add correct padding if necessary and possible.
+  /// * Validate that the length is correct (a multiple of four).
+  String normalize(String source, [int start = 0, int end]) {
+    end = RangeError.checkValidRange(start, end, source.length);
+    const percent = 0x25;
+    const equals = 0x3d;
+    StringBuffer buffer;
+    var sliceStart = start;
+    var alphabet = _Base64Encoder._base64Alphabet;
+    var inverseAlphabet = _Base64Decoder._inverseAlphabet;
+    var firstPadding = -1;
+    var firstPaddingSourceIndex = -1;
+    var paddingCount = 0;
+    for (var i = start; i < end;) {
+      var sliceEnd = i;
+      var char = source.codeUnitAt(i++);
+      var originalChar = char;
+      // Normalize char, keep originalChar to see if it matches the source.
+      if (char == percent) {
+        if (i + 2 <= end) {
+          char = parseHexByte(source, i); // May be negative.
+          i += 2;
+          // We know that %25 isn't valid, but our table considers it
+          // a potential padding start, so skip the checks.
+          if (char == percent) char = -1;
+        } else {
+          // An invalid HEX escape (too short).
+          // Just skip past the handling and reach the throw below.
+          char = -1;
+        }
+      }
+      // If char is negative here, hex-decoding failed in some way.
+      if (0 <= char && char <= 127) {
+        var value = inverseAlphabet[char];
+        if (value >= 0) {
+          char = alphabet.codeUnitAt(value);
+          if (char == originalChar) continue;
+        } else if (value == _Base64Decoder._padding) {
+          // We have ruled out percent, so char is '='.
+          if (firstPadding < 0) {
+            // Mark position in normalized output where padding occurs.
+            firstPadding = (buffer?.length ?? 0) + (sliceEnd - sliceStart);
+            firstPaddingSourceIndex = sliceEnd;
+          }
+          paddingCount++;
+          // It could have been an escaped equals (%3D).
+          if (originalChar == equals) continue;
+        }
+        if (value != _Base64Decoder._invalid) {
+          buffer ??= StringBuffer();
+          buffer.write(source.substring(sliceStart, sliceEnd));
+          buffer.writeCharCode(char);
+          sliceStart = i;
+          continue;
+        }
+      }
+      throw FormatException("Invalid base64 data", source, sliceEnd);
+    }
+    if (buffer != null) {
+      buffer.write(source.substring(sliceStart, end));
+      if (firstPadding >= 0) {
+        // There was padding in the source. Check that it is valid:
+        // * result length a multiple of four
+        // * one or two padding characters at the end.
+        _checkPadding(source, firstPaddingSourceIndex, end, firstPadding,
+            paddingCount, buffer.length);
+      } else {
+        // Length of last chunk (1-4 chars) in the encoding.
+        var endLength = ((buffer.length - 1) % 4) + 1;
+        if (endLength == 1) {
+          // The data must have length 0, 2 or 3 modulo 4.
+          throw FormatException("Invalid base64 encoding length ", source, end);
+        }
+        while (endLength < 4) {
+          buffer.write("=");
+          endLength++;
+        }
+      }
+      return source.replaceRange(start, end, buffer.toString());
+    }
+    // Original was already normalized, only check padding.
+    var length = end - start;
+    if (firstPadding >= 0) {
+      _checkPadding(source, firstPaddingSourceIndex, end, firstPadding,
+          paddingCount, length);
+    } else {
+      // No padding given, so add some if needed it.
+      var endLength = length % 4;
+      if (endLength == 1) {
+        // The data must have length 0, 2 or 3 modulo 4.
+        throw FormatException("Invalid base64 encoding length ", source, end);
+      }
+      if (endLength > 1) {
+        // There is no "insertAt" on String, but this works as well.
+        source = source.replaceRange(end, end, (endLength == 2) ? "==" : "=");
+      }
+    }
+    return source;
+  }
+
+  static void _checkPadding(String source, int sourceIndex, int sourceEnd,
+      int firstPadding, int paddingCount, int length) {
+    if (length % 4 != 0) {
+      throw FormatException(
+          "Invalid base64 padding, padded length must be multiple of four, "
+          "is $length",
+          source,
+          sourceEnd);
+    }
+    if (firstPadding + paddingCount != length) {
+      throw FormatException(
+          "Invalid base64 padding, '=' not at the end", source, sourceIndex);
+    }
+    if (paddingCount > 2) {
+      throw FormatException(
+          "Invalid base64 padding, more than two '=' characters",
+          source,
+          sourceIndex);
+    }
+  }
+}
+
+// ------------------------------------------------------------------------
+// Encoder
+// ------------------------------------------------------------------------
+
+/// Base64 and base64url encoding converter.
+///
+/// Encodes lists of bytes using base64 or base64url encoding.
+///
+/// The results are ASCII strings using a restricted alphabet.
+class Base64Encoder extends Converter<List<int>, String> {
+  final bool _urlSafe;
+
+  const Base64Encoder() : _urlSafe = false;
+  const Base64Encoder.urlSafe() : _urlSafe = true;
+
+  String convert(List<int> input) {
+    if (input.isEmpty) return "";
+    var encoder = _Base64Encoder(_urlSafe);
+    var buffer = encoder.encode(input, 0, input.length, true);
+    return String.fromCharCodes(buffer);
+  }
+
+  ByteConversionSink startChunkedConversion(Sink<String> sink) {
+    if (sink is StringConversionSink) {
+      return _Utf8Base64EncoderSink(sink.asUtf8Sink(false), _urlSafe);
+    }
+    return _AsciiBase64EncoderSink(sink, _urlSafe);
+  }
+}
+
+/// Helper class for encoding bytes to base64.
+class _Base64Encoder {
+  /// The RFC 4648 base64 encoding alphabet.
+  static const String _base64Alphabet =
+      "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+  /// The RFC 4648 base64url encoding alphabet.
+  static const String _base64UrlAlphabet =
+      "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
+
+  /// Shift-count to extract the values stored in [_state].
+  static const int _valueShift = 2;
+
+  /// Mask to extract the count value stored in [_state].
+  static const int _countMask = 3;
+
+  static const int _sixBitMask = 0x3F;
+
+  /// Intermediate state between chunks.
+  ///
+  /// Encoding handles three bytes at a time.
+  /// If fewer than three bytes has been seen, this value encodes
+  /// the number of bytes seen (0, 1 or 2) and their values.
+  int _state = 0;
+
+  /// Alphabet used for encoding.
+  final String _alphabet;
+
+  _Base64Encoder(bool urlSafe)
+      : _alphabet = urlSafe ? _base64UrlAlphabet : _base64Alphabet;
+
+  /// Encode count and bits into a value to be stored in [_state].
+  static int _encodeState(int count, int bits) {
+    assert(count <= _countMask);
+    return bits << _valueShift | count;
+  }
+
+  /// Extract bits from encoded state.
+  static int _stateBits(int state) => state >> _valueShift;
+
+  /// Extract count from encoded state.
+  static int _stateCount(int state) => state & _countMask;
+
+  /// Create a [Uint8List] with the provided length.
+  Uint8List createBuffer(int bufferLength) => Uint8List(bufferLength);
+
+  /// Encode [bytes] from [start] to [end] and the bits in [_state].
+  ///
+  /// Returns a [Uint8List] of the ASCII codes of the encoded data.
+  ///
+  /// If the input, including left over [_state] from earlier encodings,
+  /// are not a multiple of three bytes, then the partial state is stored
+  /// back into [_state].
+  /// If [isLast] is true, partial state is encoded in the output instead,
+  /// with the necessary padding.
+  ///
+  /// Returns `null` if there is no output.
+  Uint8List encode(List<int> bytes, int start, int end, bool isLast) {
+    assert(0 <= start);
+    assert(start <= end);
+    assert(bytes == null || end <= bytes.length);
+    var length = end - start;
+
+    var count = _stateCount(_state);
+    var byteCount = (count + length);
+    var fullChunks = byteCount ~/ 3;
+    var partialChunkLength = byteCount - fullChunks * 3;
+    var bufferLength = fullChunks * 4;
+    if (isLast && partialChunkLength > 0) {
+      bufferLength += 4; // Room for padding.
+    }
+    var output = createBuffer(bufferLength);
+    _state =
+        encodeChunk(_alphabet, bytes, start, end, isLast, output, 0, _state);
+    if (bufferLength > 0) return output;
+    // If the input plus the data in state is still less than three bytes,
+    // there may not be any output.
+    return null;
+  }
+
+  static int encodeChunk(String alphabet, List<int> bytes, int start, int end,
+      bool isLast, Uint8List output, int outputIndex, int state) {
+    var bits = _stateBits(state);
+    // Count number of missing bytes in three-byte chunk.
+    var expectedChars = 3 - _stateCount(state);
+
+    // The input must be a list of bytes (integers in the range 0..255).
+    // The value of `byteOr` will be the bitwise or of all the values in
+    // `bytes` and a later check will validate that they were all valid bytes.
+    var byteOr = 0;
+    for (var i = start; i < end; i++) {
+      var byte = bytes[i];
+      byteOr |= byte;
+      bits = ((bits << 8) | byte) & 0xFFFFFF; // Never store more than 24 bits.
+      expectedChars--;
+      if (expectedChars == 0) {
+        output[outputIndex++] = alphabet.codeUnitAt((bits >> 18) & _sixBitMask);
+        output[outputIndex++] = alphabet.codeUnitAt((bits >> 12) & _sixBitMask);
+        output[outputIndex++] = alphabet.codeUnitAt((bits >> 6) & _sixBitMask);
+        output[outputIndex++] = alphabet.codeUnitAt(bits & _sixBitMask);
+        expectedChars = 3;
+        bits = 0;
+      }
+    }
+    if (byteOr >= 0 && byteOr <= 255) {
+      if (isLast && expectedChars < 3) {
+        writeFinalChunk(alphabet, output, outputIndex, 3 - expectedChars, bits);
+        return 0;
+      }
+      return _encodeState(3 - expectedChars, bits);
+    }
+
+    // There was an invalid byte value somewhere in the input - find it!
+    var i = start;
+    while (i < end) {
+      var byte = bytes[i];
+      if (byte < 0 || byte > 255) break;
+      i++;
+    }
+    throw ArgumentError.value(
+        bytes, "Not a byte value at index $i: 0x${bytes[i].toRadixString(16)}");
+  }
+
+  /// Writes a final encoded four-character chunk.
+  ///
+  /// Only used when the [_state] contains a partial (1 or 2 byte)
+  /// input.
+  static void writeFinalChunk(
+      String alphabet, Uint8List output, int outputIndex, int count, int bits) {
+    assert(count > 0);
+    if (count == 1) {
+      output[outputIndex++] = alphabet.codeUnitAt((bits >> 2) & _sixBitMask);
+      output[outputIndex++] = alphabet.codeUnitAt((bits << 4) & _sixBitMask);
+      output[outputIndex++] = _paddingChar;
+      output[outputIndex++] = _paddingChar;
+    } else {
+      assert(count == 2);
+      output[outputIndex++] = alphabet.codeUnitAt((bits >> 10) & _sixBitMask);
+      output[outputIndex++] = alphabet.codeUnitAt((bits >> 4) & _sixBitMask);
+      output[outputIndex++] = alphabet.codeUnitAt((bits << 2) & _sixBitMask);
+      output[outputIndex++] = _paddingChar;
+    }
+  }
+}
+
+class _BufferCachingBase64Encoder extends _Base64Encoder {
+  /// Reused buffer.
+  ///
+  /// When the buffer isn't released to the sink, only used to create another
+  /// value (a string), the buffer can be reused between chunks.
+  Uint8List bufferCache;
+
+  _BufferCachingBase64Encoder(bool urlSafe) : super(urlSafe);
+
+  Uint8List createBuffer(int bufferLength) {
+    if (bufferCache == null || bufferCache.length < bufferLength) {
+      bufferCache = Uint8List(bufferLength);
+    }
+    // Return a view of the buffer, so it has the requested length.
+    return Uint8List.view(bufferCache.buffer, 0, bufferLength);
+  }
+}
+
+abstract class _Base64EncoderSink extends ByteConversionSinkBase {
+  void add(List<int> source) {
+    _add(source, 0, source.length, false);
+  }
+
+  void close() {
+    _add(null, 0, 0, true);
+  }
+
+  void addSlice(List<int> source, int start, int end, bool isLast) {
+    if (end == null) throw ArgumentError.notNull("end");
+    RangeError.checkValidRange(start, end, source.length);
+    _add(source, start, end, isLast);
+  }
+
+  void _add(List<int> source, int start, int end, bool isLast);
+}
+
+class _AsciiBase64EncoderSink extends _Base64EncoderSink {
+  final Sink<String> _sink;
+  final _Base64Encoder _encoder;
+
+  _AsciiBase64EncoderSink(this._sink, bool urlSafe)
+      : _encoder = _BufferCachingBase64Encoder(urlSafe);
+
+  void _add(List<int> source, int start, int end, bool isLast) {
+    var buffer = _encoder.encode(source, start, end, isLast);
+    if (buffer != null) {
+      var string = String.fromCharCodes(buffer);
+      _sink.add(string);
+    }
+    if (isLast) {
+      _sink.close();
+    }
+  }
+}
+
+class _Utf8Base64EncoderSink extends _Base64EncoderSink {
+  final ByteConversionSink _sink;
+  final _Base64Encoder _encoder;
+
+  _Utf8Base64EncoderSink(this._sink, bool urlSafe)
+      : _encoder = _Base64Encoder(urlSafe);
+
+  void _add(List<int> source, int start, int end, bool isLast) {
+    var buffer = _encoder.encode(source, start, end, isLast);
+    if (buffer != null) {
+      _sink.addSlice(buffer, 0, buffer.length, isLast);
+    }
+  }
+}
+
+// ------------------------------------------------------------------------
+// Decoder
+// ------------------------------------------------------------------------
+
+/// Decoder for base64 encoded data.
+///
+/// This decoder accepts both base64 and base64url ("url-safe") encodings.
+///
+/// The encoding is required to be properly padded.
+class Base64Decoder extends Converter<String, List<int>> {
+  const Base64Decoder();
+
+  /// Decodes the characters of [input] from [start] to [end] as base64.
+  ///
+  /// If [start] is omitted, it defaults to the start of [input].
+  /// If [end] is omitted, it defaults to the end of [input].
+  ///
+  /// The returned [Uint8List] contains exactly the decoded bytes,
+  /// so the [Uint8List.length] is precisely the number of decoded bytes.
+  /// The [Uint8List.buffer] may be larger than the decoded bytes.
+  Uint8List convert(String input, [int start = 0, int end]) {
+    end = RangeError.checkValidRange(start, end, input.length);
+    if (start == end) return Uint8List(0);
+    var decoder = _Base64Decoder();
+    var buffer = decoder.decode(input, start, end);
+    decoder.close(input, end);
+    return buffer;
+  }
+
+  StringConversionSink startChunkedConversion(Sink<List<int>> sink) {
+    return _Base64DecoderSink(sink);
+  }
+}
+
+/// Helper class implementing base64 decoding with intermediate state.
+class _Base64Decoder {
+  /// Shift-count to extract the values stored in [_state].
+  static const int _valueShift = 2;
+
+  /// Mask to extract the count value stored in [_state].
+  static const int _countMask = 3;
+
+  /// Invalid character in decoding table.
+  static const int _invalid = -2;
+
+  /// Padding character in decoding table.
+  static const int _padding = -1;
+
+  // Shorthands to make the table more readable.
+  static const int __ = _invalid;
+  static const int _p = _padding;
+
+  /// Mapping from ASCII characters to their index in the base64 alphabet.
+  ///
+  /// Uses [_invalid] for invalid indices and [_padding] for the padding
+  /// character.
+  ///
+  /// Accepts the "URL-safe" alphabet as well (`-` and `_` are the
+  /// 62nd and 63rd alphabet characters), and considers `%` a padding
+  /// character, which must then be followed by `3D`, the percent-escape
+  /// for `=`.
+  static final List<int> _inverseAlphabet = Int8List.fromList([
+    __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, //
+    __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, //
+    __, __, __, __, __, _p, __, __, __, __, __, 62, __, 62, __, 63, //
+    52, 53, 54, 55, 56, 57, 58, 59, 60, 61, __, __, __, _p, __, __, //
+    __, 00, 01, 02, 03, 04, 05, 06, 07, 08, 09, 10, 11, 12, 13, 14, //
+    15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, __, __, __, __, 63, //
+    __, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, //
+    41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, __, __, __, __, __, //
+  ]);
+
+  // Character constants.
+  static const int _char_percent = 0x25; // '%'.
+  static const int _char_3 = 0x33; // '3'.
+  static const int _char_d = 0x64; // 'd'.
+
+  /// Maintains the intermediate state of a partly-decoded input.
+  ///
+  /// Base64 is decoded in chunks of four characters. If a chunk does not
+  /// contain a full block, the decoded bits (six per character) of the
+  /// available characters are stored in [_state] until the next call to
+  /// [_decode] or [_close].
+  ///
+  /// If no padding has been seen, the value is
+  ///   `numberOfCharactersSeen | (decodedBits << 2)`
+  /// where `numberOfCharactersSeen` is between 0 and 3 and decoded bits
+  /// contains six bits per seen character.
+  ///
+  /// If padding has been seen the value is negative. It's the bitwise negation
+  /// of the number of remaining allowed padding characters (always ~0 or ~1).
+  ///
+  /// A state of `0` or `~0` are valid places to end decoding, all other values
+  /// mean that a four-character block has not been completed.
+  int _state = 0;
+
+  /// Encodes [count] and [bits] as a value to be stored in [_state].
+  static int _encodeCharacterState(int count, int bits) {
+    assert(count == (count & _countMask));
+    return (bits << _valueShift | count);
+  }
+
+  /// Extracts count from a [_state] value.
+  static int _stateCount(int state) {
+    assert(state >= 0);
+    return state & _countMask;
+  }
+
+  /// Extracts value bits from a [_state] value.
+  static int _stateBits(int state) {
+    assert(state >= 0);
+    return state >> _valueShift;
+  }
+
+  /// Encodes a number of expected padding characters to be stored in [_state].
+  static int _encodePaddingState(int expectedPadding) {
+    assert(expectedPadding >= 0);
+    assert(expectedPadding <= 5);
+    return -expectedPadding - 1; // ~expectedPadding adapted to dart2js.
+  }
+
+  /// Extracts expected padding character count from a [_state] value.
+  static int _statePadding(int state) {
+    assert(state < 0);
+    return -state - 1; // ~state adapted to dart2js.
+  }
+
+  static bool _hasSeenPadding(int state) => state < 0;
+
+  /// Decodes [input] from [start] to [end].
+  ///
+  /// Returns a [Uint8List] with the decoded bytes.
+  /// If a previous call had an incomplete four-character block, the bits from
+  /// those are included in decoding
+  Uint8List decode(String input, int start, int end) {
+    assert(0 <= start);
+    assert(start <= end);
+    assert(end <= input.length);
+    if (_hasSeenPadding(_state)) {
+      _state = _checkPadding(input, start, end, _state);
+      return null;
+    }
+    if (start == end) return Uint8List(0);
+    var buffer = _allocateBuffer(input, start, end, _state);
+    _state = decodeChunk(input, start, end, buffer, 0, _state);
+    return buffer;
+  }
+
+  /// Checks that [_state] represents a valid decoding.
+  void close(String input, int end) {
+    if (_state < _encodePaddingState(0)) {
+      throw FormatException("Missing padding character", input, end);
+    }
+    if (_state > 0) {
+      throw FormatException(
+          "Invalid length, must be multiple of four", input, end);
+    }
+    _state = _encodePaddingState(0);
+  }
+
+  /// Decodes [input] from [start] to [end].
+  ///
+  /// Includes the state returned by a previous call in the decoding.
+  /// Writes the decoding to [output] at [outIndex], and there must
+  /// be room in the output.
+  static int decodeChunk(String input, int start, int end, Uint8List output,
+      int outIndex, int state) {
+    assert(!_hasSeenPadding(state));
+    const asciiMask = 127;
+    const asciiMax = 127;
+    const eightBitMask = 0xFF;
+    const bitsPerCharacter = 6;
+
+    var bits = _stateBits(state);
+    var count = _stateCount(state);
+    // String contents should be all ASCII.
+    // Instead of checking for each character, we collect the bitwise-or of
+    // all the characters in `charOr` and later validate that all characters
+    // were ASCII.
+    var charOr = 0;
+    for (var i = start; i < end; i++) {
+      var char = input.codeUnitAt(i);
+      charOr |= char;
+      var code = _inverseAlphabet[char & asciiMask];
+      if (code >= 0) {
+        bits = ((bits << bitsPerCharacter) | code) & 0xFFFFFF;
+        count = (count + 1) & 3;
+        if (count == 0) {
+          assert(outIndex + 3 <= output.length);
+          output[outIndex++] = (bits >> 16) & eightBitMask;
+          output[outIndex++] = (bits >> 8) & eightBitMask;
+          output[outIndex++] = bits & eightBitMask;
+          bits = 0;
+        }
+        continue;
+      } else if (code == _padding && count > 1) {
+        if (charOr < 0 || charOr > asciiMax) break;
+        if (count == 3) {
+          if ((bits & 0x03) != 0) {
+            throw FormatException("Invalid encoding before padding", input, i);
+          }
+          output[outIndex++] = bits >> 10;
+          output[outIndex++] = bits >> 2;
+        } else {
+          if ((bits & 0x0F) != 0) {
+            throw FormatException("Invalid encoding before padding", input, i);
+          }
+          output[outIndex++] = bits >> 4;
+        }
+        // Expected padding is the number of expected padding characters,
+        // where `=` counts as three and `%3D` counts as one per character.
+        //
+        // Expect either zero or one padding depending on count (2 or 3),
+        // plus two more characters if the code was `%` (a partial padding).
+        var expectedPadding = (3 - count) * 3;
+        if (char == _char_percent) expectedPadding += 2;
+        state = _encodePaddingState(expectedPadding);
+        return _checkPadding(input, i + 1, end, state);
+      }
+      throw FormatException("Invalid character", input, i);
+    }
+    if (charOr >= 0 && charOr <= asciiMax) {
+      return _encodeCharacterState(count, bits);
+    }
+    // There is an invalid (non-ASCII) character in the input.
+    int i;
+    for (i = start; i < end; i++) {
+      var char = input.codeUnitAt(i);
+      if (char < 0 || char > asciiMax) break;
+    }
+    throw FormatException("Invalid character", input, i);
+  }
+
+  /// Allocates a buffer with room for the decoding of a substring of [input].
+  ///
+  /// Includes room for the characters in [state], and handles padding correctly.
+  static Uint8List _allocateBuffer(
+      String input, int start, int end, int state) {
+    assert(state >= 0);
+    var paddingStart = _trimPaddingChars(input, start, end);
+    var length = _stateCount(state) + (paddingStart - start);
+    // Three bytes per full four bytes in the input.
+    var bufferLength = (length >> 2) * 3;
+    // If padding was seen, then this is the last chunk, and the final partial
+    // chunk should be decoded too.
+    var remainderLength = length & 3;
+    if (remainderLength != 0 && paddingStart < end) {
+      bufferLength += remainderLength - 1;
+    }
+    if (bufferLength > 0) return Uint8List(bufferLength);
+    // If the input plus state is less than four characters, and it's not
+    // at the end of input, no buffer is needed.
+    return null;
+  }
+
+  /// Returns the position of the start of padding at the end of the input.
+  ///
+  /// Returns the end of input if there is no padding.
+  ///
+  /// This is used to ensure that the decoding buffer has the exact size
+  /// it needs when input is valid, and at least enough bytes to reach the error
+  /// when input is invalid.
+  ///
+  /// Never count more than two padding sequences since any more than that
+  /// will raise an error anyway, and we only care about being precise for
+  /// successful conversions.
+  static int _trimPaddingChars(String input, int start, int end) {
+    // This may count '%=' as two paddings. That's ok, it will err later,
+    // but the buffer will be large enough to reach the error.
+    var padding = 0;
+    var index = end;
+    var newEnd = end;
+    while (index > start && padding < 2) {
+      index--;
+      var char = input.codeUnitAt(index);
+      if (char == _paddingChar) {
+        padding++;
+        newEnd = index;
+        continue;
+      }
+      if ((char | 0x20) == _char_d) {
+        if (index == start) break;
+        index--;
+        char = input.codeUnitAt(index);
+      }
+      if (char == _char_3) {
+        if (index == start) break;
+        index--;
+        char = input.codeUnitAt(index);
+      }
+      if (char == _char_percent) {
+        padding++;
+        newEnd = index;
+        continue;
+      }
+      break;
+    }
+    return newEnd;
+  }
+
+  /// Check that the remainder of the string is valid padding.
+  ///
+  /// Valid padding is a correct number (0, 1 or 2) of `=` characters
+  /// or `%3D` sequences depending on the number of preceding base64 characters.
+  /// The [state] parameter encodes which padding continuations are allowed
+  /// as the number of expected characters. That number is the number of
+  /// expected padding characters times 3 minus the number of padding characters
+  /// seen so far, where `=` counts as 3 counts as three characters,
+  /// and the padding sequence `%3D` counts as one character per character.
+  ///
+  /// The number of missing characters is always between 0 and 5 because we
+  /// only call this function after having seen at least one `=` or `%`
+  /// character.
+  /// If the number of missing characters is not 3 or 0, we have seen (at least)
+  /// a `%` character and expects the rest of the `%3D` sequence, and a `=` is
+  /// not allowed. When missing 3 characters, either `=` or `%` is allowed.
+  ///
+  /// When the value is 0, no more padding (or any other character) is allowed.
+  static int _checkPadding(String input, int start, int end, int state) {
+    assert(_hasSeenPadding(state));
+    if (start == end) return state;
+    var expectedPadding = _statePadding(state);
+    assert(expectedPadding >= 0);
+    assert(expectedPadding < 6);
+    while (expectedPadding > 0) {
+      var char = input.codeUnitAt(start);
+      if (expectedPadding == 3) {
+        if (char == _paddingChar) {
+          expectedPadding -= 3;
+          start++;
+          break;
+        }
+        if (char == _char_percent) {
+          expectedPadding--;
+          start++;
+          if (start == end) break;
+          char = input.codeUnitAt(start);
+        } else {
+          break;
+        }
+      }
+      // Partial padding means we have seen part of a "%3D" escape.
+      var expectedPartialPadding = expectedPadding;
+      if (expectedPartialPadding > 3) expectedPartialPadding -= 3;
+      if (expectedPartialPadding == 2) {
+        // Expects '3'
+        if (char != _char_3) break;
+        start++;
+        expectedPadding--;
+        if (start == end) break;
+        char = input.codeUnitAt(start);
+      }
+      // Expects 'D' or 'd'.
+      if ((char | 0x20) != _char_d) break;
+      start++;
+      expectedPadding--;
+      if (start == end) break;
+    }
+    if (start != end) {
+      throw FormatException("Invalid padding character", input, start);
+    }
+    return _encodePaddingState(expectedPadding);
+  }
+}
+
+class _Base64DecoderSink extends StringConversionSinkBase {
+  /// Output sink
+  final Sink<List<int>> _sink;
+  final _Base64Decoder _decoder = _Base64Decoder();
+
+  _Base64DecoderSink(this._sink);
+
+  void add(String string) {
+    if (string.isEmpty) return;
+    var buffer = _decoder.decode(string, 0, string.length);
+    if (buffer != null) _sink.add(buffer);
+  }
+
+  void close() {
+    _decoder.close(null, null);
+    _sink.close();
+  }
+
+  void addSlice(String string, int start, int end, bool isLast) {
+    end = RangeError.checkValidRange(start, end, string.length);
+    if (start == end) return;
+    var buffer = _decoder.decode(string, start, end);
+    if (buffer != null) _sink.add(buffer);
+    if (isLast) {
+      _decoder.close(string, end);
+      _sink.close();
+    }
+  }
+}
diff --git a/sdk_nnbd/lib/convert/byte_conversion.dart b/sdk_nnbd/lib/convert/byte_conversion.dart
new file mode 100644
index 0000000..3d52d78
--- /dev/null
+++ b/sdk_nnbd/lib/convert/byte_conversion.dart
@@ -0,0 +1,109 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.convert;
+
+/// The [ByteConversionSink] provides an interface for converters to
+/// efficiently transmit byte data.
+///
+/// Instead of limiting the interface to one non-chunked list of bytes it
+/// accepts its input in chunks (themselves being lists of bytes).
+///
+/// This abstract class will likely get more methods over time. Implementers are
+/// urged to extend or mix in [ByteConversionSinkBase] to ensure that their
+/// class covers the newly added methods.
+abstract class ByteConversionSink extends ChunkedConversionSink<List<int>> {
+  ByteConversionSink();
+  factory ByteConversionSink.withCallback(
+      void callback(List<int> accumulated)) = _ByteCallbackSink;
+  factory ByteConversionSink.from(Sink<List<int>> sink) = _ByteAdapterSink;
+
+  /// Adds the next [chunk] to `this`.
+  ///
+  /// Adds the bytes defined by [start] and [end]-exclusive to `this`.
+  ///
+  /// If [isLast] is `true` closes `this`.
+  ///
+  /// Contrary to `add` the given [chunk] must not be held onto. Once the method
+  /// returns, it is safe to overwrite the data in it.
+  void addSlice(List<int> chunk, int start, int end, bool isLast);
+
+  // TODO(floitsch): add more methods:
+  // - iterateBytes.
+}
+
+/// This class provides a base-class for converters that need to accept byte
+/// inputs.
+abstract class ByteConversionSinkBase extends ByteConversionSink {
+  void add(List<int> chunk);
+  void close();
+
+  void addSlice(List<int> chunk, int start, int end, bool isLast) {
+    add(chunk.sublist(start, end));
+    if (isLast) close();
+  }
+}
+
+/// This class adapts a simple [Sink] to a [ByteConversionSink].
+///
+/// All additional methods of the [ByteConversionSink] (compared to the
+/// ChunkedConversionSink) are redirected to the `add` method.
+class _ByteAdapterSink extends ByteConversionSinkBase {
+  final Sink<List<int>> _sink;
+
+  _ByteAdapterSink(this._sink);
+
+  void add(List<int> chunk) {
+    _sink.add(chunk);
+  }
+
+  void close() {
+    _sink.close();
+  }
+}
+
+/// This class accumulates all chunks into one list of bytes
+/// and invokes a callback when the sink is closed.
+///
+/// This class can be used to terminate a chunked conversion.
+class _ByteCallbackSink extends ByteConversionSinkBase {
+  static const _INITIAL_BUFFER_SIZE = 1024;
+
+  final void Function(List<int>) _callback;
+  List<int> _buffer = Uint8List(_INITIAL_BUFFER_SIZE);
+  int _bufferIndex = 0;
+
+  _ByteCallbackSink(void callback(List<int> accumulated))
+      : _callback = callback;
+
+  void add(Iterable<int> chunk) {
+    var freeCount = _buffer.length - _bufferIndex;
+    if (chunk.length > freeCount) {
+      // Grow the buffer.
+      var oldLength = _buffer.length;
+      var newLength = _roundToPowerOf2(chunk.length + oldLength) * 2;
+      var grown = Uint8List(newLength);
+      grown.setRange(0, _buffer.length, _buffer);
+      _buffer = grown;
+    }
+    _buffer.setRange(_bufferIndex, _bufferIndex + chunk.length, chunk);
+    _bufferIndex += chunk.length;
+  }
+
+  static int _roundToPowerOf2(int v) {
+    assert(v > 0);
+    v--;
+    v |= v >> 1;
+    v |= v >> 2;
+    v |= v >> 4;
+    v |= v >> 8;
+    v |= v >> 16;
+    v++;
+    return v;
+  }
+
+  void close() {
+    _callback(_buffer.sublist(0, _bufferIndex));
+  }
+}
diff --git a/sdk_nnbd/lib/convert/chunked_conversion.dart b/sdk_nnbd/lib/convert/chunked_conversion.dart
new file mode 100644
index 0000000..e946f97
--- /dev/null
+++ b/sdk_nnbd/lib/convert/chunked_conversion.dart
@@ -0,0 +1,82 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.convert;
+
+/// A [ChunkedConversionSink] is used to transmit data more efficiently between
+/// two converters during chunked conversions.
+///
+/// The basic `ChunkedConversionSink` is just a [Sink], and converters should
+/// work with a plain `Sink`, but may work more efficiently with certain
+/// specialized types of `ChunkedConversionSink`.
+///
+/// It is recommended that implementations of `ChunkedConversionSink` extend
+/// this class, to inherit any further methods that may be added to the class.
+abstract class ChunkedConversionSink<T> implements Sink<T> {
+  ChunkedConversionSink();
+  factory ChunkedConversionSink.withCallback(
+      void callback(List<T> accumulated)) = _SimpleCallbackSink<T>;
+
+  /// Adds chunked data to this sink.
+  ///
+  /// This method is also used when converters are used as [StreamTransformer]s.
+  void add(T chunk);
+
+  /// Closes the sink.
+  ///
+  /// This signals the end of the chunked conversion. This method is called
+  /// when converters are used as [StreamTransformer]'s.
+  void close();
+}
+
+/// This class accumulates all chunks and invokes a callback with a list of
+/// the chunks when the sink is closed.
+///
+/// This class can be used to terminate a chunked conversion.
+class _SimpleCallbackSink<T> extends ChunkedConversionSink<T> {
+  final void Function(List<T>) _callback;
+  final List<T> _accumulated = <T>[];
+
+  _SimpleCallbackSink(this._callback);
+
+  void add(T chunk) {
+    _accumulated.add(chunk);
+  }
+
+  void close() {
+    _callback(_accumulated);
+  }
+}
+
+/// This class implements the logic for a chunked conversion as a
+/// stream transformer.
+///
+/// It is used as strategy in the [EventTransformStream].
+///
+/// It also implements the [ChunkedConversionSink] interface so that it
+/// can be used as output sink in a chunked conversion.
+class _ConverterStreamEventSink<S, T> implements EventSink<S> {
+  /// The output sink for the converter.
+  final EventSink<T> _eventSink;
+
+  /// The input sink for new data. All data that is received with
+  /// [handleData] is added into this sink.
+  final Sink<S> _chunkedSink;
+
+  _ConverterStreamEventSink(Converter<S, T> converter, EventSink<T> sink)
+      : _eventSink = sink,
+        _chunkedSink = converter.startChunkedConversion(sink);
+
+  void add(S o) {
+    _chunkedSink.add(o);
+  }
+
+  void addError(Object error, [StackTrace stackTrace]) {
+    _eventSink.addError(error, stackTrace);
+  }
+
+  void close() {
+    _chunkedSink.close();
+  }
+}
diff --git a/sdk_nnbd/lib/convert/codec.dart b/sdk_nnbd/lib/convert/codec.dart
new file mode 100644
index 0000000..38e4a3c
--- /dev/null
+++ b/sdk_nnbd/lib/convert/codec.dart
@@ -0,0 +1,97 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.convert;
+
+/// A [Codec] encodes and (if supported) decodes data.
+///
+/// Codecs can be fused. For example fusing [json] and [utf8] produces
+/// an encoder that can convert Json objects directly to bytes, or can decode
+/// bytes directly to json objects.
+///
+/// Fused codecs generally attempt to optimize the operations and can be faster
+/// than executing each step of an encoding separately.
+abstract class Codec<S, T> {
+  const Codec();
+
+  /// Encodes [input].
+  ///
+  /// The input is encoded as if by `encoder.convert`.
+  T encode(S input) => encoder.convert(input);
+
+  /// Decodes [encoded] data.
+  ///
+  /// The input is decoded as if by `decoder.convert`.
+  S decode(T encoded) => decoder.convert(encoded);
+
+  /// Returns the encoder from [S] to [T].
+  ///
+  /// It may be stateful and should not be reused.
+  Converter<S, T> get encoder;
+
+  /// Returns the decoder of `this`, converting from [T] to [S].
+  ///
+  /// It may be stateful and should not be reused.
+  Converter<T, S> get decoder;
+
+  /// Fuses `this` with `other`.
+  ///
+  /// When encoding, the resulting codec encodes with `this` before
+  /// encoding with [other].
+  ///
+  /// When decoding, the resulting codec decodes with [other] before decoding
+  /// with `this`.
+  ///
+  /// In some cases one needs to use the [inverted] codecs to be able to fuse
+  /// them correctly. That is, the output type of `this` ([T]) must match the
+  /// input type of the second codec [other].
+  ///
+  /// Examples:
+  /// ```dart
+  /// final jsonToBytes = json.fuse(utf8);
+  /// List<int> bytes = jsonToBytes.encode(["json-object"]);
+  /// var decoded = jsonToBytes.decode(bytes);
+  /// assert(decoded is List && decoded[0] == "json-object");
+  ///
+  /// var inverted = json.inverted;
+  /// var jsonIdentity = json.fuse(inverted);
+  /// var jsonObject = jsonIdentity.encode(["1", 2]);
+  /// assert(jsonObject is List && jsonObject[0] == "1" && jsonObject[1] == 2);
+  /// ```
+  // TODO(floitsch): use better example with line-splitter once that one is
+  // in this library.
+  Codec<S, R> fuse<R>(Codec<T, R> other) {
+    return _FusedCodec<S, T, R>(this, other);
+  }
+
+  /// Inverts `this`.
+  ///
+  /// The [encoder] and [decoder] of the resulting codec are swapped.
+  Codec<T, S> get inverted => _InvertedCodec<T, S>(this);
+}
+
+/// Fuses the given codecs.
+///
+/// In the non-chunked conversion simply invokes the non-chunked conversions in
+/// sequence.
+class _FusedCodec<S, M, T> extends Codec<S, T> {
+  final Codec<S, M> _first;
+  final Codec<M, T> _second;
+
+  Converter<S, T> get encoder => _first.encoder.fuse<T>(_second.encoder);
+  Converter<T, S> get decoder => _second.decoder.fuse<S>(_first.decoder);
+
+  _FusedCodec(this._first, this._second);
+}
+
+class _InvertedCodec<T, S> extends Codec<T, S> {
+  final Codec<S, T> _codec;
+
+  _InvertedCodec(Codec<S, T> codec) : _codec = codec;
+
+  Converter<T, S> get encoder => _codec.decoder;
+  Converter<S, T> get decoder => _codec.encoder;
+
+  Codec<S, T> get inverted => _codec;
+}
diff --git a/sdk_nnbd/lib/convert/convert.dart b/sdk_nnbd/lib/convert/convert.dart
new file mode 100644
index 0000000..6173782
--- /dev/null
+++ b/sdk_nnbd/lib/convert/convert.dart
@@ -0,0 +1,72 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+///
+/// Encoders and decoders for converting between different data representations,
+/// including JSON and UTF-8.
+///
+/// In addition to converters for common data representations, this library
+/// provides support for implementing converters in a way which makes them easy to
+/// chain and to use with streams.
+///
+/// To use this library in your code:
+///
+///     import 'dart:convert';
+///
+/// Two commonly used converters are the top-level instances of
+/// [JsonCodec] and [Utf8Codec], named [json] and [utf8], respectively.
+///
+/// JSON is a simple text format for representing
+/// structured objects and collections.
+/// The JSON encoder/decoder transforms between strings and
+/// object structures, such as lists and maps, using the JSON format.
+///
+/// UTF-8 is a common variable-width encoding that can represent
+/// every character in the Unicode character set.
+/// The UTF-8 encoder/decoder transforms between Strings and bytes.
+///
+/// Converters are often used with streams
+/// to transform the data that comes through the stream
+/// as it becomes available.
+/// The following code uses two converters.
+/// The first is a UTF-8 decoder, which converts the data from bytes to UTF-8
+/// as it's read from a file,
+/// The second is an instance of [LineSplitter],
+/// which splits the data on newline boundaries.
+///
+///     var lineNumber = 1;
+///     var stream = File('quotes.txt').openRead();
+///
+///     stream.transform(utf8.decoder)
+///           .transform(const LineSplitter())
+///           .listen((line) {
+///             if (showLineNumbers) {
+///               stdout.write('${lineNumber++} ');
+///             }
+///             stdout.writeln(line);
+///           });
+///
+/// See the documentation for the [Codec] and [Converter] classes
+/// for information about creating your own converters.
+///
+/// {@category Core}
+library dart.convert;
+
+import 'dart:async';
+import 'dart:typed_data';
+import 'dart:_internal' show CastConverter, parseHexByte;
+
+part 'ascii.dart';
+part 'base64.dart';
+part 'byte_conversion.dart';
+part 'chunked_conversion.dart';
+part 'codec.dart';
+part 'converter.dart';
+part 'encoding.dart';
+part 'html_escape.dart';
+part 'json.dart';
+part 'latin1.dart';
+part 'line_splitter.dart';
+part 'string_conversion.dart';
+part 'utf.dart';
diff --git a/sdk_nnbd/lib/convert/convert_sources.gni b/sdk_nnbd/lib/convert/convert_sources.gni
new file mode 100644
index 0000000..ad79649
--- /dev/null
+++ b/sdk_nnbd/lib/convert/convert_sources.gni
@@ -0,0 +1,23 @@
+# 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.
+
+# This file contains all sources for the dart:convert library.
+convert_sdk_sources = [
+  "convert.dart",
+
+  # The above file needs to be first as it lists the parts below.
+  "ascii.dart",
+  "base64.dart",
+  "byte_conversion.dart",
+  "chunked_conversion.dart",
+  "codec.dart",
+  "converter.dart",
+  "encoding.dart",
+  "html_escape.dart",
+  "json.dart",
+  "latin1.dart",
+  "line_splitter.dart",
+  "string_conversion.dart",
+  "utf.dart",
+]
diff --git a/sdk_nnbd/lib/convert/converter.dart b/sdk_nnbd/lib/convert/converter.dart
new file mode 100644
index 0000000..2167933
--- /dev/null
+++ b/sdk_nnbd/lib/convert/converter.dart
@@ -0,0 +1,72 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.convert;
+
+/// A [Converter] converts data from one representation into another.
+///
+/// It is recommended that implementations of `Converter` extend this class,
+/// to inherit any further methods that may be added to the class.
+abstract class Converter<S, T> extends StreamTransformerBase<S, T> {
+  const Converter();
+
+  /// Adapts [source] to be a `Converter<TS, TT>`.
+  ///
+  /// This allows [source] to be used at the new type, but at run-time it
+  /// must satisfy the requirements of both the new type and its original type.
+  ///
+  /// Conversion input must be both [SS] and [TS] and the output created by
+  /// [source] for those input must be both [ST] and [TT].
+  static Converter<TS, TT> castFrom<SS, ST, TS, TT>(Converter<SS, ST> source) =>
+      CastConverter<SS, ST, TS, TT>(source);
+
+  /// Converts [input] and returns the result of the conversion.
+  T convert(S input);
+
+  /// Fuses `this` with [other].
+  ///
+  /// Encoding with the resulting converter is equivalent to converting with
+  /// `this` before converting with `other`.
+  Converter<S, TT> fuse<TT>(Converter<T, TT> other) {
+    return _FusedConverter<S, T, TT>(this, other);
+  }
+
+  /// Starts a chunked conversion.
+  ///
+  /// The returned sink serves as input for the long-running conversion. The
+  /// given [sink] serves as output.
+  Sink<S> startChunkedConversion(Sink<T> sink) {
+    throw UnsupportedError(
+        "This converter does not support chunked conversions: $this");
+  }
+
+  Stream<T> bind(Stream<S> stream) {
+    return Stream<T>.eventTransformed(
+        stream, (EventSink sink) => _ConverterStreamEventSink(this, sink));
+  }
+
+  /// Provides a `Converter<RS, RT>` view of this stream transformer.
+  ///
+  /// The resulting transformer will check at run-time that all conversion
+  /// inputs are actually instances of [S],
+  /// and it will check that all conversion output produced by this converter
+  /// are actually instances of [RT].
+  Converter<RS, RT> cast<RS, RT>() => Converter.castFrom<S, T, RS, RT>(this);
+}
+
+/// Fuses two converters.
+///
+/// For a non-chunked conversion converts the input in sequence.
+class _FusedConverter<S, M, T> extends Converter<S, T> {
+  final Converter<S, M> _first;
+  final Converter<M, T> _second;
+
+  _FusedConverter(this._first, this._second);
+
+  T convert(S input) => _second.convert(_first.convert(input));
+
+  Sink<S> startChunkedConversion(Sink<T> sink) {
+    return _first.startChunkedConversion(_second.startChunkedConversion(sink));
+  }
+}
diff --git a/sdk_nnbd/lib/convert/encoding.dart b/sdk_nnbd/lib/convert/encoding.dart
new file mode 100644
index 0000000..7ce8ec3
--- /dev/null
+++ b/sdk_nnbd/lib/convert/encoding.dart
@@ -0,0 +1,81 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.convert;
+
+/// Open-ended Encoding enum.
+abstract class Encoding extends Codec<String, List<int>> {
+  const Encoding();
+
+  /// Returns the encoder from `String` to `List<int>`.
+  ///
+  /// It may be stateful and should not be reused.
+  Converter<String, List<int>> get encoder;
+
+  /// Returns the decoder of `this`, converting from `List<int>` to `String`.
+  ///
+  /// It may be stateful and should not be reused.
+  Converter<List<int>, String> get decoder;
+
+  Future<String> decodeStream(Stream<List<int>> byteStream) {
+    return decoder
+        .bind(byteStream)
+        .fold(StringBuffer(),
+            (StringBuffer buffer, String string) => buffer..write(string))
+        .then((StringBuffer buffer) => buffer.toString());
+  }
+
+  /// Name of the encoding.
+  ///
+  /// If the encoding is standardized, this is the lower-case version of one of
+  /// the IANA official names for the character set (see
+  /// http://www.iana.org/assignments/character-sets/character-sets.xml)
+  String get name;
+
+  // All aliases (in lowercase) of supported encoding from
+  // http://www.iana.org/assignments/character-sets/character-sets.xml.
+  static final Map<String, Encoding> _nameToEncoding = <String, Encoding>{
+    // ISO_8859-1:1987.
+    "iso_8859-1:1987": latin1,
+    "iso-ir-100": latin1,
+    "iso_8859-1": latin1,
+    "iso-8859-1": latin1,
+    "latin1": latin1,
+    "l1": latin1,
+    "ibm819": latin1,
+    "cp819": latin1,
+    "csisolatin1": latin1,
+
+    // US-ASCII.
+    "iso-ir-6": ascii,
+    "ansi_x3.4-1968": ascii,
+    "ansi_x3.4-1986": ascii,
+    "iso_646.irv:1991": ascii,
+    "iso646-us": ascii,
+    "us-ascii": ascii,
+    "us": ascii,
+    "ibm367": ascii,
+    "cp367": ascii,
+    "csascii": ascii,
+    "ascii": ascii, // This is not in the IANA official names.
+
+    // UTF-8.
+    "csutf8": utf8,
+    "utf-8": utf8
+  };
+
+  /// Gets an [Encoding] object from the name of the character set
+  /// name. The names used are the IANA official names for the
+  /// character set (see
+  /// http://www.iana.org/assignments/character-sets/character-sets.xml).
+  ///
+  /// The [name] passed is case insensitive.
+  ///
+  /// If character set is not supported [:null:] is returned.
+  static Encoding getByName(String name) {
+    if (name == null) return null;
+    name = name.toLowerCase();
+    return _nameToEncoding[name];
+  }
+}
diff --git a/sdk_nnbd/lib/convert/html_escape.dart b/sdk_nnbd/lib/convert/html_escape.dart
new file mode 100644
index 0000000..a0a7119
--- /dev/null
+++ b/sdk_nnbd/lib/convert/html_escape.dart
@@ -0,0 +1,223 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.convert;
+
+/// A `String` converter that converts characters to HTML entities.
+///
+/// This is intended to sanitize text before inserting the text into an HTML
+/// document. Characters that are meaningful in HTML are converted to
+/// HTML entities (like `&amp;` for `&`).
+///
+/// The general converter escapes all characters that are meaningful in HTML
+/// attributes or normal element context. Elements with special content types
+/// (like CSS or JavaScript) may need a more specialized escaping that
+/// understands that content type.
+///
+/// If the context where the text will be inserted is known in more detail,
+/// it's possible to omit escaping some characters (like quotes when not
+/// inside an attribute value).
+///
+/// The escaped text should only be used inside quoted HTML attributes values
+/// or as text content of a normal element. Using the escaped text inside a
+/// tag, but not inside a quoted attribute value, is still dangerous.
+const HtmlEscape htmlEscape = HtmlEscape();
+
+/// HTML escape modes.
+///
+/// Allows specifying a mode for HTML escaping that depend on the context
+/// where the escaped result is going to be used.
+/// The relevant contexts are:
+///
+/// * as text content of an HTML element.
+/// * as value of a (single- or double-) quoted attribute value.
+///
+/// All modes require escaping of `&` (ampersand) characters, and may
+/// enable escaping of more characters.
+///
+/// Custom escape modes can be created using the [HtmlEscapeMode.HtmlEscapeMode]
+/// constructor.
+class HtmlEscapeMode {
+  final String _name;
+
+  /// Whether to escape '<' and '>'.
+  final bool escapeLtGt;
+
+  /// Whether to escape '"' (quote).
+  final bool escapeQuot;
+
+  /// Whether to escape "'" (apostrophe).
+  final bool escapeApos;
+
+  /// Whether to escape "/" (forward slash, solidus).
+  ///
+  /// Escaping a slash is recommended to avoid cross-site scripting attacks by
+  /// [the Open Web Application Security Project](https://www.owasp.org/index.php/XSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet#RULE_.231_-_HTML_Escape_Before_Inserting_Untrusted_Data_into_HTML_Element_Content)
+  final bool escapeSlash;
+
+  /// Default escaping mode which escape all characters.
+  ///
+  /// The result of such an escaping is usable both in element content and
+  /// in any attribute value.
+  ///
+  /// The escaping only works for elements with normal HTML content,
+  /// and not for, for example, script or style element content,
+  /// which require escapes matching their particular content syntax.
+  static const HtmlEscapeMode unknown =
+      HtmlEscapeMode._('unknown', true, true, true, true);
+
+  /// Escaping mode for text going into double-quoted HTML attribute values.
+  ///
+  /// The result should not be used as the content of an unquoted
+  /// or single-quoted attribute value.
+  ///
+  /// Escapes double quotes (`"`) but not single quotes (`'`),
+  /// and escapes `<` and `>` characters because they are not allowed
+  /// in strict XHTML attributes
+  static const HtmlEscapeMode attribute =
+      HtmlEscapeMode._('attribute', true, true, false, false);
+
+  /// Escaping mode for text going into single-quoted HTML attribute values.
+  ///
+  /// The result should not be used as the content of an unquoted
+  /// or double-quoted attribute value.
+  ///
+  /// Escapes single quotes (`'`) but not double quotes (`"`),
+  /// and escapes `<` and `>` characters because they are not allowed
+  /// in strict XHTML attributes
+  static const HtmlEscapeMode sqAttribute =
+      HtmlEscapeMode._('attribute', true, false, true, false);
+
+  /// Escaping mode for text going into HTML element content.
+  ///
+  /// The escaping only works for elements with normal HTML content,
+  /// and not for, for example, script or style element content,
+  /// which require escapes matching their particular content syntax.
+  ///
+  /// Escapes `<` and `>` characters.
+  static const HtmlEscapeMode element =
+      HtmlEscapeMode._('element', true, false, false, false);
+
+  const HtmlEscapeMode._(this._name, this.escapeLtGt, this.escapeQuot,
+      this.escapeApos, this.escapeSlash);
+
+  /// Create a custom escaping mode.
+  ///
+  /// All modes escape `&`.
+  /// The mode can further be set to escape `<` and `>` ([escapeLtGt]),
+  /// `"` ([escapeQuot]), `'` ([escapeApos]), and/or `/` ([escapeSlash]).
+  const HtmlEscapeMode(
+      {String name = "custom",
+      this.escapeLtGt = false,
+      this.escapeQuot = false,
+      this.escapeApos = false,
+      this.escapeSlash = false})
+      : _name = name;
+
+  String toString() => _name;
+}
+
+/// Converter which escapes characters with special meaning in HTML.
+///
+/// The converter finds characters that are significant in HTML source and
+/// replaces them with corresponding HTML entities.
+///
+/// The characters that need escaping in HTML are:
+///
+/// * `&` (ampersand) always need to be escaped.
+/// * `<` (less than) and '>' (greater than) when inside an element.
+/// * `"` (quote) when inside a double-quoted attribute value.
+/// * `'` (apostrophe) when inside a single-quoted attribute value.
+///       Apostrophe is escaped as `&#39;` instead of `&apos;` since
+///       not all browsers understand `&apos;`.
+/// * `/` (slash) is recommended to be escaped because it may be used
+///       to terminate an element in some HTML dialects.
+///
+/// Escaping `>` (greater than) isn't necessary, but the result is often
+/// found to be easier to read if greater-than is also escaped whenever
+/// less-than is.
+class HtmlEscape extends Converter<String, String> {
+  /// The [HtmlEscapeMode] used by the converter.
+  final HtmlEscapeMode mode;
+
+  /// Create converter that escapes HTML characters.
+  ///
+  /// If [mode] is provided as either [HtmlEscapeMode.attribute] or
+  /// [HtmlEscapeMode.element], only the corresponding subset of HTML
+  /// characters are escaped.
+  /// The default is to escape all HTML characters.
+  const HtmlEscape([this.mode = HtmlEscapeMode.unknown]);
+
+  String convert(String text) {
+    var val = _convert(text, 0, text.length);
+    return val == null ? text : val;
+  }
+
+  /// Converts the substring of text from start to end.
+  ///
+  /// Returns `null` if no changes were necessary, otherwise returns
+  /// the converted string.
+  String _convert(String text, int start, int end) {
+    StringBuffer result;
+    for (var i = start; i < end; i++) {
+      var ch = text[i];
+      String replacement;
+      switch (ch) {
+        case '&':
+          replacement = '&amp;';
+          break;
+        case '"':
+          if (mode.escapeQuot) replacement = '&quot;';
+          break;
+        case "'":
+          if (mode.escapeApos) replacement = '&#39;';
+          break;
+        case '<':
+          if (mode.escapeLtGt) replacement = '&lt;';
+          break;
+        case '>':
+          if (mode.escapeLtGt) replacement = '&gt;';
+          break;
+        case '/':
+          if (mode.escapeSlash) replacement = '&#47;';
+          break;
+      }
+      if (replacement != null) {
+        result ??= StringBuffer();
+        if (i > start) result.write(text.substring(start, i));
+        result.write(replacement);
+        start = i + 1;
+      }
+    }
+    if (result == null) return null;
+    if (end > start) result.write(text.substring(start, end));
+    return result.toString();
+  }
+
+  StringConversionSink startChunkedConversion(Sink<String> sink) {
+    return _HtmlEscapeSink(this,
+        sink is StringConversionSink ? sink : StringConversionSink.from(sink));
+  }
+}
+
+class _HtmlEscapeSink extends StringConversionSinkBase {
+  final HtmlEscape _escape;
+  final StringConversionSink _sink;
+
+  _HtmlEscapeSink(this._escape, this._sink);
+
+  void addSlice(String chunk, int start, int end, bool isLast) {
+    var val = _escape._convert(chunk, start, end);
+    if (val == null) {
+      _sink.addSlice(chunk, start, end, isLast);
+    } else {
+      _sink.add(val);
+      if (isLast) _sink.close();
+    }
+  }
+
+  void close() {
+    _sink.close();
+  }
+}
diff --git a/sdk_nnbd/lib/convert/json.dart b/sdk_nnbd/lib/convert/json.dart
new file mode 100644
index 0000000..5746e52
--- /dev/null
+++ b/sdk_nnbd/lib/convert/json.dart
@@ -0,0 +1,1034 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.convert;
+
+/// Error thrown by JSON serialization if an object cannot be serialized.
+///
+/// The [unsupportedObject] field holds that object that failed to be serialized.
+///
+/// If an object isn't directly serializable, the serializer calls the `toJson`
+/// method on the object. If that call fails, the error will be stored in the
+/// [cause] field. If the call returns an object that isn't directly
+/// serializable, the [cause] is null.
+class JsonUnsupportedObjectError extends Error {
+  /// The object that could not be serialized.
+  final Object unsupportedObject;
+
+  /// The exception thrown when trying to convert the object.
+  final Object cause;
+
+  /// The partial result of the conversion, up until the error happened.
+  ///
+  /// May be null.
+  final String partialResult;
+
+  JsonUnsupportedObjectError(this.unsupportedObject,
+      {this.cause, this.partialResult});
+
+  String toString() {
+    var safeString = Error.safeToString(unsupportedObject);
+    String prefix;
+    if (cause != null) {
+      prefix = "Converting object to an encodable object failed:";
+    } else {
+      prefix = "Converting object did not return an encodable object:";
+    }
+    return "$prefix $safeString";
+  }
+}
+
+/// Reports that an object could not be stringified due to cyclic references.
+///
+/// An object that references itself cannot be serialized by
+/// [JsonCodec.encode]/[JsonEncoder.convert].
+/// When the cycle is detected, a [JsonCyclicError] is thrown.
+class JsonCyclicError extends JsonUnsupportedObjectError {
+  /// The first object that was detected as part of a cycle.
+  JsonCyclicError(Object object) : super(object);
+  String toString() => "Cyclic error in JSON stringify";
+}
+
+/// An instance of the default implementation of the [JsonCodec].
+///
+/// This instance provides a convenient access to the most common JSON
+/// use cases.
+///
+/// Examples:
+///
+///     var encoded = json.encode([1, 2, { "a": null }]);
+///     var decoded = json.decode('["foo", { "bar": 499 }]');
+///
+/// The top-level [jsonEncode] and [jsonDecode] functions may be used instead if
+/// a local variable shadows the [json] constant.
+const JsonCodec json = JsonCodec();
+
+/// Converts [value] to a JSON string.
+///
+/// If value contains objects that are not directly encodable to a JSON
+/// string (a value that is not a number, boolean, string, null, list or a map
+/// with string keys), the [toEncodable] function is used to convert it to an
+/// object that must be directly encodable.
+///
+/// If [toEncodable] is omitted, it defaults to a function that returns the
+/// result of calling `.toJson()` on the unencodable object.
+///
+/// Shorthand for [json.encode]. Useful if a local variable shadows the global
+/// [json] constant.
+String jsonEncode(Object object, {Object toEncodable(Object nonEncodable)}) =>
+    json.encode(object, toEncodable: toEncodable);
+
+/// Parses the string and returns the resulting Json object.
+///
+/// The optional [reviver] function is called once for each object or list
+/// property that has been parsed during decoding. The `key` argument is either
+/// the integer list index for a list property, the string map key for object
+/// properties, or `null` for the final result.
+///
+/// The default [reviver] (when not provided) is the identity function.
+///
+/// Shorthand for [json.decode]. Useful if a local variable shadows the global
+/// [json] constant.
+dynamic jsonDecode(String source, {Object reviver(Object key, Object value)}) =>
+    json.decode(source, reviver: reviver);
+
+/// A [JsonCodec] encodes JSON objects to strings and decodes strings to
+/// JSON objects.
+///
+/// Examples:
+///
+///     var encoded = json.encode([1, 2, { "a": null }]);
+///     var decoded = json.decode('["foo", { "bar": 499 }]');
+class JsonCodec extends Codec<Object, String> {
+  final Function(Object key, Object value) _reviver;
+  final Function(dynamic) _toEncodable;
+
+  /// Creates a `JsonCodec` with the given reviver and encoding function.
+  ///
+  /// The [reviver] function is called during decoding. It is invoked once for
+  /// each object or list property that has been parsed.
+  /// The `key` argument is either the integer list index for a list property,
+  /// the string map key for object properties, or `null` for the final result.
+  ///
+  /// If [reviver] is omitted, it defaults to returning the value argument.
+  ///
+  /// The [toEncodable] function is used during encoding. It is invoked for
+  /// values that are not directly encodable to a string (a value that is not a
+  /// number, boolean, string, null, list or a map with string keys). The
+  /// function must return an object that is directly encodable. The elements of
+  /// a returned list and values of a returned map do not need to be directly
+  /// encodable, and if they aren't, `toEncodable` will be used on them as well.
+  /// Please notice that it is possible to cause an infinite recursive regress
+  /// in this way, by effectively creating an infinite data structure through
+  /// repeated call to `toEncodable`.
+  ///
+  /// If [toEncodable] is omitted, it defaults to a function that returns the
+  /// result of calling `.toJson()` on the unencodable object.
+  const JsonCodec({reviver(Object key, Object value), toEncodable(var object)})
+      : _reviver = reviver,
+        _toEncodable = toEncodable;
+
+  /// Creates a `JsonCodec` with the given reviver.
+  ///
+  /// The [reviver] function is called once for each object or list property
+  /// that has been parsed during decoding. The `key` argument is either the
+  /// integer list index for a list property, the string map key for object
+  /// properties, or `null` for the final result.
+  JsonCodec.withReviver(reviver(Object key, Object value))
+      : this(reviver: reviver);
+
+  /// Parses the string and returns the resulting Json object.
+  ///
+  /// The optional [reviver] function is called once for each object or list
+  /// property that has been parsed during decoding. The `key` argument is either
+  /// the integer list index for a list property, the string map key for object
+  /// properties, or `null` for the final result.
+  ///
+  /// The default [reviver] (when not provided) is the identity function.
+  dynamic decode(String source, {reviver(Object key, Object value)}) {
+    reviver ??= _reviver;
+    if (reviver == null) return decoder.convert(source);
+    return JsonDecoder(reviver).convert(source);
+  }
+
+  /// Converts [value] to a JSON string.
+  ///
+  /// If value contains objects that are not directly encodable to a JSON
+  /// string (a value that is not a number, boolean, string, null, list or a map
+  /// with string keys), the [toEncodable] function is used to convert it to an
+  /// object that must be directly encodable.
+  ///
+  /// If [toEncodable] is omitted, it defaults to a function that returns the
+  /// result of calling `.toJson()` on the unencodable object.
+  String encode(Object value, {toEncodable(object)}) {
+    toEncodable ??= _toEncodable;
+    if (toEncodable == null) return encoder.convert(value);
+    return JsonEncoder(toEncodable).convert(value);
+  }
+
+  JsonEncoder get encoder {
+    if (_toEncodable == null) return const JsonEncoder();
+    return JsonEncoder(_toEncodable);
+  }
+
+  JsonDecoder get decoder {
+    if (_reviver == null) return const JsonDecoder();
+    return JsonDecoder(_reviver);
+  }
+}
+
+/// This class converts JSON objects to strings.
+class JsonEncoder extends Converter<Object, String> {
+  /// The string used for indention.
+  ///
+  /// When generating multi-line output, this string is inserted once at the
+  /// beginning of each indented line for each level of indentation.
+  ///
+  /// If `null`, the output is encoded as a single line.
+  final String indent;
+
+  /// Function called on non-encodable objects to return a replacement
+  /// encodable object that will be encoded in the orignal's place.
+  final Function(dynamic) _toEncodable;
+
+  /// Creates a JSON encoder.
+  ///
+  /// The JSON encoder handles numbers, strings, booleans, null, lists and
+  /// maps with string keys directly.
+  ///
+  /// Any other object is attempted converted by [toEncodable] to an
+  /// object that is of one of the convertible types.
+  ///
+  /// If [toEncodable] is omitted, it defaults to calling `.toJson()` on
+  /// the object.
+  const JsonEncoder([toEncodable(object)])
+      : indent = null,
+        _toEncodable = toEncodable;
+
+  /// Creates a JSON encoder that creates multi-line JSON.
+  ///
+  /// The encoding of elements of lists and maps are indented and put on separate
+  /// lines. The [indent] string is prepended to these elements, once for each
+  /// level of indentation.
+  ///
+  /// If [indent] is `null`, the output is encoded as a single line.
+  ///
+  /// The JSON encoder handles numbers, strings, booleans, null, lists and
+  /// maps with string keys directly.
+  ///
+  /// Any other object is attempted converted by [toEncodable] to an
+  /// object that is of one of the convertible types.
+  ///
+  /// If [toEncodable] is omitted, it defaults to calling `.toJson()` on
+  /// the object.
+  const JsonEncoder.withIndent(this.indent, [toEncodable(object)])
+      : _toEncodable = toEncodable;
+
+  /// Converts [object] to a JSON [String].
+  ///
+  /// Directly serializable values are [num], [String], [bool], and [Null], as
+  /// well as some [List] and [Map] values. For [List], the elements must all be
+  /// serializable. For [Map], the keys must be [String] and the values must be
+  /// serializable.
+  ///
+  /// If a value of any other type is attempted to be serialized, the
+  /// `toEncodable` function provided in the constructor is called with the value
+  /// as argument. The result, which must be a directly serializable value, is
+  /// serialized instead of the original value.
+  ///
+  /// If the conversion throws, or returns a value that is not directly
+  /// serializable, a [JsonUnsupportedObjectError] exception is thrown.
+  /// If the call throws, the error is caught and stored in the
+  /// [JsonUnsupportedObjectError]'s [:cause:] field.
+  ///
+  /// If a [List] or [Map] contains a reference to itself, directly or through
+  /// other lists or maps, it cannot be serialized and a [JsonCyclicError] is
+  /// thrown.
+  ///
+  /// [object] should not change during serialization.
+  ///
+  /// If an object is serialized more than once, [convert] may cache the text
+  /// for it. In other words, if the content of an object changes after it is
+  /// first serialized, the new values may not be reflected in the result.
+  String convert(Object object) =>
+      _JsonStringStringifier.stringify(object, _toEncodable, indent);
+
+  /// Starts a chunked conversion.
+  ///
+  /// The converter works more efficiently if the given [sink] is a
+  /// [StringConversionSink].
+  ///
+  /// Returns a chunked-conversion sink that accepts at most one object. It is
+  /// an error to invoke `add` more than once on the returned sink.
+  ChunkedConversionSink<Object> startChunkedConversion(Sink<String> sink) {
+    if (sink is _Utf8EncoderSink) {
+      return _JsonUtf8EncoderSink(
+          sink._sink,
+          _toEncodable,
+          JsonUtf8Encoder._utf8Encode(indent),
+          JsonUtf8Encoder._defaultBufferSize);
+    }
+    return _JsonEncoderSink(
+        sink is StringConversionSink ? sink : StringConversionSink.from(sink),
+        _toEncodable,
+        indent);
+  }
+
+  // Override the base class's bind, to provide a better type.
+  Stream<String> bind(Stream<Object> stream) => super.bind(stream);
+
+  Converter<Object, T> fuse<T>(Converter<String, T> other) {
+    if (other is Utf8Encoder && T is List<int>) {
+      // The instance check guarantees that `T` is (a subtype of) List<int>,
+      // but the static type system doesn't know that, and so we cast.
+      // Cast through dynamic to keep the cast implicit for builds using
+      // unchecked implicit casts.
+      return JsonUtf8Encoder(indent, _toEncodable) as dynamic;
+    }
+    return super.fuse<T>(other);
+  }
+}
+
+/// Encoder that encodes a single object as a UTF-8 encoded JSON string.
+///
+/// This encoder works equivalently to first converting the object to
+/// a JSON string, and then UTF-8 encoding the string, but without
+/// creating an intermediate string.
+class JsonUtf8Encoder extends Converter<Object, List<int>> {
+  /// Default buffer size used by the JSON-to-UTF-8 encoder.
+  static const int _defaultBufferSize = 256;
+  @deprecated
+  static const int DEFAULT_BUFFER_SIZE = _defaultBufferSize;
+
+  /// Indentation used in pretty-print mode, `null` if not pretty.
+  final List<int> _indent;
+
+  /// Function called with each un-encodable object encountered.
+  final Function(dynamic) _toEncodable;
+
+  /// UTF-8 buffer size.
+  final int _bufferSize;
+
+  /// Create converter.
+  ///
+  /// If [indent] is non-`null`, the converter attempts to "pretty-print" the
+  /// JSON, and uses `indent` as the indentation. Otherwise the result has no
+  /// whitespace outside of string literals.
+  /// If `indent` contains characters that are not valid JSON whitespace
+  /// characters, the result will not be valid JSON. JSON whitespace characters
+  /// are space (U+0020), tab (U+0009), line feed (U+000a) and carriage return
+  /// (U+000d) ([ECMA
+  /// 404](http://www.ecma-international.org/publications/standards/Ecma-404.htm)).
+  ///
+  /// The [bufferSize] is the size of the internal buffers used to collect
+  /// UTF-8 code units.
+  /// If using [startChunkedConversion], it will be the size of the chunks.
+  ///
+  /// The JSON encoder handles numbers, strings, booleans, null, lists and maps
+  /// directly.
+  ///
+  /// Any other object is attempted converted by [toEncodable] to an object that
+  /// is of one of the convertible types.
+  ///
+  /// If [toEncodable] is omitted, it defaults to calling `.toJson()` on the
+  /// object.
+  JsonUtf8Encoder(
+      [String indent, toEncodable(object), int bufferSize = _defaultBufferSize])
+      : _indent = _utf8Encode(indent),
+        _toEncodable = toEncodable,
+        _bufferSize = bufferSize;
+
+  static List<int> _utf8Encode(String string) {
+    if (string == null) return null;
+    if (string.isEmpty) return Uint8List(0);
+    checkAscii:
+    {
+      for (var i = 0; i < string.length; i++) {
+        if (string.codeUnitAt(i) >= 0x80) break checkAscii;
+      }
+      return string.codeUnits;
+    }
+    return utf8.encode(string);
+  }
+
+  /// Convert [object] into UTF-8 encoded JSON.
+  List<int> convert(Object object) {
+    var bytes = <List<int>>[];
+    // The `stringify` function always converts into chunks.
+    // Collect the chunks into the `bytes` list, then combine them afterwards.
+    void addChunk(Uint8List chunk, int start, int end) {
+      if (start > 0 || end < chunk.length) {
+        var length = end - start;
+        chunk =
+            Uint8List.view(chunk.buffer, chunk.offsetInBytes + start, length);
+      }
+      bytes.add(chunk);
+    }
+
+    _JsonUtf8Stringifier.stringify(
+        object, _indent, _toEncodable, _bufferSize, addChunk);
+    if (bytes.length == 1) return bytes[0];
+    var length = 0;
+    for (var i = 0; i < bytes.length; i++) {
+      length += bytes[i].length;
+    }
+    var result = Uint8List(length);
+    for (var i = 0, offset = 0; i < bytes.length; i++) {
+      var byteList = bytes[i];
+      int end = offset + byteList.length;
+      result.setRange(offset, end, byteList);
+      offset = end;
+    }
+    return result;
+  }
+
+  /// Start a chunked conversion.
+  ///
+  /// Only one object can be passed into the returned sink.
+  ///
+  /// The argument [sink] will receive byte lists in sizes depending on the
+  /// `bufferSize` passed to the constructor when creating this encoder.
+  ChunkedConversionSink<Object> startChunkedConversion(Sink<List<int>> sink) {
+    ByteConversionSink byteSink;
+    if (sink is ByteConversionSink) {
+      byteSink = sink;
+    } else {
+      byteSink = ByteConversionSink.from(sink);
+    }
+    return _JsonUtf8EncoderSink(byteSink, _toEncodable, _indent, _bufferSize);
+  }
+
+  // Override the base class's bind, to provide a better type.
+  Stream<List<int>> bind(Stream<Object> stream) {
+    return super.bind(stream);
+  }
+}
+
+/// Implements the chunked conversion from object to its JSON representation.
+///
+/// The sink only accepts one value, but will produce output in a chunked way.
+class _JsonEncoderSink extends ChunkedConversionSink<Object> {
+  final String _indent;
+  final Function(dynamic) _toEncodable;
+  final StringConversionSink _sink;
+  bool _isDone = false;
+
+  _JsonEncoderSink(this._sink, this._toEncodable, this._indent);
+
+  /// Encodes the given object [o].
+  ///
+  /// It is an error to invoke this method more than once on any instance. While
+  /// this makes the input effectively non-chunked the output will be generated
+  /// in a chunked way.
+  void add(Object o) {
+    if (_isDone) {
+      throw StateError("Only one call to add allowed");
+    }
+    _isDone = true;
+    var stringSink = _sink.asStringSink();
+    _JsonStringStringifier.printOn(o, stringSink, _toEncodable, _indent);
+    stringSink.close();
+  }
+
+  void close() {/* do nothing */}
+}
+
+/// Sink returned when starting a chunked conversion from object to bytes.
+class _JsonUtf8EncoderSink extends ChunkedConversionSink<Object> {
+  /// The byte sink receiveing the encoded chunks.
+  final ByteConversionSink _sink;
+  final List<int> _indent;
+  final Function(dynamic) _toEncodable;
+  final int _bufferSize;
+  bool _isDone = false;
+  _JsonUtf8EncoderSink(
+      this._sink, this._toEncodable, this._indent, this._bufferSize);
+
+  /// Callback called for each slice of result bytes.
+  void _addChunk(Uint8List chunk, int start, int end) {
+    _sink.addSlice(chunk, start, end, false);
+  }
+
+  void add(Object object) {
+    if (_isDone) {
+      throw StateError("Only one call to add allowed");
+    }
+    _isDone = true;
+    _JsonUtf8Stringifier.stringify(
+        object, _indent, _toEncodable, _bufferSize, _addChunk);
+    _sink.close();
+  }
+
+  void close() {
+    if (!_isDone) {
+      _isDone = true;
+      _sink.close();
+    }
+  }
+}
+
+/// This class parses JSON strings and builds the corresponding objects.
+class JsonDecoder extends Converter<String, Object> {
+  final Function(Object key, Object value) _reviver;
+
+  /// Constructs a new JsonDecoder.
+  ///
+  /// The [reviver] may be `null`.
+  const JsonDecoder([reviver(Object key, Object value)]) : _reviver = reviver;
+
+  /// Converts the given JSON-string [input] to its corresponding object.
+  ///
+  /// Parsed JSON values are of the types [num], [String], [bool], [Null],
+  /// [List]s of parsed JSON values or [Map]s from [String] to parsed JSON
+  /// values.
+  ///
+  /// If `this` was initialized with a reviver, then the parsing operation
+  /// invokes the reviver on every object or list property that has been parsed.
+  /// The arguments are the property name ([String]) or list index ([int]), and
+  /// the value is the parsed value. The return value of the reviver is used as
+  /// the value of that property instead the parsed value.
+  ///
+  /// Throws [FormatException] if the input is not valid JSON text.
+  dynamic convert(String input) => _parseJson(input, _reviver);
+
+  /// Starts a conversion from a chunked JSON string to its corresponding object.
+  ///
+  /// The output [sink] receives exactly one decoded element through `add`.
+  external StringConversionSink startChunkedConversion(Sink<Object> sink);
+
+  // Override the base class's bind, to provide a better type.
+  Stream<Object> bind(Stream<String> stream) => super.bind(stream);
+}
+
+// Internal optimized JSON parsing implementation.
+external _parseJson(String source, reviver(key, value));
+
+// Implementation of encoder/stringifier.
+
+dynamic _defaultToEncodable(dynamic object) => object.toJson();
+
+/// JSON encoder that traverses an object structure and writes JSON source.
+///
+/// This is an abstract implementation that doesn't decide on the output
+/// format, but writes the JSON through abstract methods like [writeString].
+abstract class _JsonStringifier {
+  // Character code constants.
+  static const int backspace = 0x08;
+  static const int tab = 0x09;
+  static const int newline = 0x0a;
+  static const int carriageReturn = 0x0d;
+  static const int formFeed = 0x0c;
+  static const int quote = 0x22;
+  static const int char_0 = 0x30;
+  static const int backslash = 0x5c;
+  static const int char_b = 0x62;
+  static const int char_f = 0x66;
+  static const int char_n = 0x6e;
+  static const int char_r = 0x72;
+  static const int char_t = 0x74;
+  static const int char_u = 0x75;
+
+  /// List of objects currently being traversed. Used to detect cycles.
+  final List _seen = [];
+
+  /// Function called for each un-encodable object encountered.
+  final Function(dynamic) _toEncodable;
+
+  _JsonStringifier(toEncodable(o))
+      : _toEncodable = toEncodable ?? _defaultToEncodable;
+
+  String get _partialResult;
+
+  /// Append a string to the JSON output.
+  void writeString(String characters);
+
+  /// Append part of a string to the JSON output.
+  void writeStringSlice(String characters, int start, int end);
+
+  /// Append a single character, given by its code point, to the JSON output.
+  void writeCharCode(int charCode);
+
+  /// Write a number to the JSON output.
+  void writeNumber(num number);
+
+  // ('0' + x) or ('a' + x - 10)
+  static int hexDigit(int x) => x < 10 ? 48 + x : 87 + x;
+
+  /// Write, and suitably escape, a string's content as a JSON string literal.
+  void writeStringContent(String s) {
+    var offset = 0;
+    final length = s.length;
+    for (var i = 0; i < length; i++) {
+      var charCode = s.codeUnitAt(i);
+      if (charCode > backslash) continue;
+      if (charCode < 32) {
+        if (i > offset) writeStringSlice(s, offset, i);
+        offset = i + 1;
+        writeCharCode(backslash);
+        switch (charCode) {
+          case backspace:
+            writeCharCode(char_b);
+            break;
+          case tab:
+            writeCharCode(char_t);
+            break;
+          case newline:
+            writeCharCode(char_n);
+            break;
+          case formFeed:
+            writeCharCode(char_f);
+            break;
+          case carriageReturn:
+            writeCharCode(char_r);
+            break;
+          default:
+            writeCharCode(char_u);
+            writeCharCode(char_0);
+            writeCharCode(char_0);
+            writeCharCode(hexDigit((charCode >> 4) & 0xf));
+            writeCharCode(hexDigit(charCode & 0xf));
+            break;
+        }
+      } else if (charCode == quote || charCode == backslash) {
+        if (i > offset) writeStringSlice(s, offset, i);
+        offset = i + 1;
+        writeCharCode(backslash);
+        writeCharCode(charCode);
+      }
+    }
+    if (offset == 0) {
+      writeString(s);
+    } else if (offset < length) {
+      writeStringSlice(s, offset, length);
+    }
+  }
+
+  /// Check if an encountered object is already being traversed.
+  ///
+  /// Records the object if it isn't already seen. Should have a matching call to
+  /// [_removeSeen] when the object is no longer being traversed.
+  void _checkCycle(object) {
+    for (var i = 0; i < _seen.length; i++) {
+      if (identical(object, _seen[i])) {
+        throw JsonCyclicError(object);
+      }
+    }
+    _seen.add(object);
+  }
+
+  /// Remove [object] from the list of currently traversed objects.
+  ///
+  /// Should be called in the opposite order of the matching [_checkCycle]
+  /// calls.
+  void _removeSeen(object) {
+    assert(_seen.isNotEmpty);
+    assert(identical(_seen.last, object));
+    _seen.removeLast();
+  }
+
+  /// Write an object.
+  ///
+  /// If [object] isn't directly encodable, the [_toEncodable] function gets one
+  /// chance to return a replacement which is encodable.
+  void writeObject(object) {
+    // Tries stringifying object directly. If it's not a simple value, List or
+    // Map, call toJson() to get a custom representation and try serializing
+    // that.
+    if (writeJsonValue(object)) return;
+    _checkCycle(object);
+    try {
+      var customJson = _toEncodable(object);
+      if (!writeJsonValue(customJson)) {
+        throw JsonUnsupportedObjectError(object, partialResult: _partialResult);
+      }
+      _removeSeen(object);
+    } catch (e) {
+      throw JsonUnsupportedObjectError(object,
+          cause: e, partialResult: _partialResult);
+    }
+  }
+
+  /// Serialize a [num], [String], [bool], [Null], [List] or [Map] value.
+  ///
+  /// Returns true if the value is one of these types, and false if not.
+  /// If a value is both a [List] and a [Map], it's serialized as a [List].
+  bool writeJsonValue(object) {
+    if (object is num) {
+      if (!object.isFinite) return false;
+      writeNumber(object);
+      return true;
+    } else if (identical(object, true)) {
+      writeString('true');
+      return true;
+    } else if (identical(object, false)) {
+      writeString('false');
+      return true;
+    } else if (object == null) {
+      writeString('null');
+      return true;
+    } else if (object is String) {
+      writeString('"');
+      writeStringContent(object);
+      writeString('"');
+      return true;
+    } else if (object is List) {
+      _checkCycle(object);
+      writeList(object);
+      _removeSeen(object);
+      return true;
+    } else if (object is Map) {
+      _checkCycle(object);
+      // writeMap can fail if keys are not all strings.
+      var success = writeMap(object);
+      _removeSeen(object);
+      return success;
+    } else {
+      return false;
+    }
+  }
+
+  /// Serialize a [List].
+  void writeList(List list) {
+    writeString('[');
+    if (list.isNotEmpty) {
+      writeObject(list[0]);
+      for (var i = 1; i < list.length; i++) {
+        writeString(',');
+        writeObject(list[i]);
+      }
+    }
+    writeString(']');
+  }
+
+  /// Serialize a [Map].
+  bool writeMap(Map map) {
+    if (map.isEmpty) {
+      writeString("{}");
+      return true;
+    }
+    var keyValueList = List(map.length * 2);
+    var i = 0;
+    var allStringKeys = true;
+    map.forEach((key, value) {
+      if (key is! String) {
+        allStringKeys = false;
+      }
+      keyValueList[i++] = key;
+      keyValueList[i++] = value;
+    });
+    if (!allStringKeys) return false;
+    writeString('{');
+    var separator = '"';
+    for (var i = 0; i < keyValueList.length; i += 2) {
+      writeString(separator);
+      separator = ',"';
+      writeStringContent(keyValueList[i]);
+      writeString('":');
+      writeObject(keyValueList[i + 1]);
+    }
+    writeString('}');
+    return true;
+  }
+}
+
+/// A modification of [_JsonStringifier] which indents the contents of [List] and
+/// [Map] objects using the specified indent value.
+///
+/// Subclasses should implement [writeIndentation].
+abstract class _JsonPrettyPrintMixin implements _JsonStringifier {
+  int _indentLevel = 0;
+
+  /// Add [indentLevel] indentations to the JSON output.
+  void writeIndentation(int indentLevel);
+
+  void writeList(List list) {
+    if (list.isEmpty) {
+      writeString('[]');
+    } else {
+      writeString('[\n');
+      _indentLevel++;
+      writeIndentation(_indentLevel);
+      writeObject(list[0]);
+      for (var i = 1; i < list.length; i++) {
+        writeString(',\n');
+        writeIndentation(_indentLevel);
+        writeObject(list[i]);
+      }
+      writeString('\n');
+      _indentLevel--;
+      writeIndentation(_indentLevel);
+      writeString(']');
+    }
+  }
+
+  bool writeMap(Map map) {
+    if (map.isEmpty) {
+      writeString("{}");
+      return true;
+    }
+    var keyValueList = List(map.length * 2);
+    var i = 0;
+    var allStringKeys = true;
+    map.forEach((key, value) {
+      if (key is! String) {
+        allStringKeys = false;
+      }
+      keyValueList[i++] = key;
+      keyValueList[i++] = value;
+    });
+    if (!allStringKeys) return false;
+    writeString('{\n');
+    _indentLevel++;
+    var separator = "";
+    for (var i = 0; i < keyValueList.length; i += 2) {
+      writeString(separator);
+      separator = ",\n";
+      writeIndentation(_indentLevel);
+      writeString('"');
+      writeStringContent(keyValueList[i]);
+      writeString('": ');
+      writeObject(keyValueList[i + 1]);
+    }
+    writeString('\n');
+    _indentLevel--;
+    writeIndentation(_indentLevel);
+    writeString('}');
+    return true;
+  }
+}
+
+/// A specialization of [_JsonStringifier] that writes its JSON to a string.
+class _JsonStringStringifier extends _JsonStringifier {
+  final StringSink _sink;
+
+  _JsonStringStringifier(this._sink, dynamic Function(dynamic) _toEncodable)
+      : super(_toEncodable);
+
+  /// Convert object to a string.
+  ///
+  /// The [toEncodable] function is used to convert non-encodable objects
+  /// to encodable ones.
+  ///
+  /// If [indent] is not `null`, the resulting JSON will be "pretty-printed"
+  /// with newlines and indentation. The `indent` string is added as indentation
+  /// for each indentation level. It should only contain valid JSON whitespace
+  /// characters (space, tab, carriage return or line feed).
+  static String stringify(object, toEncodable(o), String indent) {
+    var output = StringBuffer();
+    printOn(object, output, toEncodable, indent);
+    return output.toString();
+  }
+
+  /// Convert object to a string, and write the result to the [output] sink.
+  ///
+  /// The result is written piecemally to the sink.
+  static void printOn(
+      object, StringSink output, toEncodable(o), String indent) {
+    _JsonStringifier stringifier;
+    if (indent == null) {
+      stringifier = _JsonStringStringifier(output, toEncodable);
+    } else {
+      stringifier = _JsonStringStringifierPretty(output, toEncodable, indent);
+    }
+    stringifier.writeObject(object);
+  }
+
+  String get _partialResult => _sink is StringBuffer ? _sink.toString() : null;
+
+  void writeNumber(num number) {
+    _sink.write(number.toString());
+  }
+
+  void writeString(String string) {
+    _sink.write(string);
+  }
+
+  void writeStringSlice(String string, int start, int end) {
+    _sink.write(string.substring(start, end));
+  }
+
+  void writeCharCode(int charCode) {
+    _sink.writeCharCode(charCode);
+  }
+}
+
+class _JsonStringStringifierPretty extends _JsonStringStringifier
+    with _JsonPrettyPrintMixin {
+  final String _indent;
+
+  _JsonStringStringifierPretty(StringSink sink, toEncodable(o), this._indent)
+      : super(sink, toEncodable);
+
+  void writeIndentation(int count) {
+    for (var i = 0; i < count; i++) writeString(_indent);
+  }
+}
+
+/// Specialization of [_JsonStringifier] that writes the JSON as UTF-8.
+///
+/// The JSON text is UTF-8 encoded and written to [Uint8List] buffers.
+/// The buffers are then passed back to a user provided callback method.
+class _JsonUtf8Stringifier extends _JsonStringifier {
+  final int bufferSize;
+  final void Function(Uint8List list, int start, int end) addChunk;
+  Uint8List buffer;
+  int index = 0;
+
+  _JsonUtf8Stringifier(toEncodable(o), this.bufferSize, this.addChunk)
+      : buffer = Uint8List(bufferSize),
+        super(toEncodable);
+
+  /// Convert [object] to UTF-8 encoded JSON.
+  ///
+  /// Calls [addChunk] with slices of UTF-8 code units.
+  /// These will typically have size [bufferSize], but may be shorter.
+  /// The buffers are not reused, so the [addChunk] call may keep and reuse the
+  /// chunks.
+  ///
+  /// If [indent] is non-`null`, the result will be "pretty-printed" with extra
+  /// newlines and indentation, using [indent] as the indentation.
+  static void stringify(Object object, List<int> indent, toEncodable(o),
+      int bufferSize, void addChunk(Uint8List chunk, int start, int end)) {
+    _JsonUtf8Stringifier stringifier;
+    if (indent != null) {
+      stringifier =
+          _JsonUtf8StringifierPretty(toEncodable, indent, bufferSize, addChunk);
+    } else {
+      stringifier = _JsonUtf8Stringifier(toEncodable, bufferSize, addChunk);
+    }
+    stringifier.writeObject(object);
+    stringifier.flush();
+  }
+
+  /// Must be called at the end to push the last chunk to the [addChunk]
+  /// callback.
+  void flush() {
+    if (index > 0) {
+      addChunk(buffer, 0, index);
+    }
+    buffer = null;
+    index = 0;
+  }
+
+  String get _partialResult => null;
+
+  void writeNumber(num number) {
+    writeAsciiString(number.toString());
+  }
+
+  /// Write a string that is known to not have non-ASCII characters.
+  void writeAsciiString(String string) {
+    // TODO(lrn): Optimize by copying directly into buffer instead of going
+    // through writeCharCode;
+    for (var i = 0; i < string.length; i++) {
+      var char = string.codeUnitAt(i);
+      assert(char <= 0x7f);
+      writeByte(char);
+    }
+  }
+
+  void writeString(String string) {
+    writeStringSlice(string, 0, string.length);
+  }
+
+  void writeStringSlice(String string, int start, int end) {
+    // TODO(lrn): Optimize by copying directly into buffer instead of going
+    // through writeCharCode/writeByte. Assumption is the most characters
+    // in starings are plain ASCII.
+    for (var i = start; i < end; i++) {
+      var char = string.codeUnitAt(i);
+      if (char <= 0x7f) {
+        writeByte(char);
+      } else {
+        if ((char & 0xFC00) == 0xD800 && i + 1 < end) {
+          // Lead surrogate.
+          var nextChar = string.codeUnitAt(i + 1);
+          if ((nextChar & 0xFC00) == 0xDC00) {
+            // Tail surrogate.
+            char = 0x10000 + ((char & 0x3ff) << 10) + (nextChar & 0x3ff);
+            writeFourByteCharCode(char);
+            i++;
+            continue;
+          }
+        }
+        writeMultiByteCharCode(char);
+      }
+    }
+  }
+
+  void writeCharCode(int charCode) {
+    if (charCode <= 0x7f) {
+      writeByte(charCode);
+      return;
+    }
+    writeMultiByteCharCode(charCode);
+  }
+
+  void writeMultiByteCharCode(int charCode) {
+    if (charCode <= 0x7ff) {
+      writeByte(0xC0 | (charCode >> 6));
+      writeByte(0x80 | (charCode & 0x3f));
+      return;
+    }
+    if (charCode <= 0xffff) {
+      writeByte(0xE0 | (charCode >> 12));
+      writeByte(0x80 | ((charCode >> 6) & 0x3f));
+      writeByte(0x80 | (charCode & 0x3f));
+      return;
+    }
+    writeFourByteCharCode(charCode);
+  }
+
+  void writeFourByteCharCode(int charCode) {
+    assert(charCode <= 0x10ffff);
+    writeByte(0xF0 | (charCode >> 18));
+    writeByte(0x80 | ((charCode >> 12) & 0x3f));
+    writeByte(0x80 | ((charCode >> 6) & 0x3f));
+    writeByte(0x80 | (charCode & 0x3f));
+  }
+
+  void writeByte(int byte) {
+    assert(byte <= 0xff);
+    if (index == buffer.length) {
+      addChunk(buffer, 0, index);
+      buffer = Uint8List(bufferSize);
+      index = 0;
+    }
+    buffer[index++] = byte;
+  }
+}
+
+/// Pretty-printing version of [_JsonUtf8Stringifier].
+class _JsonUtf8StringifierPretty extends _JsonUtf8Stringifier
+    with _JsonPrettyPrintMixin {
+  final List<int> indent;
+  _JsonUtf8StringifierPretty(toEncodable(o), this.indent, int bufferSize,
+      void addChunk(Uint8List buffer, int start, int end))
+      : super(toEncodable, bufferSize, addChunk);
+
+  void writeIndentation(int count) {
+    var indent = this.indent;
+    var indentLength = indent.length;
+    if (indentLength == 1) {
+      var char = indent[0];
+      while (count > 0) {
+        writeByte(char);
+        count -= 1;
+      }
+      return;
+    }
+    while (count > 0) {
+      count--;
+      var end = index + indentLength;
+      if (end <= buffer.length) {
+        buffer.setRange(index, end, indent);
+        index = end;
+      } else {
+        for (var i = 0; i < indentLength; i++) {
+          writeByte(indent[i]);
+        }
+      }
+    }
+  }
+}
diff --git a/sdk_nnbd/lib/convert/latin1.dart b/sdk_nnbd/lib/convert/latin1.dart
new file mode 100644
index 0000000..c22010c
--- /dev/null
+++ b/sdk_nnbd/lib/convert/latin1.dart
@@ -0,0 +1,182 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.convert;
+
+/// An instance of the default implementation of the [Latin1Codec].
+///
+/// This instance provides a convenient access to the most common ISO Latin 1
+/// use cases.
+///
+/// Examples:
+/// ```dart
+/// var encoded = latin1.encode("blåbærgrød");
+/// var decoded = latin1.decode([0x62, 0x6c, 0xe5, 0x62, 0xe6,
+///                              0x72, 0x67, 0x72, 0xf8, 0x64]);
+/// ```
+const Latin1Codec latin1 = Latin1Codec();
+
+const int _latin1Mask = 0xFF;
+
+/// A [Latin1Codec] encodes strings to ISO Latin-1 (aka ISO-8859-1) bytes
+/// and decodes Latin-1 bytes to strings.
+class Latin1Codec extends Encoding {
+  final bool _allowInvalid;
+
+  /// Instantiates a new [Latin1Codec].
+  ///
+  /// If [allowInvalid] is true, the [decode] method and the converter
+  /// returned by [decoder] will default to allowing invalid values. Invalid
+  /// values are decoded into the Unicode Replacement character (U+FFFD).
+  /// Calls to the [decode] method can override this default.
+  ///
+  /// Encoders will not accept invalid (non Latin-1) characters.
+  const Latin1Codec({bool allowInvalid = false}) : _allowInvalid = allowInvalid;
+
+  /// The name of this codec, "iso-8859-1".
+  String get name => "iso-8859-1";
+
+  Uint8List encode(String source) => encoder.convert(source);
+
+  /// Decodes the Latin-1 [bytes] (a list of unsigned 8-bit integers) to the
+  /// corresponding string.
+  ///
+  /// If [bytes] contains values that are not in the range 0 .. 255, the decoder
+  /// will eventually throw a [FormatException].
+  ///
+  /// If [allowInvalid] is not provided, it defaults to the value used to create
+  /// this [Latin1Codec].
+  String decode(List<int> bytes, {bool allowInvalid}) {
+    allowInvalid ??= _allowInvalid;
+    if (allowInvalid) {
+      return const Latin1Decoder(allowInvalid: true).convert(bytes);
+    } else {
+      return const Latin1Decoder(allowInvalid: false).convert(bytes);
+    }
+  }
+
+  Latin1Encoder get encoder => const Latin1Encoder();
+
+  Latin1Decoder get decoder => _allowInvalid
+      ? const Latin1Decoder(allowInvalid: true)
+      : const Latin1Decoder(allowInvalid: false);
+}
+
+/// This class converts strings of only ISO Latin-1 characters to bytes.
+class Latin1Encoder extends _UnicodeSubsetEncoder {
+  const Latin1Encoder() : super(_latin1Mask);
+}
+
+/// This class converts Latin-1 bytes (lists of unsigned 8-bit integers)
+/// to a string.
+class Latin1Decoder extends _UnicodeSubsetDecoder {
+  /// Instantiates a new [Latin1Decoder].
+  ///
+  /// The optional [allowInvalid] argument defines how [convert] deals
+  /// with invalid bytes.
+  ///
+  /// If it is `true`, [convert] replaces invalid bytes with the Unicode
+  /// Replacement character `U+FFFD` (�).
+  /// Otherwise it throws a [FormatException].
+  const Latin1Decoder({bool allowInvalid = false})
+      : super(allowInvalid, _latin1Mask);
+
+  /// Starts a chunked conversion.
+  ///
+  /// The converter works more efficiently if the given [sink] is a
+  /// [StringConversionSink].
+  ByteConversionSink startChunkedConversion(Sink<String> sink) {
+    StringConversionSink stringSink;
+    if (sink is StringConversionSink) {
+      stringSink = sink;
+    } else {
+      stringSink = StringConversionSink.from(sink);
+    }
+    // TODO(lrn): Use stringSink.asUtf16Sink() if it becomes available.
+    if (!_allowInvalid) return _Latin1DecoderSink(stringSink);
+    return _Latin1AllowInvalidDecoderSink(stringSink);
+  }
+}
+
+class _Latin1DecoderSink extends ByteConversionSinkBase {
+  StringConversionSink _sink;
+  _Latin1DecoderSink(this._sink);
+
+  void close() {
+    _sink.close();
+    _sink = null;
+  }
+
+  void add(List<int> source) {
+    addSlice(source, 0, source.length, false);
+  }
+
+  void _addSliceToSink(List<int> source, int start, int end, bool isLast) {
+    // If _sink was a UTF-16 conversion sink, just add the slice directly with
+    // _sink.addSlice(source, start, end, isLast).
+    // The code below is an moderately stupid workaround until a real
+    // solution can be made.
+    _sink.add(String.fromCharCodes(source, start, end));
+    if (isLast) close();
+  }
+
+  void addSlice(List<int> source, int start, int end, bool isLast) {
+    end = RangeError.checkValidRange(start, end, source.length);
+    if (start == end) return;
+    if (source is! Uint8List) {
+      // List may contain value outside of the 0..255 range. If so, throw.
+      // Technically, we could excuse Uint8ClampedList as well, but it unlikely
+      // to be relevant.
+      _checkValidLatin1(source, start, end);
+    }
+    _addSliceToSink(source, start, end, isLast);
+  }
+
+  static void _checkValidLatin1(List<int> source, int start, int end) {
+    var mask = 0;
+    for (var i = start; i < end; i++) {
+      mask |= source[i];
+    }
+    if (mask >= 0 && mask <= _latin1Mask) {
+      return;
+    }
+    _reportInvalidLatin1(source, start, end); // Always throws.
+  }
+
+  static void _reportInvalidLatin1(List<int> source, int start, int end) {
+    // Find the index of the first non-Latin-1 character code.
+    for (var i = start; i < end; i++) {
+      var char = source[i];
+      if (char < 0 || char > _latin1Mask) {
+        throw FormatException(
+            "Source contains non-Latin-1 characters.", source, i);
+      }
+    }
+    // Unreachable - we only call the function if the loop above throws.
+    assert(false);
+  }
+}
+
+class _Latin1AllowInvalidDecoderSink extends _Latin1DecoderSink {
+  _Latin1AllowInvalidDecoderSink(StringConversionSink sink) : super(sink);
+
+  void addSlice(List<int> source, int start, int end, bool isLast) {
+    RangeError.checkValidRange(start, end, source.length);
+    for (var i = start; i < end; i++) {
+      var char = source[i];
+      if (char > _latin1Mask || char < 0) {
+        if (i > start) _addSliceToSink(source, start, i, false);
+        // Add UTF-8 encoding of U+FFFD.
+        _addSliceToSink(const [0xFFFD], 0, 1, false);
+        start = i + 1;
+      }
+    }
+    if (start < end) {
+      _addSliceToSink(source, start, end, isLast);
+    }
+    if (isLast) {
+      close();
+    }
+  }
+}
diff --git a/sdk_nnbd/lib/convert/line_splitter.dart b/sdk_nnbd/lib/convert/line_splitter.dart
new file mode 100644
index 0000000..71be2c0
--- /dev/null
+++ b/sdk_nnbd/lib/convert/line_splitter.dart
@@ -0,0 +1,172 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.convert;
+
+// Character constants.
+const int _LF = 10;
+const int _CR = 13;
+
+/// A [StreamTransformer] that splits a [String] into individual lines.
+///
+/// A line is terminated by either a CR (U+000D), a LF (U+000A), a
+/// CR+LF sequence (DOS line ending),
+/// and a final non-empty line can be ended by the end of the string.
+///
+/// The returned lines do not contain the line terminators.
+
+class LineSplitter extends StreamTransformerBase<String, String> {
+  const LineSplitter();
+
+  /// Split [lines] into individual lines.
+  ///
+  /// If [start] and [end] are provided, only split the contents of
+  /// `lines.substring(start, end)`. The [start] and [end] values must
+  /// specify a valid sub-range of [lines]
+  /// (`0 <= start <= end <= lines.length`).
+  static Iterable<String> split(String lines, [int start = 0, int end]) sync* {
+    end = RangeError.checkValidRange(start, end, lines.length);
+    var sliceStart = start;
+    var char = 0;
+    for (var i = start; i < end; i++) {
+      var previousChar = char;
+      char = lines.codeUnitAt(i);
+      if (char != _CR) {
+        if (char != _LF) continue;
+        if (previousChar == _CR) {
+          sliceStart = i + 1;
+          continue;
+        }
+      }
+      yield lines.substring(sliceStart, i);
+      sliceStart = i + 1;
+    }
+    if (sliceStart < end) {
+      yield lines.substring(sliceStart, end);
+    }
+  }
+
+  List<String> convert(String data) {
+    var lines = <String>[];
+    var end = data.length;
+    var sliceStart = 0;
+    var char = 0;
+    for (var i = 0; i < end; i++) {
+      var previousChar = char;
+      char = data.codeUnitAt(i);
+      if (char != _CR) {
+        if (char != _LF) continue;
+        if (previousChar == _CR) {
+          sliceStart = i + 1;
+          continue;
+        }
+      }
+      lines.add(data.substring(sliceStart, i));
+      sliceStart = i + 1;
+    }
+    if (sliceStart < end) {
+      lines.add(data.substring(sliceStart, end));
+    }
+    return lines;
+  }
+
+  StringConversionSink startChunkedConversion(Sink<String> sink) {
+    return _LineSplitterSink(
+        sink is StringConversionSink ? sink : StringConversionSink.from(sink));
+  }
+
+  Stream<String> bind(Stream<String> stream) {
+    return Stream<String>.eventTransformed(
+        stream, (EventSink<String> sink) => _LineSplitterEventSink(sink));
+  }
+}
+
+// TODO(floitsch): deal with utf8.
+class _LineSplitterSink extends StringConversionSinkBase {
+  final StringConversionSink _sink;
+
+  /// The carry-over from the previous chunk.
+  ///
+  /// If the previous slice ended in a line without a line terminator,
+  /// then the next slice may continue the line.
+  String _carry;
+
+  /// Whether to skip a leading LF character from the next slice.
+  ///
+  /// If the previous slice ended on a CR character, a following LF
+  /// would be part of the same line termination, and should be ignored.
+  ///
+  /// Only `true` when [_carry] is `null`.
+  bool _skipLeadingLF = false;
+
+  _LineSplitterSink(this._sink);
+
+  void addSlice(String chunk, int start, int end, bool isLast) {
+    end = RangeError.checkValidRange(start, end, chunk.length);
+    // If the chunk is empty, it's probably because it's the last one.
+    // Handle that here, so we know the range is non-empty below.
+    if (start >= end) {
+      if (isLast) close();
+      return;
+    }
+    if (_carry != null) {
+      assert(!_skipLeadingLF);
+      chunk = _carry + chunk.substring(start, end);
+      start = 0;
+      end = chunk.length;
+      _carry = null;
+    } else if (_skipLeadingLF) {
+      if (chunk.codeUnitAt(start) == _LF) {
+        start += 1;
+      }
+      _skipLeadingLF = false;
+    }
+    _addLines(chunk, start, end);
+    if (isLast) close();
+  }
+
+  void close() {
+    if (_carry != null) {
+      _sink.add(_carry);
+      _carry = null;
+    }
+    _sink.close();
+  }
+
+  void _addLines(String lines, int start, int end) {
+    var sliceStart = start;
+    var char = 0;
+    for (var i = start; i < end; i++) {
+      var previousChar = char;
+      char = lines.codeUnitAt(i);
+      if (char != _CR) {
+        if (char != _LF) continue;
+        if (previousChar == _CR) {
+          sliceStart = i + 1;
+          continue;
+        }
+      }
+      _sink.add(lines.substring(sliceStart, i));
+      sliceStart = i + 1;
+    }
+    if (sliceStart < end) {
+      _carry = lines.substring(sliceStart, end);
+    } else {
+      _skipLeadingLF = (char == _CR);
+    }
+  }
+}
+
+class _LineSplitterEventSink extends _LineSplitterSink
+    implements EventSink<String> {
+  final EventSink<String> _eventSink;
+
+  _LineSplitterEventSink(EventSink<String> eventSink)
+      : _eventSink = eventSink,
+        super(StringConversionSink.from(eventSink));
+
+  void addError(Object o, [StackTrace stackTrace]) {
+    _eventSink.addError(o, stackTrace);
+  }
+}
diff --git a/sdk_nnbd/lib/convert/string_conversion.dart b/sdk_nnbd/lib/convert/string_conversion.dart
new file mode 100644
index 0000000..81e5621
--- /dev/null
+++ b/sdk_nnbd/lib/convert/string_conversion.dart
@@ -0,0 +1,318 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.convert;
+
+/// This class provides an interface for converters to
+/// efficiently transmit String data.
+///
+/// Instead of limiting the interface to one non-chunked String it accepts
+/// partial strings or can be transformed into a byte sink that
+/// accepts UTF-8 code units.
+///
+/// This abstract class will likely get more methods over time. Implementers are
+/// urged to extend [StringConversionSinkBase] or to mix in
+/// [StringConversionSinkMixin], to ensure that their class covers the newly
+/// added methods.
+abstract class StringConversionSink extends ChunkedConversionSink<String> {
+  StringConversionSink();
+  factory StringConversionSink.withCallback(void callback(String accumulated)) =
+      _StringCallbackSink;
+  factory StringConversionSink.from(Sink<String> sink) = _StringAdapterSink;
+
+  /// Creates a new instance wrapping the given [sink].
+  ///
+  /// Every string that is added to the returned instance is forwarded to
+  /// the [sink]. The instance is allowed to buffer and is not required to
+  /// forward immediately.
+  factory StringConversionSink.fromStringSink(StringSink sink) =
+      _StringSinkConversionSink<StringSink>;
+
+  /// Adds the next [chunk] to `this`.
+  ///
+  /// Adds the substring defined by [start] and [end]-exclusive to `this`.
+  ///
+  /// If [isLast] is `true` closes `this`.
+  void addSlice(String chunk, int start, int end, bool isLast);
+
+  /// Returns `this` as a sink that accepts UTF-8 input.
+  ///
+  /// If used, this method must be the first and only call to `this`. It
+  /// invalidates `this`. All further operations must be performed on the result.
+  ByteConversionSink asUtf8Sink(bool allowMalformed);
+  // - asRuneSink
+  // - asCodeUnitsSink
+
+  /// Returns `this` as a [ClosableStringSink].
+  ///
+  /// If used, this method must be the first and only call to `this`. It
+  /// invalidates `this`. All further operations must be performed on the result.
+  ClosableStringSink asStringSink();
+}
+
+/// A [ClosableStringSink] extends the [StringSink] interface by adding a
+/// `close` method.
+abstract class ClosableStringSink extends StringSink {
+  /// Creates a new instance combining a [StringSink] [sink] and a callback
+  /// [onClose] which is invoked when the returned instance is closed.
+  factory ClosableStringSink.fromStringSink(StringSink sink, void onClose()) =
+      _ClosableStringSink;
+
+  /// Closes `this` and flushes any outstanding data.
+  void close();
+}
+
+/// This class wraps an existing [StringSink] and invokes a
+/// closure when [close] is invoked.
+class _ClosableStringSink implements ClosableStringSink {
+  final void Function() _callback;
+  final StringSink _sink;
+
+  _ClosableStringSink(this._sink, this._callback);
+
+  void close() {
+    _callback();
+  }
+
+  void writeCharCode(int charCode) {
+    _sink.writeCharCode(charCode);
+  }
+
+  void write(Object o) {
+    _sink.write(o);
+  }
+
+  void writeln([Object o = ""]) {
+    _sink.writeln(o);
+  }
+
+  void writeAll(Iterable objects, [String separator = ""]) {
+    _sink.writeAll(objects, separator);
+  }
+}
+
+/// This class wraps an existing [StringConversionSink] and exposes a
+/// [ClosableStringSink] interface. The wrapped sink only needs to implement
+/// `add` and `close`.
+// TODO(floitsch): make this class public?
+class _StringConversionSinkAsStringSinkAdapter implements ClosableStringSink {
+  static const _MIN_STRING_SIZE = 16;
+
+  StringBuffer _buffer;
+  StringConversionSink _chunkedSink;
+
+  _StringConversionSinkAsStringSinkAdapter(this._chunkedSink)
+      : _buffer = StringBuffer();
+
+  void close() {
+    if (_buffer.isNotEmpty) _flush();
+    _chunkedSink.close();
+  }
+
+  void writeCharCode(int charCode) {
+    _buffer.writeCharCode(charCode);
+    if (_buffer.length > _MIN_STRING_SIZE) _flush();
+  }
+
+  void write(Object o) {
+    if (_buffer.isNotEmpty) _flush();
+    _chunkedSink.add(o.toString());
+  }
+
+  void writeln([Object o = ""]) {
+    _buffer.writeln(o);
+    if (_buffer.length > _MIN_STRING_SIZE) _flush();
+  }
+
+  void writeAll(Iterable objects, [String separator = ""]) {
+    if (_buffer.isNotEmpty) _flush();
+    var iterator = objects.iterator;
+    if (!iterator.moveNext()) return;
+    if (separator.isEmpty) {
+      do {
+        _chunkedSink.add(iterator.current.toString());
+      } while (iterator.moveNext());
+    } else {
+      _chunkedSink.add(iterator.current.toString());
+      while (iterator.moveNext()) {
+        write(separator);
+        _chunkedSink.add(iterator.current.toString());
+      }
+    }
+  }
+
+  void _flush() {
+    var accumulated = _buffer.toString();
+    _buffer.clear();
+    _chunkedSink.add(accumulated);
+  }
+}
+
+/// This class provides a base-class for converters that need to accept String
+/// inputs.
+abstract class StringConversionSinkBase extends StringConversionSinkMixin {}
+
+/// This class provides a mixin for converters that need to accept String
+/// inputs.
+abstract class StringConversionSinkMixin implements StringConversionSink {
+  void addSlice(String str, int start, int end, bool isLast);
+  void close();
+
+  void add(String str) {
+    addSlice(str, 0, str.length, false);
+  }
+
+  ByteConversionSink asUtf8Sink(bool allowMalformed) {
+    return _Utf8ConversionSink(this, allowMalformed);
+  }
+
+  ClosableStringSink asStringSink() {
+    return _StringConversionSinkAsStringSinkAdapter(this);
+  }
+}
+
+/// This class is a [StringConversionSink] that wraps a [StringSink].
+class _StringSinkConversionSink<TStringSink extends StringSink>
+    extends StringConversionSinkBase {
+  TStringSink _stringSink;
+  _StringSinkConversionSink(this._stringSink);
+
+  void close() {}
+  void addSlice(String str, int start, int end, bool isLast) {
+    if (start != 0 || end != str.length) {
+      for (var i = start; i < end; i++) {
+        _stringSink.writeCharCode(str.codeUnitAt(i));
+      }
+    } else {
+      _stringSink.write(str);
+    }
+    if (isLast) close();
+  }
+
+  void add(String str) {
+    _stringSink.write(str);
+  }
+
+  ByteConversionSink asUtf8Sink(bool allowMalformed) {
+    return _Utf8StringSinkAdapter(this, _stringSink, allowMalformed);
+  }
+
+  ClosableStringSink asStringSink() {
+    return ClosableStringSink.fromStringSink(_stringSink, close);
+  }
+}
+
+/// This class accumulates all chunks into one string
+/// and invokes a callback when the sink is closed.
+///
+/// This class can be used to terminate a chunked conversion.
+class _StringCallbackSink extends _StringSinkConversionSink<StringBuffer> {
+  final void Function(String) _callback;
+  _StringCallbackSink(this._callback) : super(StringBuffer());
+
+  void close() {
+    var accumulated = _stringSink.toString();
+    _stringSink.clear();
+    _callback(accumulated);
+  }
+
+  ByteConversionSink asUtf8Sink(bool allowMalformed) {
+    return _Utf8StringSinkAdapter(this, _stringSink, allowMalformed);
+  }
+}
+
+/// This class adapts a simple [ChunkedConversionSink] to a
+/// [StringConversionSink].
+///
+/// All additional methods of the [StringConversionSink] (compared to the
+/// ChunkedConversionSink) are redirected to the `add` method.
+class _StringAdapterSink extends StringConversionSinkBase {
+  final Sink<String> _sink;
+
+  _StringAdapterSink(this._sink);
+
+  void add(String str) {
+    _sink.add(str);
+  }
+
+  void addSlice(String str, int start, int end, bool isLast) {
+    if (start == 0 && end == str.length) {
+      add(str);
+    } else {
+      add(str.substring(start, end));
+    }
+    if (isLast) close();
+  }
+
+  void close() {
+    _sink.close();
+  }
+}
+
+/// Decodes UTF-8 code units and stores them in a [StringSink].
+class _Utf8StringSinkAdapter extends ByteConversionSink {
+  final _Utf8Decoder _decoder;
+  final Sink _sink;
+
+  _Utf8StringSinkAdapter(this._sink, StringSink stringSink, bool allowMalformed)
+      : _decoder = _Utf8Decoder(stringSink, allowMalformed);
+
+  void close() {
+    _decoder.close();
+    if (_sink != null) _sink.close();
+  }
+
+  void add(List<int> chunk) {
+    addSlice(chunk, 0, chunk.length, false);
+  }
+
+  void addSlice(
+      List<int> codeUnits, int startIndex, int endIndex, bool isLast) {
+    _decoder.convert(codeUnits, startIndex, endIndex);
+    if (isLast) close();
+  }
+}
+
+/// Decodes UTF-8 code units.
+///
+/// Forwards the decoded strings to the given [StringConversionSink].
+// TODO(floitsch): make this class public?
+class _Utf8ConversionSink extends ByteConversionSink {
+  final _Utf8Decoder _decoder;
+  final StringConversionSink _chunkedSink;
+  final StringBuffer _buffer;
+  _Utf8ConversionSink(StringConversionSink sink, bool allowMalformed)
+      : this._(sink, StringBuffer(), allowMalformed);
+
+  _Utf8ConversionSink._(
+      this._chunkedSink, StringBuffer stringBuffer, bool allowMalformed)
+      : _decoder = _Utf8Decoder(stringBuffer, allowMalformed),
+        _buffer = stringBuffer;
+
+  void close() {
+    _decoder.close();
+    if (_buffer.isNotEmpty) {
+      var accumulated = _buffer.toString();
+      _buffer.clear();
+      _chunkedSink.addSlice(accumulated, 0, accumulated.length, true);
+    } else {
+      _chunkedSink.close();
+    }
+  }
+
+  void add(List<int> chunk) {
+    addSlice(chunk, 0, chunk.length, false);
+  }
+
+  void addSlice(List<int> chunk, int startIndex, int endIndex, bool isLast) {
+    _decoder.convert(chunk, startIndex, endIndex);
+    if (_buffer.isNotEmpty) {
+      var accumulated = _buffer.toString();
+      _chunkedSink.addSlice(accumulated, 0, accumulated.length, isLast);
+      _buffer.clear();
+      return;
+    }
+    if (isLast) close();
+  }
+}
diff --git a/sdk_nnbd/lib/convert/utf.dart b/sdk_nnbd/lib/convert/utf.dart
new file mode 100644
index 0000000..39eb135
--- /dev/null
+++ b/sdk_nnbd/lib/convert/utf.dart
@@ -0,0 +1,556 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.convert;
+
+/// The Unicode Replacement character `U+FFFD` (�).
+const int unicodeReplacementCharacterRune = 0xFFFD;
+
+/// The Unicode Byte Order Marker (BOM) character `U+FEFF`.
+const int unicodeBomCharacterRune = 0xFEFF;
+
+/// An instance of the default implementation of the [Utf8Codec].
+///
+/// This instance provides a convenient access to the most common UTF-8
+/// use cases.
+///
+/// Examples:
+///
+///     var encoded = utf8.encode("Îñţérñåţîöñåļîžåţîờñ");
+///     var decoded = utf8.decode([0x62, 0x6c, 0xc3, 0xa5, 0x62, 0xc3, 0xa6,
+///                                0x72, 0x67, 0x72, 0xc3, 0xb8, 0x64]);
+const Utf8Codec utf8 = Utf8Codec();
+
+/// A [Utf8Codec] encodes strings to utf-8 code units (bytes) and decodes
+/// UTF-8 code units to strings.
+class Utf8Codec extends Encoding {
+  final bool _allowMalformed;
+
+  /// Instantiates a new [Utf8Codec].
+  ///
+  /// The optional [allowMalformed] argument defines how [decoder] (and [decode])
+  /// deal with invalid or unterminated character sequences.
+  ///
+  /// If it is `true` (and not overridden at the method invocation) [decode] and
+  /// the [decoder] replace invalid (or unterminated) octet
+  /// sequences with the Unicode Replacement character `U+FFFD` (�). Otherwise
+  /// they throw a [FormatException].
+  const Utf8Codec({bool allowMalformed = false})
+      : _allowMalformed = allowMalformed;
+
+  /// The name of this codec, "utf-8".
+  String get name => "utf-8";
+
+  /// Decodes the UTF-8 [codeUnits] (a list of unsigned 8-bit integers) to the
+  /// corresponding string.
+  ///
+  /// If the [codeUnits] start with the encoding of a
+  /// [unicodeBomCharacterRune], that character is discarded.
+  ///
+  /// If [allowMalformed] is `true` the decoder replaces invalid (or
+  /// unterminated) character sequences with the Unicode Replacement character
+  /// `U+FFFD` (�). Otherwise it throws a [FormatException].
+  ///
+  /// If [allowMalformed] is not given, it defaults to the `allowMalformed` that
+  /// was used to instantiate `this`.
+  String decode(List<int> codeUnits, {bool allowMalformed}) {
+    allowMalformed ??= _allowMalformed;
+    return Utf8Decoder(allowMalformed: allowMalformed).convert(codeUnits);
+  }
+
+  Utf8Encoder get encoder => const Utf8Encoder();
+  Utf8Decoder get decoder {
+    return Utf8Decoder(allowMalformed: _allowMalformed);
+  }
+}
+
+/// This class converts strings to their UTF-8 code units (a list of
+/// unsigned 8-bit integers).
+class Utf8Encoder extends Converter<String, List<int>> {
+  const Utf8Encoder();
+
+  /// Converts [string] to its UTF-8 code units (a list of
+  /// unsigned 8-bit integers).
+  ///
+  /// If [start] and [end] are provided, only the substring
+  /// `string.substring(start, end)` is converted.
+  Uint8List convert(String string, [int start = 0, int end]) {
+    var stringLength = string.length;
+    end = RangeError.checkValidRange(start, end, stringLength);
+    var length = end - start;
+    if (length == 0) return Uint8List(0);
+    // Create a new encoder with a length that is guaranteed to be big enough.
+    // A single code unit uses at most 3 bytes, a surrogate pair at most 4.
+    var encoder = _Utf8Encoder.withBufferSize(length * 3);
+    var endPosition = encoder._fillBuffer(string, start, end);
+    assert(endPosition >= end - 1);
+    if (endPosition != end) {
+      // Encoding skipped the last code unit.
+      // That can only happen if the last code unit is a leadsurrogate.
+      // Force encoding of the lead surrogate by itself.
+      var lastCodeUnit = string.codeUnitAt(end - 1);
+      assert(_isLeadSurrogate(lastCodeUnit));
+      // We use a non-surrogate as `nextUnit` so that _writeSurrogate just
+      // writes the lead-surrogate.
+      var wasCombined = encoder._writeSurrogate(lastCodeUnit, 0);
+      assert(!wasCombined);
+    }
+    return encoder._buffer.sublist(0, encoder._bufferIndex);
+  }
+
+  /// Starts a chunked conversion.
+  ///
+  /// The converter works more efficiently if the given [sink] is a
+  /// [ByteConversionSink].
+  StringConversionSink startChunkedConversion(Sink<List<int>> sink) {
+    return _Utf8EncoderSink(
+        sink is ByteConversionSink ? sink : ByteConversionSink.from(sink));
+  }
+
+  // Override the base-classes bind, to provide a better type.
+  Stream<List<int>> bind(Stream<String> stream) => super.bind(stream);
+}
+
+/// This class encodes Strings to UTF-8 code units (unsigned 8 bit integers).
+// TODO(floitsch): make this class public.
+class _Utf8Encoder {
+  int _carry = 0;
+  int _bufferIndex = 0;
+  final Uint8List _buffer;
+
+  static const _DEFAULT_BYTE_BUFFER_SIZE = 1024;
+
+  _Utf8Encoder() : this.withBufferSize(_DEFAULT_BYTE_BUFFER_SIZE);
+
+  _Utf8Encoder.withBufferSize(int bufferSize)
+      : _buffer = _createBuffer(bufferSize);
+
+  /// Allow an implementation to pick the most efficient way of storing bytes.
+  static Uint8List _createBuffer(int size) => Uint8List(size);
+
+  /// Tries to combine the given [leadingSurrogate] with the [nextCodeUnit] and
+  /// writes it to [_buffer].
+  ///
+  /// Returns true if the [nextCodeUnit] was combined with the
+  /// [leadingSurrogate]. If it wasn't then nextCodeUnit was not a trailing
+  /// surrogate and has not been written yet.
+  ///
+  /// It is safe to pass 0 for [nextCodeUnit] in which case only the leading
+  /// surrogate is written.
+  bool _writeSurrogate(int leadingSurrogate, int nextCodeUnit) {
+    if (_isTailSurrogate(nextCodeUnit)) {
+      var rune = _combineSurrogatePair(leadingSurrogate, nextCodeUnit);
+      // If the rune is encoded with 2 code-units then it must be encoded
+      // with 4 bytes in UTF-8.
+      assert(rune > _THREE_BYTE_LIMIT);
+      assert(rune <= _FOUR_BYTE_LIMIT);
+      _buffer[_bufferIndex++] = 0xF0 | (rune >> 18);
+      _buffer[_bufferIndex++] = 0x80 | ((rune >> 12) & 0x3f);
+      _buffer[_bufferIndex++] = 0x80 | ((rune >> 6) & 0x3f);
+      _buffer[_bufferIndex++] = 0x80 | (rune & 0x3f);
+      return true;
+    } else {
+      // TODO(floitsch): allow to throw on malformed strings.
+      // Encode the half-surrogate directly into UTF-8. This yields
+      // invalid UTF-8, but we started out with invalid UTF-16.
+
+      // Surrogates are always encoded in 3 bytes in UTF-8.
+      _buffer[_bufferIndex++] = 0xE0 | (leadingSurrogate >> 12);
+      _buffer[_bufferIndex++] = 0x80 | ((leadingSurrogate >> 6) & 0x3f);
+      _buffer[_bufferIndex++] = 0x80 | (leadingSurrogate & 0x3f);
+      return false;
+    }
+  }
+
+  /// Fills the [_buffer] with as many characters as possible.
+  ///
+  /// Does not encode any trailing lead-surrogate. This must be done by the
+  /// caller.
+  ///
+  /// Returns the position in the string. The returned index points to the
+  /// first code unit that hasn't been encoded.
+  int _fillBuffer(String str, int start, int end) {
+    if (start != end && _isLeadSurrogate(str.codeUnitAt(end - 1))) {
+      // Don't handle a trailing lead-surrogate in this loop. The caller has
+      // to deal with those.
+      end--;
+    }
+    int stringIndex;
+    for (stringIndex = start; stringIndex < end; stringIndex++) {
+      var codeUnit = str.codeUnitAt(stringIndex);
+      // ASCII has the same representation in UTF-8 and UTF-16.
+      if (codeUnit <= _ONE_BYTE_LIMIT) {
+        if (_bufferIndex >= _buffer.length) break;
+        _buffer[_bufferIndex++] = codeUnit;
+      } else if (_isLeadSurrogate(codeUnit)) {
+        if (_bufferIndex + 3 >= _buffer.length) break;
+        // Note that it is safe to read the next code unit. We decremented
+        // [end] above when the last valid code unit was a leading surrogate.
+        var nextCodeUnit = str.codeUnitAt(stringIndex + 1);
+        var wasCombined = _writeSurrogate(codeUnit, nextCodeUnit);
+        if (wasCombined) stringIndex++;
+      } else {
+        var rune = codeUnit;
+        if (rune <= _TWO_BYTE_LIMIT) {
+          if (_bufferIndex + 1 >= _buffer.length) break;
+          _buffer[_bufferIndex++] = 0xC0 | (rune >> 6);
+          _buffer[_bufferIndex++] = 0x80 | (rune & 0x3f);
+        } else {
+          assert(rune <= _THREE_BYTE_LIMIT);
+          if (_bufferIndex + 2 >= _buffer.length) break;
+          _buffer[_bufferIndex++] = 0xE0 | (rune >> 12);
+          _buffer[_bufferIndex++] = 0x80 | ((rune >> 6) & 0x3f);
+          _buffer[_bufferIndex++] = 0x80 | (rune & 0x3f);
+        }
+      }
+    }
+    return stringIndex;
+  }
+}
+
+/// This class encodes chunked strings to UTF-8 code units (unsigned 8-bit
+/// integers).
+class _Utf8EncoderSink extends _Utf8Encoder with StringConversionSinkMixin {
+  final ByteConversionSink _sink;
+
+  _Utf8EncoderSink(this._sink);
+
+  void close() {
+    if (_carry != 0) {
+      // addSlice will call close again, but then the carry must be equal to 0.
+      addSlice("", 0, 0, true);
+      return;
+    }
+    _sink.close();
+  }
+
+  void addSlice(String str, int start, int end, bool isLast) {
+    _bufferIndex = 0;
+
+    if (start == end && !isLast) {
+      return;
+    }
+
+    if (_carry != 0) {
+      var nextCodeUnit = 0;
+      if (start != end) {
+        nextCodeUnit = str.codeUnitAt(start);
+      } else {
+        assert(isLast);
+      }
+      var wasCombined = _writeSurrogate(_carry, nextCodeUnit);
+      // Either we got a non-empty string, or we must not have been combined.
+      assert(!wasCombined || start != end);
+      if (wasCombined) start++;
+      _carry = 0;
+    }
+    do {
+      start = _fillBuffer(str, start, end);
+      var isLastSlice = isLast && (start == end);
+      if (start == end - 1 && _isLeadSurrogate(str.codeUnitAt(start))) {
+        if (isLast && _bufferIndex < _buffer.length - 3) {
+          // There is still space for the last incomplete surrogate.
+          // We use a non-surrogate as second argument. This way the
+          // function will just add the surrogate-half to the buffer.
+          var hasBeenCombined = _writeSurrogate(str.codeUnitAt(start), 0);
+          assert(!hasBeenCombined);
+        } else {
+          // Otherwise store it in the carry. If isLast is true, then
+          // close will flush the last carry.
+          _carry = str.codeUnitAt(start);
+        }
+        start++;
+      }
+      _sink.addSlice(_buffer, 0, _bufferIndex, isLastSlice);
+      _bufferIndex = 0;
+    } while (start < end);
+    if (isLast) close();
+  }
+
+  // TODO(floitsch): implement asUtf8Sink. Sligthly complicated because it
+  // needs to deal with malformed input.
+}
+
+/// This class converts UTF-8 code units (lists of unsigned 8-bit integers)
+/// to a string.
+class Utf8Decoder extends Converter<List<int>, String> {
+  final bool _allowMalformed;
+
+  /// Instantiates a new [Utf8Decoder].
+  ///
+  /// The optional [allowMalformed] argument defines how [convert] deals
+  /// with invalid or unterminated character sequences.
+  ///
+  /// If it is `true` [convert] replaces invalid (or unterminated) character
+  /// sequences with the Unicode Replacement character `U+FFFD` (�). Otherwise
+  /// it throws a [FormatException].
+  const Utf8Decoder({bool allowMalformed = false})
+      : _allowMalformed = allowMalformed;
+
+  /// Converts the UTF-8 [codeUnits] (a list of unsigned 8-bit integers) to the
+  /// corresponding string.
+  ///
+  /// Uses the code units from [start] to, but no including, [end].
+  /// If [end] is omitted, it defaults to `codeUnits.length`.
+  ///
+  /// If the [codeUnits] start with the encoding of a
+  /// [unicodeBomCharacterRune], that character is discarded.
+  String convert(List<int> codeUnits, [int start = 0, int end]) {
+    // Allow the implementation to intercept and specialize based on the type
+    // of codeUnits.
+    var result = _convertIntercepted(_allowMalformed, codeUnits, start, end);
+    if (result != null) {
+      return result;
+    }
+
+    var length = codeUnits.length;
+    end = RangeError.checkValidRange(start, end, length);
+
+    // Fast case for ASCII strings avoids StringBuffer/_Utf8Decoder.
+    int oneBytes = _scanOneByteCharacters(codeUnits, start, end);
+    StringBuffer buffer;
+    bool isFirstCharacter = true;
+    if (oneBytes > 0) {
+      var firstPart = String.fromCharCodes(codeUnits, start, start + oneBytes);
+      start += oneBytes;
+      if (start == end) {
+        return firstPart;
+      }
+      buffer = StringBuffer(firstPart);
+      isFirstCharacter = false;
+    }
+
+    buffer ??= StringBuffer();
+    var decoder = _Utf8Decoder(buffer, _allowMalformed);
+    decoder._isFirstCharacter = isFirstCharacter;
+    decoder.convert(codeUnits, start, end);
+    decoder.flush(codeUnits, end);
+    return buffer.toString();
+  }
+
+  /// Starts a chunked conversion.
+  ///
+  /// The converter works more efficiently if the given [sink] is a
+  /// [StringConversionSink].
+  ByteConversionSink startChunkedConversion(Sink<String> sink) {
+    StringConversionSink stringSink;
+    if (sink is StringConversionSink) {
+      stringSink = sink;
+    } else {
+      stringSink = StringConversionSink.from(sink);
+    }
+    return stringSink.asUtf8Sink(_allowMalformed);
+  }
+
+  // Override the base-classes bind, to provide a better type.
+  Stream<String> bind(Stream<List<int>> stream) => super.bind(stream);
+
+  external Converter<List<int>, T> fuse<T>(Converter<String, T> next);
+
+  external static String _convertIntercepted(
+      bool allowMalformed, List<int> codeUnits, int start, int end);
+}
+
+// UTF-8 constants.
+const int _ONE_BYTE_LIMIT = 0x7f; // 7 bits
+const int _TWO_BYTE_LIMIT = 0x7ff; // 11 bits
+const int _THREE_BYTE_LIMIT = 0xffff; // 16 bits
+const int _FOUR_BYTE_LIMIT = 0x10ffff; // 21 bits, truncated to Unicode max.
+
+// UTF-16 constants.
+const int _SURROGATE_TAG_MASK = 0xFC00;
+const int _SURROGATE_VALUE_MASK = 0x3FF;
+const int _LEAD_SURROGATE_MIN = 0xD800;
+const int _TAIL_SURROGATE_MIN = 0xDC00;
+
+bool _isLeadSurrogate(int codeUnit) =>
+    (codeUnit & _SURROGATE_TAG_MASK) == _LEAD_SURROGATE_MIN;
+bool _isTailSurrogate(int codeUnit) =>
+    (codeUnit & _SURROGATE_TAG_MASK) == _TAIL_SURROGATE_MIN;
+int _combineSurrogatePair(int lead, int tail) =>
+    0x10000 + ((lead & _SURROGATE_VALUE_MASK) << 10) |
+    (tail & _SURROGATE_VALUE_MASK);
+
+/// Decodes UTF-8.
+///
+/// The decoder handles chunked input.
+// TODO(floitsch): make this class public.
+class _Utf8Decoder {
+  final bool _allowMalformed;
+  final StringSink _stringSink;
+  bool _isFirstCharacter = true;
+  int _value = 0;
+  int _expectedUnits = 0;
+  int _extraUnits = 0;
+
+  _Utf8Decoder(this._stringSink, this._allowMalformed);
+
+  bool get hasPartialInput => _expectedUnits > 0;
+
+  // Limits of one through four byte encodings.
+  static const List<int> _LIMITS = <int>[
+    _ONE_BYTE_LIMIT,
+    _TWO_BYTE_LIMIT,
+    _THREE_BYTE_LIMIT,
+    _FOUR_BYTE_LIMIT
+  ];
+
+  void close() {
+    flush();
+  }
+
+  /// Flushes this decoder as if closed.
+  ///
+  /// This method throws if the input was partial and the decoder was
+  /// constructed with `allowMalformed` set to `false`.
+  ///
+  /// The [source] and [offset] of the current position may be provided,
+  /// and are included in the exception if one is thrown.
+  void flush([List<int> source, int offset]) {
+    if (hasPartialInput) {
+      if (!_allowMalformed) {
+        throw FormatException(
+            "Unfinished UTF-8 octet sequence", source, offset);
+      }
+      _stringSink.writeCharCode(unicodeReplacementCharacterRune);
+      _value = 0;
+      _expectedUnits = 0;
+      _extraUnits = 0;
+    }
+  }
+
+  void convert(List<int> codeUnits, int startIndex, int endIndex) {
+    var value = _value;
+    var expectedUnits = _expectedUnits;
+    var extraUnits = _extraUnits;
+    _value = 0;
+    _expectedUnits = 0;
+    _extraUnits = 0;
+
+    var i = startIndex;
+    loop:
+    while (true) {
+      multibyte:
+      if (expectedUnits > 0) {
+        do {
+          if (i == endIndex) {
+            break loop;
+          }
+          var unit = codeUnits[i];
+          if ((unit & 0xC0) != 0x80) {
+            expectedUnits = 0;
+            if (!_allowMalformed) {
+              throw FormatException(
+                  "Bad UTF-8 encoding 0x${unit.toRadixString(16)}",
+                  codeUnits,
+                  i);
+            }
+            _isFirstCharacter = false;
+            _stringSink.writeCharCode(unicodeReplacementCharacterRune);
+            break multibyte;
+          } else {
+            value = (value << 6) | (unit & 0x3f);
+            expectedUnits--;
+            i++;
+          }
+        } while (expectedUnits > 0);
+        if (value <= _LIMITS[extraUnits - 1]) {
+          // Overly long encoding. The value could be encoded with a shorter
+          // encoding.
+          if (!_allowMalformed) {
+            throw FormatException(
+                "Overlong encoding of 0x${value.toRadixString(16)}",
+                codeUnits,
+                i - extraUnits - 1);
+          }
+          expectedUnits = extraUnits = 0;
+          value = unicodeReplacementCharacterRune;
+        }
+        if (value > _FOUR_BYTE_LIMIT) {
+          if (!_allowMalformed) {
+            throw FormatException(
+                "Character outside valid Unicode range: "
+                "0x${value.toRadixString(16)}",
+                codeUnits,
+                i - extraUnits - 1);
+          }
+          value = unicodeReplacementCharacterRune;
+        }
+        if (!_isFirstCharacter || value != unicodeBomCharacterRune) {
+          _stringSink.writeCharCode(value);
+        }
+        _isFirstCharacter = false;
+      }
+
+      while (i < endIndex) {
+        var oneBytes = _scanOneByteCharacters(codeUnits, i, endIndex);
+        if (oneBytes > 0) {
+          _isFirstCharacter = false;
+          assert(i + oneBytes <= endIndex);
+          _stringSink.write(String.fromCharCodes(codeUnits, i, i + oneBytes));
+
+          i += oneBytes;
+          if (i == endIndex) break;
+        }
+        var unit = codeUnits[i++];
+        // TODO(floitsch): the way we test we could potentially allow
+        // units that are too large, if they happen to have the
+        // right bit-pattern. (Same is true for the multibyte loop above).
+        // TODO(floitsch): optimize this loop. See:
+        // https://codereview.chromium.org/22929022/diff/1/sdk/lib/convert/utf.dart?column_width=80
+        if (unit < 0) {
+          // TODO(floitsch): should this be unit <= 0 ?
+          if (!_allowMalformed) {
+            throw FormatException(
+                "Negative UTF-8 code unit: -0x${(-unit).toRadixString(16)}",
+                codeUnits,
+                i - 1);
+          }
+          _stringSink.writeCharCode(unicodeReplacementCharacterRune);
+        } else {
+          assert(unit > _ONE_BYTE_LIMIT);
+          if ((unit & 0xE0) == 0xC0) {
+            value = unit & 0x1F;
+            expectedUnits = extraUnits = 1;
+            continue loop;
+          }
+          if ((unit & 0xF0) == 0xE0) {
+            value = unit & 0x0F;
+            expectedUnits = extraUnits = 2;
+            continue loop;
+          }
+          // 0xF5, 0xF6 ... 0xFF never appear in valid UTF-8 sequences.
+          if ((unit & 0xF8) == 0xF0 && unit < 0xF5) {
+            value = unit & 0x07;
+            expectedUnits = extraUnits = 3;
+            continue loop;
+          }
+          if (!_allowMalformed) {
+            throw FormatException(
+                "Bad UTF-8 encoding 0x${unit.toRadixString(16)}",
+                codeUnits,
+                i - 1);
+          }
+          value = unicodeReplacementCharacterRune;
+          expectedUnits = extraUnits = 0;
+          _isFirstCharacter = false;
+          _stringSink.writeCharCode(value);
+        }
+      }
+      break loop;
+    }
+    if (expectedUnits > 0) {
+      _value = value;
+      _expectedUnits = expectedUnits;
+      _extraUnits = extraUnits;
+    }
+  }
+}
+
+// Returns the number of bytes in [units] starting at offset [from] which have
+// the leftmost bit set to 0.
+//
+// To increase performance of this critical method we have a special variant of
+// it implemented in the VM's patch files, which is why we make it external.
+external int _scanOneByteCharacters(List<int> units, int from, int endIndex);
diff --git a/sdk_nnbd/lib/core/annotations.dart b/sdk_nnbd/lib/core/annotations.dart
new file mode 100644
index 0000000..2d30f1c
--- /dev/null
+++ b/sdk_nnbd/lib/core/annotations.dart
@@ -0,0 +1,240 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.core;
+
+/**
+ * The annotation `@Deprecated('migration')` marks a feature as deprecated.
+ *
+ * The annotation [deprecated] is a shorthand for deprecating until
+ * an unspecified "next release" without migration instructions.
+ *
+ * The intent of the `@Deprecated` annotation is to inform users of a feature
+ * that they should change their code, even if it is currently still working
+ * correctly.
+ *
+ * A deprecated feature is scheduled to be removed at a later time, possibly
+ * specified in [message]. A deprecated feature should not be used, code using
+ * it will break at some point in the future. If existing code is using the
+ * feature it should be rewritten to not use the deprecated feature.
+ *
+ * A deprecated feature should document how the same effect can be achieved in
+ * [message], so the programmer knows how to rewrite the code.
+ *
+ * The `@Deprecated` annotation applies to libraries, top-level declarations
+ * (variables, getters, setters, functions, classes and typedefs),
+ * class-level declarations (variables, getters, setters, methods, operators or
+ * constructors, whether static or not), named optional arguments and
+ * trailing optional positional parameters.
+ *
+ * Deprecation is transitive:
+ *
+ *  - If a library is deprecated, so is every member of it.
+ *  - If a class is deprecated, so is every member of it.
+ *  - If a variable is deprecated, so are its implicit getter and setter.
+ *
+ *
+ * A tool that processes Dart source code may report when:
+ *
+ * - the code imports a deprecated library.
+ * - the code exports a deprecated library, or any deprecated member of
+ *   a non-deprecated library.
+ * - the code refers statically to a deprecated declaration.
+ * - the code dynamically uses a member of an object with a statically known
+ *   type, where the member is deprecated on the static type of the object.
+ * - the code dynamically calls a method with an argument where the
+ *   corresponding optional parameter is deprecated on the object's static type.
+ *
+ *
+ * If the deprecated use is inside a library, class or method which is itself
+ * deprecated, the tool should not bother the user about it.
+ * A deprecated feature is expected to use other deprecated features.
+ */
+class Deprecated {
+  /**
+   * Message provided to the user when they use the deprecated feature.
+   *
+   * The message should explain how to migrate away from the feature if an
+   * alternative is available, and when the deprecated feature is expected to be
+   * removed.
+   */
+  final String message;
+
+  /**
+   * Create a deprecation annotation which specifies the migration path and
+   * expiration of the annotated feature.
+   *
+   * The [message] argument should be readable by programmers, and should state
+   * an alternative feature (if available) as well as when an annotated feature
+   * is expected to be removed.
+   */
+  const Deprecated(this.message);
+
+  @Deprecated('Use `message` instead. Will be removed in Dart 3.0.0')
+  String get expires => message;
+
+  String toString() => "Deprecated feature: $message";
+}
+
+/**
+ * Marks a feature as [Deprecated] until the next release.
+ */
+const Deprecated deprecated = Deprecated("next release");
+
+class _Override {
+  const _Override();
+}
+
+/**
+ * The annotation `@override` marks an instance member as overriding a
+ * superclass member with the same name.
+ *
+ * The annotation applies to instance methods, getters and setters, and to
+ * instance fields, where it means that the implicit getter and setter of the
+ * field is marked as overriding, but the field itself is not.
+ *
+ * The intent of the `@override` notation is to catch situations where a
+ * superclass renames a member, and an independent subclass which used to
+ * override the member, could silently continue working using the
+ * superclass implementation.
+ *
+ * The editor, or a similar tool aimed at the programmer, may report if no
+ * declaration of an annotated member is inherited by the class from either a
+ * superclass or an interface.
+ *
+ * Use the `@override` annotation judiciously and only for methods where
+ * the superclass is not under the programmer's control, the superclass is in a
+ * different library or package, and it is not considered stable.
+ * In any case, the use of `@override` is optional.
+ *
+ * For example, the annotation is intentionally not used in the Dart platform
+ * libraries, since they only depend on themselves.
+ */
+const Object override = _Override();
+
+/**
+ * An annotation class that was used during development of Dart 2.
+ *
+ * Should not be used any more.
+ */
+@deprecated
+class Provisional {
+  String get message => null;
+  const Provisional({String message});
+}
+
+/**
+ * An annotation that was used during development of Dart 2.
+ *
+ * Should not be used any more.
+ */
+@deprecated
+const Null provisional = null;
+
+class _Proxy {
+  const _Proxy();
+}
+
+/**
+ * This annotation is deprecated and will be removed in Dart 2.
+ *
+ * Dart 2 has a more restrictive type system than Dart 1, and it requires
+ * method access to be either through a known interface or by using
+ * dynamic invocations. The original intent of `@proxy` (to implement a class
+ * that isn't known statically, as documented at the end of this text),
+ * is not supported by Dart 2.
+ * To continue to perform dynamic invocations on an object,
+ * it should be accessed through a reference of type `dynamic`.
+ *
+ * The annotation `@proxy` marks a class as implementing members dynamically
+ * through `noSuchMethod`.
+ *
+ * The annotation applies to any class. It is inherited by subclasses from both
+ * superclass and interfaces.
+ *
+ * If a class is annotated with `@proxy`, or it implements any class that is
+ * annotated, then all member accesses are allowed on an object of that type.
+ * As such, it is not a static type warning to access any member of the object
+ * which is not implemented by the class, or to call a method with a different
+ * number of parameters than it is declared with.
+ *
+ * The annotation does not change which classes the annotated class implements,
+ * and does not prevent static warnings for assigning an object to a variable
+ * with a static type not implemented by the object.
+ *
+ * The suppression of warnings only affect static type warnings about
+ * member access.
+ * The runtime type of the object is unaffected.
+ * It is not considered to implement any special interfaces,
+ * so assigning it to a typed variable may fail in checked mode,
+ * and testing it with the `is` operator
+ * will only return true for types it actually implements or extends.
+ * Accessing a member which isn't implemented by the class
+ * will cause the `noSuchMethod` method to be called normally,
+ * the `@proxy` annotation merely states the intent to handle (some of) those
+ * `noSuchMethod` calls gracefully.
+ *
+ * A class that marked as `@proxy` should override the `noSuchMethod`
+ * declared on [Object].
+ *
+ * The intent of the `@proxy` notation is to create objects that implement a
+ * type (or multiple types) that are not known at compile time. If the types
+ * are known at compile time, a class can be written that implements these
+ * types.
+ */
+@deprecated
+const Object proxy = _Proxy();
+
+/**
+ * A hint to tools.
+ *
+ * Tools that work with Dart programs may accept hints to guide their behavior
+ * as `pragma` annotations on declarations.
+ * Each tool decides which hints it accepts, what they mean, and whether and
+ * how they apply to sub-parts of the annotated entity.
+ *
+ * Tools that recognize pragma hints should pick a pragma prefix to identify
+ * the tool. They should recognize any hint with a [name] starting with their
+ * prefix followed by `:` as if it was intended for that tool. A hint with a
+ * prefix for another tool should be ignored (unless compatibility with that
+ * other tool is a goal).
+ *
+ * A tool may recognize unprefixed names as well, if they would recognize that
+ * name with their own prefix in front.
+ *
+ * If the hint can be parameterized, an extra [options] object can be added as well.
+ *
+ * For example:
+ *
+ * ```dart
+ * @pragma('Tool:pragma-name', [param1, param2, ...])
+ * class Foo { }
+ *
+ * @pragma('OtherTool:other-pragma')
+ * void foo() { }
+ * ```
+ *
+ * Here class Foo is annotated with a Tool specific pragma 'pragma-name' and
+ * function foo is annotated with a pragma 'other-pragma' specific to OtherTool.
+ *
+ */
+@pragma('vm:entry-point')
+class pragma {
+  /**
+   * The name of the hint.
+   *
+   * A string that is recognized by one or more tools, or such a string prefixed
+   * by a tool identifier and a colon, which is only recognized by that
+   * particular tool.
+   */
+  final String name;
+
+  /** Optional extra data parameterizing the hint. */
+  final Object options;
+
+  /** Creates a hint named [name] with optional [options]. */
+  const factory pragma(String name, [Object options]) = pragma._;
+
+  const pragma._(this.name, [this.options]);
+}
diff --git a/sdk_nnbd/lib/core/bigint.dart b/sdk_nnbd/lib/core/bigint.dart
new file mode 100644
index 0000000..b495a9e
--- /dev/null
+++ b/sdk_nnbd/lib/core/bigint.dart
@@ -0,0 +1,414 @@
+// 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.
+
+part of dart.core;
+
+/**
+ * An arbitrarily large integer.
+ */
+abstract class BigInt implements Comparable<BigInt> {
+  external static BigInt get zero;
+  external static BigInt get one;
+  external static BigInt get two;
+
+  /**
+   * Parses [source] as a, possibly signed, integer literal and returns its
+   * value.
+   *
+   * The [source] must be a non-empty sequence of base-[radix] digits,
+   * optionally prefixed with a minus or plus sign ('-' or '+').
+   *
+   * The [radix] must be in the range 2..36. The digits used are
+   * first the decimal digits 0..9, and then the letters 'a'..'z' with
+   * values 10 through 35. Also accepts upper-case letters with the same
+   * values as the lower-case ones.
+   *
+   * If no [radix] is given then it defaults to 10. In this case, the [source]
+   * digits may also start with `0x`, in which case the number is interpreted
+   * as a hexadecimal literal, which effectively means that the `0x` is ignored
+   * and the radix is instead set to 16.
+   *
+   * For any int `n` and radix `r`, it is guaranteed that
+   * `n == int.parse(n.toRadixString(r), radix: r)`.
+   *
+   * Throws a [FormatException] if the [source] is not a valid integer literal,
+   * optionally prefixed by a sign.
+   */
+  external static BigInt parse(String source, {int radix});
+
+  /**
+   * Parses [source] as a, possibly signed, integer literal and returns its
+   * value.
+   *
+   * As [parse] except that this method returns `null` if the input is not
+   * valid
+   */
+  external static BigInt tryParse(String source, {int radix});
+
+  /// Allocates a big integer from the provided [value] number.
+  external factory BigInt.from(num value);
+
+  /**
+   * Returns the absolute value of this integer.
+   *
+   * For any integer `x`, the result is the same as `x < 0 ? -x : x`.
+   */
+  BigInt abs();
+
+  /**
+   * Return the negative value of this integer.
+   *
+   * The result of negating an integer always has the opposite sign, except
+   * for zero, which is its own negation.
+   */
+  BigInt operator -();
+
+  /// Addition operator.
+  BigInt operator +(BigInt other);
+
+  /// Subtraction operator.
+  BigInt operator -(BigInt other);
+
+  /// Multiplication operator.
+  BigInt operator *(BigInt other);
+
+  /// Division operator.
+  double operator /(BigInt other);
+
+  /**
+   * Truncating division operator.
+   *
+   * Performs a truncating integer division, where the remainder is discarded.
+   *
+   * The remainder can be computed using the [remainder] method.
+   *
+   * Examples:
+   * ```
+   * var seven = new BigInt.from(7);
+   * var three = new BigInt.from(3);
+   * seven ~/ three;    // => 2
+   * (-seven) ~/ three; // => -2
+   * seven ~/ -three;   // => -2
+   * seven.remainder(three);    // => 1
+   * (-seven).remainder(three); // => -1
+   * seven.remainder(-three);   // => 1
+   * ```
+   */
+  BigInt operator ~/(BigInt other);
+
+  /**
+   * Euclidean modulo operator.
+   *
+   * Returns the remainder of the Euclidean division. The Euclidean division of
+   * two integers `a` and `b` yields two integers `q` and `r` such that
+   * `a == b * q + r` and `0 <= r < b.abs()`.
+   *
+   * The sign of the returned value `r` is always positive.
+   *
+   * See [remainder] for the remainder of the truncating division.
+   */
+  BigInt operator %(BigInt other);
+
+  /**
+   * Returns the remainder of the truncating division of `this` by [other].
+   *
+   * The result `r` of this operation satisfies:
+   * `this == (this ~/ other) * other + r`.
+   * As a consequence the remainder `r` has the same sign as the divider `this`.
+   */
+  BigInt remainder(BigInt other);
+
+  /**
+   * Shift the bits of this integer to the left by [shiftAmount].
+   *
+   * Shifting to the left makes the number larger, effectively multiplying
+   * the number by `pow(2, shiftIndex)`.
+   *
+   * There is no limit on the size of the result. It may be relevant to
+   * limit intermediate values by using the "and" operator with a suitable
+   * mask.
+   *
+   * It is an error if [shiftAmount] is negative.
+   */
+  BigInt operator <<(int shiftAmount);
+
+  /**
+   * Shift the bits of this integer to the right by [shiftAmount].
+   *
+   * Shifting to the right makes the number smaller and drops the least
+   * significant bits, effectively doing an integer division by
+   *`pow(2, shiftIndex)`.
+   *
+   * It is an error if [shiftAmount] is negative.
+   */
+  BigInt operator >>(int shiftAmount);
+
+  /**
+   * Bit-wise and operator.
+   *
+   * Treating both `this` and [other] as sufficiently large two's component
+   * integers, the result is a number with only the bits set that are set in
+   * both `this` and [other]
+   *
+   * Of both operands are negative, the result is negative, otherwise
+   * the result is non-negative.
+   */
+  BigInt operator &(BigInt other);
+
+  /**
+   * Bit-wise or operator.
+   *
+   * Treating both `this` and [other] as sufficiently large two's component
+   * integers, the result is a number with the bits set that are set in either
+   * of `this` and [other]
+   *
+   * If both operands are non-negative, the result is non-negative,
+   * otherwise the result us negative.
+   */
+  BigInt operator |(BigInt other);
+
+  /**
+   * Bit-wise exclusive-or operator.
+   *
+   * Treating both `this` and [other] as sufficiently large two's component
+   * integers, the result is a number with the bits set that are set in one,
+   * but not both, of `this` and [other]
+   *
+   * If the operands have the same sign, the result is non-negative,
+   * otherwise the result is negative.
+   */
+  BigInt operator ^(BigInt other);
+
+  /**
+   * The bit-wise negate operator.
+   *
+   * Treating `this` as a sufficiently large two's component integer,
+   * the result is a number with the opposite bits set.
+   *
+   * This maps any integer `x` to `-x - 1`.
+   */
+  BigInt operator ~();
+
+  /** Relational less than operator. */
+  bool operator <(BigInt other);
+
+  /** Relational less than or equal operator. */
+  bool operator <=(BigInt other);
+
+  /** Relational greater than operator. */
+  bool operator >(BigInt other);
+
+  /** Relational greater than or equal operator. */
+  bool operator >=(BigInt other);
+
+  /**
+   * Compares this to `other`.
+   *
+   * Returns a negative number if `this` is less than `other`, zero if they are
+   * equal, and a positive number if `this` is greater than `other`.
+   */
+  int compareTo(BigInt other);
+
+  /**
+   * Returns the minimum number of bits required to store this big integer.
+   *
+   * The number of bits excludes the sign bit, which gives the natural length
+   * for non-negative (unsigned) values.  Negative values are complemented to
+   * return the bit position of the first bit that differs from the sign bit.
+   *
+   * To find the number of bits needed to store the value as a signed value,
+   * add one, i.e. use `x.bitLength + 1`.
+   *
+   * ```
+   * x.bitLength == (-x-1).bitLength
+   *
+   * new BigInt.from(3).bitLength == 2;   // 00000011
+   * new BigInt.from(2).bitLength == 2;   // 00000010
+   * new BigInt.from(1).bitLength == 1;   // 00000001
+   * new BigInt.from(0).bitLength == 0;   // 00000000
+   * new BigInt.from(-1).bitLength == 0;  // 11111111
+   * new BigInt.from(-2).bitLength == 1;  // 11111110
+   * new BigInt.from(-3).bitLength == 2;  // 11111101
+   * new BigInt.from(-4).bitLength == 2;  // 11111100
+   * ```
+   */
+  int get bitLength;
+
+  /**
+   * Returns the sign of this big integer.
+   *
+   * Returns 0 for zero, -1 for values less than zero and
+   * +1 for values greater than zero.
+   */
+  int get sign;
+
+  /// Whether this big integer is even.
+  bool get isEven;
+
+  /// Whether this big integer is odd.
+  bool get isOdd;
+
+  /// Whether this number is negative.
+  bool get isNegative;
+
+  /**
+   * Returns `this` to the power of [exponent].
+   *
+   * Returns [one] if the [exponent] equals 0.
+   *
+   * The [exponent] must otherwise be positive.
+   *
+   * The result is always equal to the mathematical result of this to the power
+   * [exponent], only limited by the available memory.
+   */
+  BigInt pow(int exponent);
+
+  /**
+   * Returns this integer to the power of [exponent] modulo [modulus].
+   *
+   * The [exponent] must be non-negative and [modulus] must be
+   * positive.
+   */
+  BigInt modPow(BigInt exponent, BigInt modulus);
+
+  /**
+   * Returns the modular multiplicative inverse of this big integer
+   * modulo [modulus].
+   *
+   * The [modulus] must be positive.
+   *
+   * It is an error if no modular inverse exists.
+   */
+  // Returns 1/this % modulus, with modulus > 0.
+  BigInt modInverse(BigInt modulus);
+
+  /**
+   * Returns the greatest common divisor of this big integer and [other].
+   *
+   * If either number is non-zero, the result is the numerically greatest
+   * integer dividing both `this` and `other`.
+   *
+   * The greatest common divisor is independent of the order,
+   * so `x.gcd(y)` is  always the same as `y.gcd(x)`.
+   *
+   * For any integer `x`, `x.gcd(x)` is `x.abs()`.
+   *
+   * If both `this` and `other` is zero, the result is also zero.
+   */
+  BigInt gcd(BigInt other);
+
+  /**
+   * Returns the least significant [width] bits of this big integer as a
+   * non-negative number (i.e. unsigned representation).  The returned value has
+   * zeros in all bit positions higher than [width].
+   *
+   * ```
+   * new BigInt.from(-1).toUnsigned(5) == 31   // 11111111  ->  00011111
+   * ```
+   *
+   * This operation can be used to simulate arithmetic from low level languages.
+   * For example, to increment an 8 bit quantity:
+   *
+   * ```
+   * q = (q + 1).toUnsigned(8);
+   * ```
+   *
+   * `q` will count from `0` up to `255` and then wrap around to `0`.
+   *
+   * If the input fits in [width] bits without truncation, the result is the
+   * same as the input.  The minimum width needed to avoid truncation of `x` is
+   * given by `x.bitLength`, i.e.
+   *
+   * ```
+   * x == x.toUnsigned(x.bitLength);
+   * ```
+   */
+  BigInt toUnsigned(int width);
+
+  /**
+   * Returns the least significant [width] bits of this integer, extending the
+   * highest retained bit to the sign.  This is the same as truncating the value
+   * to fit in [width] bits using an signed 2-s complement representation.  The
+   * returned value has the same bit value in all positions higher than [width].
+   *
+   * ```
+   * var big15 = new BigInt.from(15);
+   * var big16 = new BigInt.from(16);
+   * var big239 = new BigInt.from(239);
+   *                                      V--sign bit-V
+   * big16.toSigned(5) == -big16   //  00010000 -> 11110000
+   * big239.toSigned(5) == big15   //  11101111 -> 00001111
+   *                                      ^           ^
+   * ```
+   *
+   * This operation can be used to simulate arithmetic from low level languages.
+   * For example, to increment an 8 bit signed quantity:
+   *
+   * ```
+   * q = (q + 1).toSigned(8);
+   * ```
+   *
+   * `q` will count from `0` up to `127`, wrap to `-128` and count back up to
+   * `127`.
+   *
+   * If the input value fits in [width] bits without truncation, the result is
+   * the same as the input.  The minimum width needed to avoid truncation of `x`
+   * is `x.bitLength + 1`, i.e.
+   *
+   * ```
+   * x == x.toSigned(x.bitLength + 1);
+   * ```
+   */
+  BigInt toSigned(int width);
+
+  /**
+   * Whether this big integer can be represented as an `int` without losing
+   * precision.
+   *
+   * Warning: this function may give a different result on
+   * dart2js, dev compiler, and the VM, due to the differences in
+   * integer precision.
+   */
+  bool get isValidInt;
+
+  /**
+   * Returns this [BigInt] as an [int].
+   *
+   * If the number does not fit, clamps to the max (or min)
+   * integer.
+   *
+   * Warning: the clamping behaves differently on dart2js, dev
+   * compiler, and the VM, due to the differences in integer
+   * precision.
+   */
+  int toInt();
+
+  /**
+   * Returns this [BigInt] as a [double].
+   *
+   * If the number is not representable as a [double], an
+   * approximation is returned. For numerically large integers, the
+   * approximation may be infinite.
+   */
+  double toDouble();
+
+  /**
+   * Returns a String-representation of this integer.
+   *
+   * The returned string is parsable by [parse].
+   * For any `BigInt` `i`, it is guaranteed that
+   * `i == BigInt.parse(i.toString())`.
+   */
+  String toString();
+
+  /**
+   * Converts [this] to a string representation in the given [radix].
+   *
+   * In the string representation, lower-case letters are used for digits above
+   * '9', with 'a' being 10 an 'z' being 35.
+   *
+   * The [radix] argument must be an integer in the range 2 to 36.
+   */
+  String toRadixString(int radix);
+}
diff --git a/sdk_nnbd/lib/core/bool.dart b/sdk_nnbd/lib/core/bool.dart
new file mode 100644
index 0000000..5ed1065
--- /dev/null
+++ b/sdk_nnbd/lib/core/bool.dart
@@ -0,0 +1,79 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.core;
+
+/**
+ * The reserved words `true` and `false` denote objects that are the only two
+ * instances of this class.
+ *
+ * It is a compile-time error for a class to attempt to extend or implement
+ * bool.
+ */
+@pragma("vm:entry-point")
+class bool {
+  /**
+   * Returns the boolean value of the environment declaration [name].
+   *
+   * The boolean value of the declaration is `true` if the declared value is
+   * the string `"true"`, and `false` if the value is `"false"`.
+   *
+   * In all other cases, including when there is no declaration for `name`,
+   * the result is the [defaultValue].
+   *
+   * The result is the same as would be returned by:
+   * ```dart
+   * (const String.fromEnvironment(name) == "true")
+   *     ? true
+   *     : (const String.fromEnvironment(name) == "false")
+   *         ? false
+   *         : defaultValue
+   * ```
+   * Example:
+   * ```dart
+   * const loggingFlag = const bool.fromEnvironment("logging");
+   * ```
+   * If you want to use a different truth-string than `"true"`, you can use the
+   * [String.fromEnvironment] constructor directly:
+   * ```dart
+   * const isLoggingOn = (const String.fromEnvironment("logging") == "on");
+   * ```
+   */
+  // The .fromEnvironment() constructors are special in that we do not want
+  // users to call them using "new". We prohibit that by giving them bodies
+  // that throw, even though const constructors are not allowed to have bodies.
+  // Disable those static errors.
+  //ignore: const_constructor_with_body
+  //ignore: const_factory
+  external const factory bool.fromEnvironment(String name,
+      {bool defaultValue = false});
+
+  external int get hashCode;
+
+  /// The logical conjunction ("and") of this and [other].
+  ///
+  /// Returns `true` if both this and [other] are `true`, and `false` otherwise.
+  //TODO(lrn): Remove "as bool" in Dart 2.
+  @Since("2.1")
+  bool operator &(bool other) => (other as bool) && this;
+
+  /// The logical disjunction ("inclusive or") of this and [other].
+  ///
+  /// Returns `true` if either this or [other] is `true`, and `false` otherwise.
+  @Since("2.1")
+  bool operator |(bool other) => (other as bool) || this;
+
+  /// The logical exclusive disjunction ("exclusive or") of this and [other].
+  ///
+  /// Returns whether this and [other] are neither both `true` nor both `false`.
+  @Since("2.1")
+  bool operator ^(bool other) => !(other as bool) == this;
+
+  /**
+   * Returns either `"true"` for `true` and `"false"` for `false`.
+   */
+  String toString() {
+    return this ? "true" : "false";
+  }
+}
diff --git a/sdk_nnbd/lib/core/comparable.dart b/sdk_nnbd/lib/core/comparable.dart
new file mode 100644
index 0000000..835aa34
--- /dev/null
+++ b/sdk_nnbd/lib/core/comparable.dart
@@ -0,0 +1,94 @@
+// Copyright (c) 2011, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.core;
+
+/**
+ * The signature of a generic comparison function.
+ *
+ * A comparison function represents an ordering on a type of objects.
+ * A total ordering on a type means that for two values, either they
+ * are equal or one is greater than the other (and the latter must then be
+ * smaller than the former).
+ *
+ * A [Comparator] function represents such a total ordering by returning
+ *
+ * * a negative integer if [a] is smaller than [b],
+ * * zero if [a] is equal to [b], and
+ * * a positive integer if [a] is greater than [b].
+ */
+typedef Comparator<T> = int Function(T a, T b);
+
+/**
+ * Interface used by types that have an intrinsic ordering.
+ *
+ * The [compareTo] operation defines a total ordering of objects,
+ * which can be used for ordering and sorting.
+ *
+ * The [Comparable] interface should be used for the natural ordering of a type.
+ * If a type can be ordered in more than one way,
+ * and none of them is the obvious natural ordering,
+ * then it might be better not to use the [Comparable] interface,
+ * and to provide separate [Comparator]s instead.
+ *
+ * It is recommended that the order of a [Comparable] agrees
+ * with its operator [operator ==] equality (`a.compareTo(b) == 0` iff `a == b`),
+ * but this is not a requirement.
+ * For example, [double] and [DateTime] have `compareTo` methods
+ * that do not agree with operator [operator ==].
+ * For doubles the [compareTo] method is more precise than the equality,
+ * and for [DateTime] it is less precise.
+ *
+ * Examples:
+ *
+ *      (0.0).compareTo(-0.0);  // => 1
+ *      0.0 == -0.0;            // => true
+ *      var dt = new DateTime.now();
+ *      var dt2 = dt.toUtc();
+ *      dt == dt2;              // => false
+ *      dt.compareTo(dt2);      // => 0
+ *
+ * The [Comparable] interface does not imply the existence
+ * of the comparison operators `<`, `<=`, `>` and `>=`.
+ * These should only be defined
+ * if the ordering is a less-than/greater-than ordering,
+ * that is, an ordering where you would naturally
+ * use the words "less than" about the order of two elements.
+ *
+ * If the equality operator and [compareTo] disagree,
+ * the comparison operators should follow the equality operator,
+ * and will likely also disagree with [compareTo].
+ * Otherwise they should match the [compareTo] method,
+ * so that `a < b` iff `a.compareTo(b) < 0`.
+ *
+ * The [double] class defines comparison operators
+ * that are compatible with equality.
+ * The operators differ from `double.compareTo` on -0.0 and NaN.
+ *
+ * The [DateTime] class has no comparison operators, instead it has the more
+ * precisely named [DateTime.isBefore] and [DateTime.isAfter].
+ */
+abstract class Comparable<T> {
+  /**
+   * Compares this object to another [Comparable]
+   *
+   * Returns a value like a [Comparator] when comparing `this` to [other].
+   * That is, it returns a negative integer if `this` is ordered before [other],
+   * a positive integer if `this` is ordered after [other],
+   * and zero if `this` and [other] are ordered together.
+   *
+   * The [other] argument must be a value that is comparable to this object.
+   */
+  int compareTo(T other);
+
+  /**
+   * A [Comparator] that compares one comparable to another.
+   *
+   * It returns the result of `a.compareTo(b)`.
+   *
+   * This utility function is used as the default comparator
+   * for ordering collections, for example in the [List] sort function.
+   */
+  static int compare(Comparable a, Comparable b) => a.compareTo(b);
+}
diff --git a/sdk_nnbd/lib/core/core.dart b/sdk_nnbd/lib/core/core.dart
new file mode 100644
index 0000000..9ab8ed4
--- /dev/null
+++ b/sdk_nnbd/lib/core/core.dart
@@ -0,0 +1,208 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/**
+ *
+ * Built-in types, collections,
+ * and other core functionality for every Dart program.
+ *
+ * This library is automatically imported.
+ *
+ * Some classes in this library,
+ * such as [String] and [num],
+ * support Dart's built-in data types.
+ * Other classes, such as [List] and [Map], provide data structures
+ * for managing collections of objects.
+ * And still other classes represent commonly used types of data
+ * such as URIs, dates and times, and errors.
+ *
+ * ## Numbers and booleans
+ *
+ * [int] and [double] provide support for Dart's built-in numerical data types:
+ * integers and double-precision floating point numbers, respectively.
+ * An object of type [bool] is either true or false.
+ * Variables of these types can be constructed from literals:
+ *
+ *     int meaningOfLife = 42;
+ *     double valueOfPi  = 3.141592;
+ *     bool visible      = true;
+ *
+ * ## Strings and regular expressions
+ *
+ * A [String] is immutable and represents a sequence of characters.
+ *
+ *     String shakespeareQuote = "All the world's a stage, ...";
+ *
+ * [StringBuffer] provides a way to construct strings efficiently.
+ *
+ *     StringBuffer moreShakespeare = new StringBuffer();
+ *     moreShakespeare.write('And all the men and women ');
+ *     moreShakespeare.write('merely players; ...');
+ *
+ * The String and StringBuffer classes implement string concatenation,
+ * interpolation, and other string manipulation features.
+ *
+ *     String philosophy = 'Live on ';
+ *     String get palindrome => philosophy + philosophy.split('').reversed.join();
+ *
+ * [RegExp] implements Dart regular expressions,
+ * which provide a grammar for matching patterns within text.
+ * For example, here's a regular expression that matches
+ * a string of one or more digits:
+ *
+ *     var numbers = new RegExp(r'\d+');
+ *
+ * Dart regular expressions have the same syntax and semantics as
+ * JavaScript regular expressions. See
+ * <http://ecma-international.org/ecma-262/5.1/#sec-15.10>
+ * for the specification of JavaScript regular expressions.
+ *
+ * ## Collections
+ *
+ * The dart:core library provides basic collections,
+ * such as [List], [Map], and [Set].
+ *
+ * A List is an ordered collection of objects, with a length.
+ * Lists are sometimes called arrays.
+ * Use a List when you need to access objects by index.
+ *
+ *     List superheroes = [ 'Batman', 'Superman', 'Harry Potter' ];
+ *
+ * A Set is an unordered collection of unique objects.
+ * You cannot get an item by index (position).
+ * Adding a duplicate item has no effect.
+ *
+ *     Set villains = new Set();
+ *     villains.add('Joker');
+ *     villains.addAll( ['Lex Luther', 'Voldemort'] );
+ *
+ * A Map is an unordered collection of key-value pairs.
+ * Maps are sometimes called associative arrays because
+ * maps associate a key to some value for easy retrieval.
+ * Keys are unique.
+ * Use a Map when you need to access objects
+ * by a unique identifier.
+ *
+ *     Map sidekicks = { 'Batman': 'Robin',
+ *                       'Superman': 'Lois Lane',
+ *                       'Harry Potter': 'Ron and Hermione' };
+ *
+ * In addition to these classes,
+ * dart:core contains [Iterable],
+ * an interface that defines functionality
+ * common in collections of objects.
+ * Examples include the ability
+ * to run a function on each element in the collection,
+ * to apply a test to each element,
+ * to retrieve an object, and to determine length.
+ *
+ * Iterable is implemented by List and Set,
+ * and used by Map for its keys and values.
+ *
+ * For other kinds of collections, check out the
+ * `dart:collection` library.
+ *
+ * ## Date and time
+ *
+ * Use [DateTime] to represent a point in time
+ * and [Duration] to represent a span of time.
+ *
+ * You can create DateTime objects with constructors
+ * or by parsing a correctly formatted string.
+ *
+ *     DateTime now = new DateTime.now();
+ *     DateTime berlinWallFell = new DateTime(1989, 11, 9);
+ *     DateTime moonLanding = DateTime.parse("1969-07-20");
+ *
+ * Create a Duration object specifying the individual time units.
+ *
+ *     Duration timeRemaining = new Duration(hours:56, minutes:14);
+ *
+ * In addition to DateTime and Duration,
+ * dart:core contains the [Stopwatch] class for measuring elapsed time.
+ *
+ * ## Uri
+ *
+ * A [Uri] object represents a uniform resource identifier,
+ * which identifies a resource on the web.
+ *
+ *     Uri dartlang = Uri.parse('http://dartlang.org/');
+ *
+ * ## Errors
+ *
+ * The [Error] class represents the occurrence of an error
+ * during runtime.
+ * Subclasses of this class represent specific kinds of errors.
+ *
+ * ## Other documentation
+ *
+ * For more information about how to use the built-in types, refer to [Built-in
+ * Types](http://www.dartlang.org/docs/dart-up-and-running/contents/ch02.html#built-in-types)
+ * in Chapter 2 of
+ * [Dart: Up and Running](http://www.dartlang.org/docs/dart-up-and-running/).
+ *
+ * Also, see [dart:core - Numbers, Collections, Strings, and
+ * More](https://www.dartlang.org/docs/dart-up-and-running/ch03.html#dartcore---numbers-collections-strings-and-more)
+ * for more coverage of classes in this package.
+ *
+ * The
+ * [Dart Language Specification](http://www.dartlang.org/docs/spec/)
+ * provides technical details.
+ *
+ * {@category Core}
+ */
+library dart.core;
+
+import "dart:collection";
+import "dart:_internal" hide Symbol, LinkedList, LinkedListEntry;
+import "dart:_internal" as internal show Symbol;
+import "dart:convert"
+    show
+        ascii,
+        base64,
+        Base64Codec,
+        Encoding,
+        latin1,
+        StringConversionSink,
+        utf8;
+import "dart:math" show Random; // Used by List.shuffle.
+import "dart:typed_data" show Uint8List, Uint16List, Endian;
+
+@Since("2.1")
+export "dart:async" show Future, Stream;
+
+part "annotations.dart";
+part "bigint.dart";
+part "bool.dart";
+part "comparable.dart";
+part "date_time.dart";
+part "double.dart";
+part "duration.dart";
+part "errors.dart";
+part "exceptions.dart";
+part "expando.dart";
+part "function.dart";
+part "identical.dart";
+part "int.dart";
+part "invocation.dart";
+part "iterable.dart";
+part "iterator.dart";
+part "list.dart";
+part "map.dart";
+part "null.dart";
+part "num.dart";
+part "object.dart";
+part "pattern.dart";
+part "print.dart";
+part "regexp.dart";
+part "set.dart";
+part "sink.dart";
+part "stacktrace.dart";
+part "stopwatch.dart";
+part "string.dart";
+part "string_buffer.dart";
+part "string_sink.dart";
+part "symbol.dart";
+part "type.dart";
+part "uri.dart";
diff --git a/sdk_nnbd/lib/core/core_sources.gni b/sdk_nnbd/lib/core/core_sources.gni
new file mode 100644
index 0000000..ce2785e
--- /dev/null
+++ b/sdk_nnbd/lib/core/core_sources.gni
@@ -0,0 +1,43 @@
+# 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.
+
+core_sdk_sources = [
+  "core.dart",
+
+  # The above file needs to be first as it lists the parts below.
+  "annotations.dart",
+  "bigint.dart",
+  "bool.dart",
+  "comparable.dart",
+  "date_time.dart",
+  "double.dart",
+  "duration.dart",
+  "errors.dart",
+  "exceptions.dart",
+  "expando.dart",
+  "function.dart",
+  "identical.dart",
+  "int.dart",
+  "invocation.dart",
+  "iterable.dart",
+  "iterator.dart",
+  "list.dart",
+  "map.dart",
+  "null.dart",
+  "num.dart",
+  "object.dart",
+  "pattern.dart",
+  "print.dart",
+  "regexp.dart",
+  "set.dart",
+  "sink.dart",
+  "stacktrace.dart",
+  "stopwatch.dart",
+  "string.dart",
+  "string_buffer.dart",
+  "string_sink.dart",
+  "symbol.dart",
+  "type.dart",
+  "uri.dart",
+]
diff --git a/sdk_nnbd/lib/core/date_time.dart b/sdk_nnbd/lib/core/date_time.dart
new file mode 100644
index 0000000..dd242de
--- /dev/null
+++ b/sdk_nnbd/lib/core/date_time.dart
@@ -0,0 +1,873 @@
+// Copyright (c) 2011, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.core;
+
+/**
+ * An instant in time, such as July 20, 1969, 8:18pm GMT.
+ *
+ * DateTimes can represent time values that are at a distance of at most
+ * 100,000,000 days from epoch (1970-01-01 UTC): -271821-04-20 to 275760-09-13.
+ *
+ * Create a DateTime object by using one of the constructors
+ * or by parsing a correctly formatted string,
+ * which complies with a subset of ISO 8601.
+ * Note that hours are specified between 0 and 23,
+ * as in a 24-hour clock.
+ * For example:
+ *
+ * ```
+ * var now = new DateTime.now();
+ * var berlinWallFell = new DateTime.utc(1989, 11, 9);
+ * var moonLanding = DateTime.parse("1969-07-20 20:18:04Z");  // 8:18pm
+ * ```
+ *
+ * A DateTime object is anchored either in the UTC time zone
+ * or in the local time zone of the current computer
+ * when the object is created.
+ *
+ * Once created, neither the value nor the time zone
+ * of a DateTime object may be changed.
+ *
+ * You can use properties to get
+ * the individual units of a DateTime object.
+ *
+ * ```
+ * assert(berlinWallFell.month == 11);
+ * assert(moonLanding.hour == 20);
+ * ```
+ *
+ * For convenience and readability,
+ * the DateTime class provides a constant for each day and month
+ * name - for example, [august] and [friday].
+ * You can use these constants to improve code readability:
+ *
+ * ```
+ * var berlinWallFell = new DateTime.utc(1989, DateTime.november, 9);
+ * assert(berlinWallFell.weekday == DateTime.thursday);
+ * ```
+ *
+ * Day and month values begin at 1, and the week starts on Monday.
+ * That is, the constants [january] and [monday] are both 1.
+ *
+ * ## Working with UTC and local time
+ *
+ * A DateTime object is in the local time zone
+ * unless explicitly created in the UTC time zone.
+ *
+ * ```
+ * var dDay = new DateTime.utc(1944, 6, 6);
+ * ```
+ *
+ * Use [isUtc] to determine whether a DateTime object is based in UTC.
+ * Use the methods [toLocal] and [toUtc]
+ * to get the equivalent date/time value specified in the other time zone.
+ * Use [timeZoneName] to get an abbreviated name of the time zone
+ * for the DateTime object.
+ * To find the difference
+ * between UTC and the time zone of a DateTime object
+ * call [timeZoneOffset].
+ *
+ * ## Comparing DateTime objects
+ *
+ * The DateTime class contains several handy methods,
+ * such as [isAfter], [isBefore], and [isAtSameMomentAs],
+ * for comparing DateTime objects.
+ *
+ * ```
+ * assert(berlinWallFell.isAfter(moonLanding) == true);
+ * assert(berlinWallFell.isBefore(moonLanding) == false);
+ * ```
+ *
+ * ## Using DateTime with Duration
+ *
+ * Use the [add] and [subtract] methods with a [Duration] object
+ * to create a new DateTime object based on another.
+ * For example, to find the date that is sixty days (24 * 60 hours) after today,
+ * write:
+ *
+ * ```
+ * var now = new DateTime.now();
+ * var sixtyDaysFromNow = now.add(new Duration(days: 60));
+ * ```
+ *
+ * To find out how much time is between two DateTime objects use
+ * [difference], which returns a [Duration] object:
+ *
+ * ```
+ * var difference = berlinWallFell.difference(moonLanding);
+ * assert(difference.inDays == 7416);
+ * ```
+ *
+ * The difference between two dates in different time zones
+ * is just the number of nanoseconds between the two points in time.
+ * It doesn't take calendar days into account.
+ * That means that the difference between two midnights in local time may be
+ * less than 24 hours times the number of days between them,
+ * if there is a daylight saving change in between.
+ * If the difference above is calculated using Australian local time, the
+ * difference is 7415 days and 23 hours, which is only 7415 whole days as
+ * reported by `inDays`.
+ *
+ * ## Other resources
+ *
+ * See [Duration] to represent a span of time.
+ * See [Stopwatch] to measure timespans.
+ *
+ * The DateTime class does not provide internationalization.
+ * To internationalize your code, use
+ * the [intl](https://pub.dartlang.org/packages/intl) package.
+ *
+ */
+class DateTime implements Comparable<DateTime> {
+  // Weekday constants that are returned by [weekday] method:
+  static const int monday = 1;
+  static const int tuesday = 2;
+  static const int wednesday = 3;
+  static const int thursday = 4;
+  static const int friday = 5;
+  static const int saturday = 6;
+  static const int sunday = 7;
+  static const int daysPerWeek = 7;
+
+  // Month constants that are returned by the [month] getter.
+  static const int january = 1;
+  static const int february = 2;
+  static const int march = 3;
+  static const int april = 4;
+  static const int may = 5;
+  static const int june = 6;
+  static const int july = 7;
+  static const int august = 8;
+  static const int september = 9;
+  static const int october = 10;
+  static const int november = 11;
+  static const int december = 12;
+  static const int monthsPerYear = 12;
+
+  /**
+   * The value of this DateTime.
+   *
+   * The content of this field is implementation dependent. On JavaScript it is
+   * equal to [millisecondsSinceEpoch]. On the VM it is equal to
+   * [microsecondsSinceEpoch].
+   */
+  final int _value;
+
+  /**
+   * True if this [DateTime] is set to UTC time.
+   *
+   * ```
+   * var dDay = new DateTime.utc(1944, 6, 6);
+   * assert(dDay.isUtc);
+   * ```
+   *
+   */
+  final bool isUtc;
+
+  /**
+   * Constructs a [DateTime] instance specified in the local time zone.
+   *
+   * For example,
+   * to create a new DateTime object representing the 7th of September 2017,
+   * 5:30pm
+   *
+   * ```
+   * var dentistAppointment = new DateTime(2017, 9, 7, 17, 30);
+   * ```
+   */
+  DateTime(int year,
+      [int month = 1,
+      int day = 1,
+      int hour = 0,
+      int minute = 0,
+      int second = 0,
+      int millisecond = 0,
+      int microsecond = 0])
+      : this._internal(year, month, day, hour, minute, second, millisecond,
+            microsecond, false);
+
+  /**
+   * Constructs a [DateTime] instance specified in the UTC time zone.
+   *
+   * ```
+   * var moonLanding = new DateTime.utc(1969, 7, 20, 20, 18, 04);
+   * ```
+   *
+   * When dealing with dates or historic events prefer to use UTC DateTimes,
+   * since they are unaffected by daylight-saving changes and are unaffected
+   * by the local timezone.
+   */
+  DateTime.utc(int year,
+      [int month = 1,
+      int day = 1,
+      int hour = 0,
+      int minute = 0,
+      int second = 0,
+      int millisecond = 0,
+      int microsecond = 0])
+      : this._internal(year, month, day, hour, minute, second, millisecond,
+            microsecond, true);
+
+  /**
+   * Constructs a [DateTime] instance with current date and time in the
+   * local time zone.
+   *
+   * ```
+   * var thisInstant = new DateTime.now();
+   * ```
+   */
+  DateTime.now() : this._now();
+
+  /**
+   * Constructs a new [DateTime] instance based on [formattedString].
+   *
+   * The [formattedString] must not be `null`.
+   * Throws a [FormatException] if the input string cannot be parsed.
+   *
+   * The function parses a subset of ISO 8601
+   * which includes the subset accepted by RFC 3339.
+   *
+   * The accepted inputs are currently:
+   *
+   * * A date: A signed four-to-six digit year, two digit month and
+   *   two digit day, optionally separated by `-` characters.
+   *   Examples: "19700101", "-0004-12-24", "81030-04-01".
+   * * An optional time part, separated from the date by either `T` or a space.
+   *   The time part is a two digit hour,
+   *   then optionally a two digit minutes value,
+   *   then optionally a two digit seconds value, and
+   *   then optionally a '.' or ',' followed by a one-to-six digit second fraction.
+   *   The minutes and seconds may be separated from the previous parts by a
+   *   ':'.
+   *   Examples: "12", "12:30:24.124", "12:30:24,124", "123010.50".
+   * * An optional time-zone offset part,
+   *   possibly separated from the previous by a space.
+   *   The time zone is either 'z' or 'Z', or it is a signed two digit hour
+   *   part and an optional two digit minute part. The sign must be either
+   *   "+" or "-", and can not be omitted.
+   *   The minutes may be separated from the hours by a ':'.
+   *   Examples: "Z", "-10", "+01:30", "+1130".
+   *
+   * This includes the output of both [toString] and [toIso8601String], which
+   * will be parsed back into a `DateTime` object with the same time as the
+   * original.
+   *
+   * The result is always in either local time or UTC.
+   * If a time zone offset other than UTC is specified,
+   * the time is converted to the equivalent UTC time.
+   *
+   * Examples of accepted strings:
+   *
+   * * `"2012-02-27 13:27:00"`
+   * * `"2012-02-27 13:27:00.123456z"`
+   * * `"2012-02-27 13:27:00,123456z"`
+   * * `"20120227 13:27:00"`
+   * * `"20120227T132700"`
+   * * `"20120227"`
+   * * `"+20120227"`
+   * * `"2012-02-27T14Z"`
+   * * `"2012-02-27T14+00:00"`
+   * * `"-123450101 00:00:00 Z"`: in the year -12345.
+   * * `"2002-02-27T14:00:00-0500"`: Same as `"2002-02-27T19:00:00Z"`
+   */
+  // TODO(lrn): restrict incorrect values like  2003-02-29T50:70:80.
+  // Or not, that may be a breaking change.
+  static DateTime parse(String formattedString) {
+    var re = _parseFormat;
+    Match match = re.firstMatch(formattedString);
+    if (match != null) {
+      int parseIntOrZero(String matched) {
+        if (matched == null) return 0;
+        return int.parse(matched);
+      }
+
+      // Parses fractional second digits of '.(\d{1,6})' into the combined
+      // microseconds.
+      int parseMilliAndMicroseconds(String matched) {
+        if (matched == null) return 0;
+        int length = matched.length;
+        assert(length >= 1);
+        assert(length <= 6);
+
+        int result = 0;
+        for (int i = 0; i < 6; i++) {
+          result *= 10;
+          if (i < matched.length) {
+            result += matched.codeUnitAt(i) ^ 0x30;
+          }
+        }
+        return result;
+      }
+
+      int years = int.parse(match[1]);
+      int month = int.parse(match[2]);
+      int day = int.parse(match[3]);
+      int hour = parseIntOrZero(match[4]);
+      int minute = parseIntOrZero(match[5]);
+      int second = parseIntOrZero(match[6]);
+      bool addOneMillisecond = false;
+      int milliAndMicroseconds = parseMilliAndMicroseconds(match[7]);
+      int millisecond =
+          milliAndMicroseconds ~/ Duration.microsecondsPerMillisecond;
+      int microsecond =
+          milliAndMicroseconds.remainder(Duration.microsecondsPerMillisecond);
+      bool isUtc = false;
+      if (match[8] != null) {
+        // timezone part
+        isUtc = true;
+        if (match[9] != null) {
+          // timezone other than 'Z' and 'z'.
+          int sign = (match[9] == '-') ? -1 : 1;
+          int hourDifference = int.parse(match[10]);
+          int minuteDifference = parseIntOrZero(match[11]);
+          minuteDifference += 60 * hourDifference;
+          minute -= sign * minuteDifference;
+        }
+      }
+      int value = _brokenDownDateToValue(years, month, day, hour, minute,
+          second, millisecond, microsecond, isUtc);
+      if (value == null) {
+        throw FormatException("Time out of range", formattedString);
+      }
+      return DateTime._withValue(value, isUtc: isUtc);
+    } else {
+      throw FormatException("Invalid date format", formattedString);
+    }
+  }
+
+  /**
+   * Constructs a new [DateTime] instance based on [formattedString].
+   *
+   * Works like [parse] except that this function returns `null`
+   * where [parse] would throw a [FormatException].
+   */
+  static DateTime tryParse(String formattedString) {
+    // TODO: Optimize to avoid throwing.
+    try {
+      return parse(formattedString);
+    } on FormatException {
+      return null;
+    }
+  }
+
+  static const int _maxMillisecondsSinceEpoch = 8640000000000000;
+
+  /**
+   * Constructs a new [DateTime] instance
+   * with the given [millisecondsSinceEpoch].
+   *
+   * If [isUtc] is false then the date is in the local time zone.
+   *
+   * The constructed [DateTime] represents
+   * 1970-01-01T00:00:00Z + [millisecondsSinceEpoch] ms in the given
+   * time zone (local or UTC).
+   */
+  external DateTime.fromMillisecondsSinceEpoch(int millisecondsSinceEpoch,
+      {bool isUtc = false});
+
+  /**
+   * Constructs a new [DateTime] instance
+   * with the given [microsecondsSinceEpoch].
+   *
+   * If [isUtc] is false then the date is in the local time zone.
+   *
+   * The constructed [DateTime] represents
+   * 1970-01-01T00:00:00Z + [microsecondsSinceEpoch] us in the given
+   * time zone (local or UTC).
+   */
+  external DateTime.fromMicrosecondsSinceEpoch(int microsecondsSinceEpoch,
+      {bool isUtc = false});
+
+  /**
+   * Constructs a new [DateTime] instance with the given value.
+   *
+   * If [isUtc] is false then the date is in the local time zone.
+   */
+  DateTime._withValue(this._value, {this.isUtc}) {
+    if (millisecondsSinceEpoch.abs() > _maxMillisecondsSinceEpoch ||
+        (millisecondsSinceEpoch.abs() == _maxMillisecondsSinceEpoch &&
+            microsecond != 0)) {
+      throw ArgumentError(
+          "DateTime is outside valid range: $millisecondsSinceEpoch");
+    }
+    if (isUtc == null) {
+      throw ArgumentError("'isUtc' flag may not be 'null'");
+    }
+  }
+
+  /**
+   * Returns true if [other] is a [DateTime] at the same moment and in the
+   * same time zone (UTC or local).
+   *
+   * ```
+   * var dDayUtc = new DateTime.utc(1944, 6, 6);
+   * var dDayLocal = dDayUtc.toLocal();
+   *
+   * // These two dates are at the same moment, but are in different zones.
+   * assert(dDayUtc != dDayLocal);
+   * ```
+   *
+   * See [isAtSameMomentAs] for a comparison that compares moments in time
+   * independently of their zones.
+   */
+  external bool operator ==(dynamic other);
+
+  /**
+   * Returns true if [this] occurs before [other].
+   *
+   * The comparison is independent
+   * of whether the time is in UTC or in the local time zone.
+   *
+   * ```
+   * var now = new DateTime.now();
+   * var earlier = now.subtract(const Duration(seconds: 5));
+   * assert(earlier.isBefore(now));
+   * assert(!now.isBefore(now));
+   *
+   * // This relation stays the same, even when changing timezones.
+   * assert(earlier.isBefore(now.toUtc()));
+   * assert(earlier.toUtc().isBefore(now));
+   *
+   * assert(!now.toUtc().isBefore(now));
+   * assert(!now.isBefore(now.toUtc()));
+   * ```
+   */
+  external bool isBefore(DateTime other);
+
+  /**
+   * Returns true if [this] occurs after [other].
+   *
+   * The comparison is independent
+   * of whether the time is in UTC or in the local time zone.
+   *
+   * ```
+   * var now = new DateTime.now();
+   * var later = now.add(const Duration(seconds: 5));
+   * assert(later.isAfter(now));
+   * assert(!now.isBefore(now));
+   *
+   * // This relation stays the same, even when changing timezones.
+   * assert(later.isAfter(now.toUtc()));
+   * assert(later.toUtc().isAfter(now));
+   *
+   * assert(!now.toUtc().isBefore(now));
+   * assert(!now.isBefore(now.toUtc()));
+   * ```
+   */
+  external bool isAfter(DateTime other);
+
+  /**
+   * Returns true if [this] occurs at the same moment as [other].
+   *
+   * The comparison is independent of whether the time is in UTC or in the local
+   * time zone.
+   *
+   * ```
+   * var now = new DateTime.now();
+   * var later = now.add(const Duration(seconds: 5));
+   * assert(!later.isAtSameMomentAs(now));
+   * assert(now.isAtSameMomentAs(now));
+   *
+   * // This relation stays the same, even when changing timezones.
+   * assert(!later.isAtSameMomentAs(now.toUtc()));
+   * assert(!later.toUtc().isAtSameMomentAs(now));
+   *
+   * assert(now.toUtc().isAtSameMomentAs(now));
+   * assert(now.isAtSameMomentAs(now.toUtc()));
+   * ```
+   */
+  external bool isAtSameMomentAs(DateTime other);
+
+  /**
+   * Compares this DateTime object to [other],
+   * returning zero if the values are equal.
+   *
+   * Returns a negative value if this DateTime [isBefore] [other]. It returns 0
+   * if it [isAtSameMomentAs] [other], and returns a positive value otherwise
+   * (when this [isAfter] [other]).
+   */
+  external int compareTo(DateTime other);
+
+  int get hashCode => (_value ^ (_value >> 30)) & 0x3FFFFFFF;
+
+  /**
+   * Returns this DateTime value in the local time zone.
+   *
+   * Returns [this] if it is already in the local time zone.
+   * Otherwise this method is equivalent to:
+   *
+   * ```
+   * new DateTime.fromMicrosecondsSinceEpoch(microsecondsSinceEpoch,
+   *                                         isUtc: false)
+   * ```
+   */
+  DateTime toLocal() {
+    if (isUtc) {
+      return DateTime._withValue(_value, isUtc: false);
+    }
+    return this;
+  }
+
+  /**
+   * Returns this DateTime value in the UTC time zone.
+   *
+   * Returns [this] if it is already in UTC.
+   * Otherwise this method is equivalent to:
+   *
+   * ```
+   * new DateTime.fromMicrosecondsSinceEpoch(microsecondsSinceEpoch,
+   *                                         isUtc: true)
+   * ```
+   */
+  DateTime toUtc() {
+    if (isUtc) return this;
+    return DateTime._withValue(_value, isUtc: true);
+  }
+
+  static String _fourDigits(int n) {
+    int absN = n.abs();
+    String sign = n < 0 ? "-" : "";
+    if (absN >= 1000) return "$n";
+    if (absN >= 100) return "${sign}0$absN";
+    if (absN >= 10) return "${sign}00$absN";
+    return "${sign}000$absN";
+  }
+
+  static String _sixDigits(int n) {
+    assert(n < -9999 || n > 9999);
+    int absN = n.abs();
+    String sign = n < 0 ? "-" : "+";
+    if (absN >= 100000) return "$sign$absN";
+    return "${sign}0$absN";
+  }
+
+  static String _threeDigits(int n) {
+    if (n >= 100) return "${n}";
+    if (n >= 10) return "0${n}";
+    return "00${n}";
+  }
+
+  static String _twoDigits(int n) {
+    if (n >= 10) return "${n}";
+    return "0${n}";
+  }
+
+  /**
+   * Returns a human-readable string for this instance.
+   *
+   * The returned string is constructed for the time zone of this instance.
+   * The `toString()` method provides a simply formatted string.
+   * It does not support internationalized strings.
+   * Use the [intl](https://pub.dartlang.org/packages/intl) package
+   * at the pub shared packages repo.
+   *
+   * The resulting string can be parsed back using [parse].
+   */
+  String toString() {
+    String y = _fourDigits(year);
+    String m = _twoDigits(month);
+    String d = _twoDigits(day);
+    String h = _twoDigits(hour);
+    String min = _twoDigits(minute);
+    String sec = _twoDigits(second);
+    String ms = _threeDigits(millisecond);
+    String us = microsecond == 0 ? "" : _threeDigits(microsecond);
+    if (isUtc) {
+      return "$y-$m-$d $h:$min:$sec.$ms${us}Z";
+    } else {
+      return "$y-$m-$d $h:$min:$sec.$ms$us";
+    }
+  }
+
+  /**
+   * Returns an ISO-8601 full-precision extended format representation.
+   *
+   * The format is `yyyy-MM-ddTHH:mm:ss.mmmuuuZ` for UTC time, and
+   * `yyyy-MM-ddTHH:mm:ss.mmmuuu` (no trailing "Z") for local/non-UTC time,
+   * where:
+   *
+   * * `yyyy` is a, possibly negative, four digit representation of the year,
+   *   if the year is in the range -9999 to 9999,
+   *   otherwise it is a signed six digit representation of the year.
+   * * `MM` is the month in the range 01 to 12,
+   * * `dd` is the day of the month in the range 01 to 31,
+   * * `HH` are hours in the range 00 to 23,
+   * * `mm` are minutes in the range 00 to 59,
+   * * `ss` are seconds in the range 00 to 59 (no leap seconds),
+   * * `mmm` are milliseconds in the range 000 to 999, and
+   * * `uuu` are microseconds in the range 001 to 999. If [microsecond] equals
+   *   0, then this part is omitted.
+   *
+   * The resulting string can be parsed back using [parse].
+   */
+  String toIso8601String() {
+    String y =
+        (year >= -9999 && year <= 9999) ? _fourDigits(year) : _sixDigits(year);
+    String m = _twoDigits(month);
+    String d = _twoDigits(day);
+    String h = _twoDigits(hour);
+    String min = _twoDigits(minute);
+    String sec = _twoDigits(second);
+    String ms = _threeDigits(millisecond);
+    String us = microsecond == 0 ? "" : _threeDigits(microsecond);
+    if (isUtc) {
+      return "$y-$m-${d}T$h:$min:$sec.$ms${us}Z";
+    } else {
+      return "$y-$m-${d}T$h:$min:$sec.$ms$us";
+    }
+  }
+
+  /**
+   * Returns a new [DateTime] instance with [duration] added to [this].
+   *
+   * ```
+   * var today = new DateTime.now();
+   * var fiftyDaysFromNow = today.add(new Duration(days: 50));
+   * ```
+   *
+   * Notice that the duration being added is actually 50 * 24 * 60 * 60
+   * seconds. If the resulting `DateTime` has a different daylight saving offset
+   * than `this`, then the result won't have the same time-of-day as `this`, and
+   * may not even hit the calendar date 50 days later.
+   *
+   * Be careful when working with dates in local time.
+   */
+  external DateTime add(Duration duration);
+
+  /**
+   * Returns a new [DateTime] instance with [duration] subtracted from [this].
+   *
+   * ```
+   * DateTime today = new DateTime.now();
+   * DateTime fiftyDaysAgo = today.subtract(new Duration(days: 50));
+   * ```
+   *
+   * Notice that the duration being subtracted is actually 50 * 24 * 60 * 60
+   * seconds. If the resulting `DateTime` has a different daylight saving offset
+   * than `this`, then the result won't have the same time-of-day as `this`, and
+   * may not even hit the calendar date 50 days earlier.
+   *
+   * Be careful when working with dates in local time.
+   */
+  external DateTime subtract(Duration duration);
+
+  /**
+   * Returns a [Duration] with the difference between [this] and [other].
+   *
+   * ```
+   * var berlinWallFell = new DateTime.utc(1989, DateTime.november, 9);
+   * var dDay = new DateTime.utc(1944, DateTime.june, 6);
+   *
+   * Duration difference = berlinWallFell.difference(dDay);
+   * assert(difference.inDays == 16592);
+   * ```
+   *
+   * The difference is measured in seconds and fractions of seconds.
+   * The difference above counts the number of fractional seconds between
+   * midnight at the beginning of those dates.
+   * If the dates above had been in local time, not UTC, then the difference
+   * between two midnights may not be a multiple of 24 hours due to daylight
+   * saving differences.
+   *
+   * For example, in Australia, similar code using local time instead of UTC:
+   *
+   * ```
+   * var berlinWallFell = new DateTime(1989, DateTime.november, 9);
+   * var dDay = new DateTime(1944, DateTime.june, 6);
+   * Duration difference = berlinWallFell.difference(dDay);
+   * assert(difference.inDays == 16592);
+   * ```
+   * will fail because the difference is actually 16591 days and 23 hours, and
+   * [Duration.inDays] only returns the number of whole days.
+   */
+  external Duration difference(DateTime other);
+
+  external DateTime._internal(int year, int month, int day, int hour,
+      int minute, int second, int millisecond, int microsecond, bool isUtc);
+
+  external DateTime._now();
+
+  /// Returns the time as value (millisecond or microsecond since epoch), or
+  /// null if the values are out of range.
+  external static int _brokenDownDateToValue(
+      int year,
+      int month,
+      int day,
+      int hour,
+      int minute,
+      int second,
+      int millisecond,
+      int microsecond,
+      bool isUtc);
+
+  /**
+   * The number of milliseconds since
+   * the "Unix epoch" 1970-01-01T00:00:00Z (UTC).
+   *
+   * This value is independent of the time zone.
+   *
+   * This value is at most
+   * 8,640,000,000,000,000ms (100,000,000 days) from the Unix epoch.
+   * In other words: `millisecondsSinceEpoch.abs() <= 8640000000000000`.
+   */
+  external int get millisecondsSinceEpoch;
+
+  /**
+   * The number of microseconds since
+   * the "Unix epoch" 1970-01-01T00:00:00Z (UTC).
+   *
+   * This value is independent of the time zone.
+   *
+   * This value is at most
+   * 8,640,000,000,000,000,000us (100,000,000 days) from the Unix epoch.
+   * In other words: `microsecondsSinceEpoch.abs() <= 8640000000000000000`.
+   *
+   * Note that this value does not fit into 53 bits (the size of a IEEE double).
+   * A JavaScript number is not able to hold this value.
+   */
+  external int get microsecondsSinceEpoch;
+
+  /**
+   * The time zone name.
+   *
+   * This value is provided by the operating system and may be an
+   * abbreviation or a full name.
+   *
+   * In the browser or on Unix-like systems commonly returns abbreviations,
+   * such as "CET" or "CEST". On Windows returns the full name, for example
+   * "Pacific Standard Time".
+   */
+  external String get timeZoneName;
+
+  /**
+   * The time zone offset, which
+   * is the difference between local time and UTC.
+   *
+   * The offset is positive for time zones east of UTC.
+   *
+   * Note, that JavaScript, Python and C return the difference between UTC and
+   * local time. Java, C# and Ruby return the difference between local time and
+   * UTC.
+   */
+  external Duration get timeZoneOffset;
+
+  /**
+   * The year.
+   *
+   * ```
+   * var moonLanding = DateTime.parse("1969-07-20 20:18:04Z");
+   * assert(moonLanding.year == 1969);
+   * ```
+   */
+  external int get year;
+
+  /**
+   * The month [1..12].
+   *
+   * ```
+   * var moonLanding = DateTime.parse("1969-07-20 20:18:04Z");
+   * assert(moonLanding.month == 7);
+   * assert(moonLanding.month == DateTime.july);
+   * ```
+   */
+  external int get month;
+
+  /**
+   * The day of the month [1..31].
+   *
+   * ```
+   * var moonLanding = DateTime.parse("1969-07-20 20:18:04Z");
+   * assert(moonLanding.day == 20);
+   * ```
+   */
+  external int get day;
+
+  /**
+   * The hour of the day, expressed as in a 24-hour clock [0..23].
+   *
+   * ```
+   * var moonLanding = DateTime.parse("1969-07-20 20:18:04Z");
+   * assert(moonLanding.hour == 20);
+   * ```
+   */
+  external int get hour;
+
+  /**
+   * The minute [0...59].
+   *
+   * ```
+   * var moonLanding = DateTime.parse("1969-07-20 20:18:04Z");
+   * assert(moonLanding.minute == 18);
+   * ```
+   */
+  external int get minute;
+
+  /**
+   * The second [0...59].
+   *
+   * ```
+   * var moonLanding = DateTime.parse("1969-07-20 20:18:04Z");
+   * assert(moonLanding.second == 4);
+   * ```
+   */
+  external int get second;
+
+  /**
+   * The millisecond [0...999].
+   *
+   * ```
+   * var moonLanding = DateTime.parse("1969-07-20 20:18:04Z");
+   * assert(moonLanding.millisecond == 0);
+   * ```
+   */
+  external int get millisecond;
+
+  /**
+   * The microsecond [0...999].
+   *
+   * ```
+   * var moonLanding = DateTime.parse("1969-07-20 20:18:04Z");
+   * assert(moonLanding.microsecond == 0);
+   * ```
+   */
+  external int get microsecond;
+
+  /**
+   * The day of the week [monday]..[sunday].
+   *
+   * In accordance with ISO 8601
+   * a week starts with Monday, which has the value 1.
+   *
+   * ```
+   * var moonLanding = DateTime.parse("1969-07-20 20:18:04Z");
+   * assert(moonLanding.weekday == 7);
+   * assert(moonLanding.weekday == DateTime.sunday);
+   * ```
+   */
+  external int get weekday;
+
+  /*
+   * date ::= yeardate time_opt timezone_opt
+   * yeardate ::= year colon_opt month colon_opt day
+   * year ::= sign_opt digit{4,6}
+   * colon_opt :: <empty> | ':'
+   * sign ::= '+' | '-'
+   * sign_opt ::=  <empty> | sign
+   * month ::= digit{2}
+   * day ::= digit{2}
+   * time_opt ::= <empty> | (' ' | 'T') hour minutes_opt
+   * minutes_opt ::= <empty> | colon_opt digit{2} seconds_opt
+   * seconds_opt ::= <empty> | colon_opt digit{2} millis_opt
+   * micros_opt ::= <empty> | ('.' | ',') digit{1,6}
+   * timezone_opt ::= <empty> | space_opt timezone
+   * space_opt :: ' ' | <empty>
+   * timezone ::= 'z' | 'Z' | sign digit{2} timezonemins_opt
+   * timezonemins_opt ::= <empty> | colon_opt digit{2}
+   */
+  static final RegExp _parseFormat = RegExp(
+      r'^([+-]?\d{4,6})-?(\d\d)-?(\d\d)' // Day part.
+      r'(?:[ T](\d\d)(?::?(\d\d)(?::?(\d\d)(?:[.,](\d{1,6}))?)?)?' // Time part.
+      r'( ?[zZ]| ?([-+])(\d\d)(?::?(\d\d))?)?)?$'); // Timezone part.
+}
diff --git a/sdk_nnbd/lib/core/double.dart b/sdk_nnbd/lib/core/double.dart
new file mode 100644
index 0000000..61191ec
--- /dev/null
+++ b/sdk_nnbd/lib/core/double.dart
@@ -0,0 +1,218 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.core;
+
+// TODO: Convert this abstract class into a concrete class double
+// that uses the patch class functionality to account for the
+// different platform implementations.
+
+/**
+ * A double-precision floating point number.
+ *
+ * Representation of Dart doubles containing double specific constants
+ * and operations and specializations of operations inherited from
+ * [num]. Dart doubles are 64-bit floating-point numbers as specified in the
+ * IEEE 754 standard.
+ *
+ * The [double] type is contagious. Operations on [double]s return
+ * [double] results.
+ *
+ * It is a compile-time error for a class to attempt to extend or implement
+ * double.
+ */
+abstract class double extends num {
+  static const double nan = 0.0 / 0.0;
+  static const double infinity = 1.0 / 0.0;
+  static const double negativeInfinity = -infinity;
+  static const double minPositive = 5e-324;
+  static const double maxFinite = 1.7976931348623157e+308;
+
+  double remainder(num other);
+
+  /** Addition operator. */
+  double operator +(num other);
+
+  /** Subtraction operator. */
+  double operator -(num other);
+
+  /** Multiplication operator. */
+  double operator *(num other);
+
+  double operator %(num other);
+
+  /** Division operator. */
+  double operator /(num other);
+
+  /**
+   * Truncating division operator.
+   *
+   * The result of the truncating division `a ~/ b` is equivalent to
+   * `(a / b).truncate()`.
+   */
+  int operator ~/(num other);
+
+  /** Negate operator. */
+  double operator -();
+
+  /** Returns the absolute value of this [double]. */
+  double abs();
+
+  /**
+   * Returns the sign of the double's numerical value.
+   *
+   * Returns -1.0 if the value is less than zero,
+   * +1.0 if the value is greater than zero,
+   * and the value itself if it is -0.0, 0.0 or NaN.
+   */
+  double get sign;
+
+  /**
+   * Returns the integer closest to `this`.
+   *
+   * Rounds away from zero when there is no closest integer:
+   *  `(3.5).round() == 4` and `(-3.5).round() == -4`.
+   *
+   * If `this` is not finite (`NaN` or infinity), throws an [UnsupportedError].
+   */
+  int round();
+
+  /**
+   * Returns the greatest integer no greater than `this`.
+   *
+   * If `this` is not finite (`NaN` or infinity), throws an [UnsupportedError].
+   */
+  int floor();
+
+  /**
+   * Returns the least integer no smaller than `this`.
+   *
+   * If `this` is not finite (`NaN` or infinity), throws an [UnsupportedError].
+   */
+  int ceil();
+
+  /**
+   * Returns the integer obtained by discarding any fractional
+   * digits from `this`.
+   *
+   * If `this` is not finite (`NaN` or infinity), throws an [UnsupportedError].
+   */
+  int truncate();
+
+  /**
+   * Returns the integer double value closest to `this`.
+   *
+   * Rounds away from zero when there is no closest integer:
+   *  `(3.5).roundToDouble() == 4` and `(-3.5).roundToDouble() == -4`.
+   *
+   * If this is already an integer valued double, including `-0.0`, or it is not
+   * a finite value, the value is returned unmodified.
+   *
+   * For the purpose of rounding, `-0.0` is considered to be below `0.0`,
+   * and `-0.0` is therefore considered closer to negative numbers than `0.0`.
+   * This means that for a value, `d` in the range `-0.5 < d < 0.0`,
+   * the result is `-0.0`.
+   */
+  double roundToDouble();
+
+  /**
+   * Returns the greatest integer double value no greater than `this`.
+   *
+   * If this is already an integer valued double, including `-0.0`, or it is not
+   * a finite value, the value is returned unmodified.
+   *
+   * For the purpose of rounding, `-0.0` is considered to be below `0.0`.
+   * A number `d` in the range `0.0 < d < 1.0` will return `0.0`.
+   */
+  double floorToDouble();
+
+  /**
+   * Returns the least integer double value no smaller than `this`.
+   *
+   * If this is already an integer valued double, including `-0.0`, or it is not
+   * a finite value, the value is returned unmodified.
+   *
+   * For the purpose of rounding, `-0.0` is considered to be below `0.0`.
+   * A number `d` in the range `-1.0 < d < 0.0` will return `-0.0`.
+   */
+  double ceilToDouble();
+
+  /**
+   * Returns the integer double value obtained by discarding any fractional
+   * digits from `this`.
+   *
+   * If this is already an integer valued double, including `-0.0`, or it is not
+   * a finite value, the value is returned unmodified.
+   *
+   * For the purpose of rounding, `-0.0` is considered to be below `0.0`.
+   * A number `d` in the range `-1.0 < d < 0.0` will return `-0.0`, and
+   * in the range `0.0 < d < 1.0` it will return 0.0.
+   */
+  double truncateToDouble();
+
+  /**
+   * Provide a representation of this [double] value.
+   *
+   * The representation is a number literal such that the closest double value
+   * to the representation's mathematical value is this [double].
+   *
+   * Returns "NaN" for the Not-a-Number value.
+   * Returns "Infinity" and "-Infinity" for positive and negative Infinity.
+   * Returns "-0.0" for negative zero.
+   *
+   * For all doubles, `d`, converting to a string and parsing the string back
+   * gives the same value again: `d == double.parse(d.toString())` (except when
+   * `d` is NaN).
+   */
+  String toString();
+
+  /**
+   * Parse [source] as an double literal and return its value.
+   *
+   * Accepts an optional sign (`+` or `-`) followed by either the characters
+   * "Infinity", the characters "NaN" or a floating-point representation.
+   * A floating-point representation is composed of a mantissa and an optional
+   * exponent part. The mantissa is either a decimal point (`.`) followed by a
+   * sequence of (decimal) digits, or a sequence of digits
+   * optionally followed by a decimal point and optionally more digits. The
+   * (optional) exponent part consists of the character "e" or "E", an optional
+   * sign, and one or more digits.
+   * The [source] must not be `null`.
+   *
+   * Leading and trailing whitespace is ignored.
+   *
+   * If the [source] string is not a valid double literal, the [onError]
+   * is called with the [source] as argument, and its return value is
+   * used instead. If no `onError` is provided, a [FormatException]
+   * is thrown instead.
+   *
+   * The [onError] function is only invoked if [source] is a [String] with an
+   * invalid format. It is not invoked if [source] is `null`.
+   *
+   * Examples of accepted strings:
+   *
+   *     "3.14"
+   *     "  3.14 \xA0"
+   *     "0."
+   *     ".0"
+   *     "-1.e3"
+   *     "1234E+7"
+   *     "+.12e-9"
+   *     "-NaN"
+   *
+   * The [onError] parameter is deprecated and will be removed.
+   * Instead of `double.parse(string, (string) { ... })`,
+   * you should use `double.tryParse(string) ?? (...)`.
+   */
+  external static double parse(String source,
+      [@deprecated double onError(String source)]);
+
+  /**
+   * Parse [source] as an double literal and return its value.
+   *
+   * Like [parse] except that this function returns `null` for invalid inputs
+   * instead of throwing, and the [source] must still not be `null`.
+   */
+  external static double tryParse(String source);
+}
diff --git a/sdk_nnbd/lib/core/duration.dart b/sdk_nnbd/lib/core/duration.dart
new file mode 100644
index 0000000..914f05a
--- /dev/null
+++ b/sdk_nnbd/lib/core/duration.dart
@@ -0,0 +1,293 @@
+// Copyright (c) 2011, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.core;
+
+/**
+ * A span of time, such as 27 days, 4 hours, 12 minutes, and 3 seconds.
+ *
+ * A `Duration` represents a difference from one point in time to another. The
+ * duration may be "negative" if the difference is from a later time to an
+ * earlier.
+ *
+ * Durations are context independent. For example, a duration of 2 days is
+ * always 48 hours, even when it is added to a `DateTime` just when the
+ * time zone is about to do a daylight-savings switch. (See [DateTime.add]).
+ *
+ * Despite the same name, a `Duration` object does not implement "Durations"
+ * as specified by ISO 8601. In particular, a duration object does not keep
+ * track of the individually provided members (such as "days" or "hours"), but
+ * only uses these arguments to compute the length of the corresponding time
+ * interval.
+ *
+ * To create a new Duration object, use this class's single constructor
+ * giving the appropriate arguments:
+ * ```dart
+ * Duration fastestMarathon = new Duration(hours:2, minutes:3, seconds:2);
+ * ```
+ * The [Duration] is the sum of all individual parts.
+ * This means that individual parts can be larger than the next-bigger unit.
+ * For example, [inMinutes] can be greater than 59.
+ * ```dart
+ * assert(fastestMarathon.inMinutes == 123);
+ * ```
+ * All individual parts are allowed to be negative.
+ *
+ * Use one of the properties, such as [inDays],
+ * to retrieve the integer value of the Duration in the specified time unit.
+ * Note that the returned value is rounded down.
+ * For example,
+ * ```dart
+ * Duration aLongWeekend = new Duration(hours:88);
+ * assert(aLongWeekend.inDays == 3);
+ * ```
+ * This class provides a collection of arithmetic
+ * and comparison operators,
+ * plus a set of constants useful for converting time units.
+ *
+ * See [DateTime] to represent a point in time.
+ * See [Stopwatch] to measure time-spans.
+ */
+class Duration implements Comparable<Duration> {
+  static const int microsecondsPerMillisecond = 1000;
+  static const int millisecondsPerSecond = 1000;
+  static const int secondsPerMinute = 60;
+  static const int minutesPerHour = 60;
+  static const int hoursPerDay = 24;
+
+  static const int microsecondsPerSecond =
+      microsecondsPerMillisecond * millisecondsPerSecond;
+  static const int microsecondsPerMinute =
+      microsecondsPerSecond * secondsPerMinute;
+  static const int microsecondsPerHour = microsecondsPerMinute * minutesPerHour;
+  static const int microsecondsPerDay = microsecondsPerHour * hoursPerDay;
+
+  static const int millisecondsPerMinute =
+      millisecondsPerSecond * secondsPerMinute;
+  static const int millisecondsPerHour = millisecondsPerMinute * minutesPerHour;
+  static const int millisecondsPerDay = millisecondsPerHour * hoursPerDay;
+
+  static const int secondsPerHour = secondsPerMinute * minutesPerHour;
+  static const int secondsPerDay = secondsPerHour * hoursPerDay;
+
+  static const int minutesPerDay = minutesPerHour * hoursPerDay;
+
+  static const Duration zero = Duration(seconds: 0);
+
+  /*
+   * The value of this Duration object in microseconds.
+   */
+  final int _duration;
+
+  /**
+   * Creates a new Duration object whose value
+   * is the sum of all individual parts.
+   *
+   * Individual parts can be larger than the next-bigger unit.
+   * For example, [hours] can be greater than 23.
+   *
+   * All individual parts are allowed to be negative.
+   * All arguments are 0 by default.
+   */
+  const Duration(
+      {int days = 0,
+      int hours = 0,
+      int minutes = 0,
+      int seconds = 0,
+      int milliseconds = 0,
+      int microseconds = 0})
+      : this._microseconds(microsecondsPerDay * days +
+            microsecondsPerHour * hours +
+            microsecondsPerMinute * minutes +
+            microsecondsPerSecond * seconds +
+            microsecondsPerMillisecond * milliseconds +
+            microseconds);
+
+  // Fast path internal direct constructor to avoids the optional arguments and
+  // [_microseconds] recomputation.
+  const Duration._microseconds(this._duration);
+
+  /**
+   * Adds this Duration and [other] and
+   * returns the sum as a new Duration object.
+   */
+  Duration operator +(Duration other) {
+    return Duration._microseconds(_duration + other._duration);
+  }
+
+  /**
+   * Subtracts [other] from this Duration and
+   * returns the difference as a new Duration object.
+   */
+  Duration operator -(Duration other) {
+    return Duration._microseconds(_duration - other._duration);
+  }
+
+  /**
+   * Multiplies this Duration by the given [factor] and returns the result
+   * as a new Duration object.
+   *
+   * Note that when [factor] is a double, and the duration is greater than
+   * 53 bits, precision is lost because of double-precision arithmetic.
+   */
+  Duration operator *(num factor) {
+    return Duration._microseconds((_duration * factor).round());
+  }
+
+  /**
+   * Divides this Duration by the given [quotient] and returns the truncated
+   * result as a new Duration object.
+   *
+   * Throws an [IntegerDivisionByZeroException] if [quotient] is `0`.
+   */
+  Duration operator ~/(int quotient) {
+    // By doing the check here instead of relying on "~/" below we get the
+    // exception even with dart2js.
+    if (quotient == 0) throw IntegerDivisionByZeroException();
+    return Duration._microseconds(_duration ~/ quotient);
+  }
+
+  /**
+   * Returns `true` if the value of this Duration
+   * is less than the value of [other].
+   */
+  bool operator <(Duration other) => this._duration < other._duration;
+
+  /**
+   * Returns `true` if the value of this Duration
+   * is greater than the value of [other].
+   */
+  bool operator >(Duration other) => this._duration > other._duration;
+
+  /**
+   * Returns `true` if the value of this Duration
+   * is less than or equal to the value of [other].
+   */
+  bool operator <=(Duration other) => this._duration <= other._duration;
+
+  /**
+   * Returns `true` if the value of this Duration
+   * is greater than or equal to the value of [other].
+   */
+  bool operator >=(Duration other) => this._duration >= other._duration;
+
+  /**
+   * Returns the number of whole days spanned by this Duration.
+   */
+  int get inDays => _duration ~/ Duration.microsecondsPerDay;
+
+  /**
+   * Returns the number of whole hours spanned by this Duration.
+   *
+   * The returned value can be greater than 23.
+   */
+  int get inHours => _duration ~/ Duration.microsecondsPerHour;
+
+  /**
+   * Returns the number of whole minutes spanned by this Duration.
+   *
+   * The returned value can be greater than 59.
+   */
+  int get inMinutes => _duration ~/ Duration.microsecondsPerMinute;
+
+  /**
+   * Returns the number of whole seconds spanned by this Duration.
+   *
+   * The returned value can be greater than 59.
+   */
+  int get inSeconds => _duration ~/ Duration.microsecondsPerSecond;
+
+  /**
+   * Returns number of whole milliseconds spanned by this Duration.
+   *
+   * The returned value can be greater than 999.
+   */
+  int get inMilliseconds => _duration ~/ Duration.microsecondsPerMillisecond;
+
+  /**
+   * Returns number of whole microseconds spanned by this Duration.
+   */
+  int get inMicroseconds => _duration;
+
+  /**
+   * Returns `true` if this [Duration] has the same value as [other].
+   */
+  bool operator ==(dynamic other) =>
+      other is Duration && _duration == other.inMicroseconds;
+
+  int get hashCode => _duration.hashCode;
+
+  /**
+   * Compares this [Duration] to [other], returning zero if the values are equal.
+   *
+   * Returns a negative integer if this `Duration` is shorter than
+   * [other], or a positive integer if it is longer.
+   *
+   * A negative `Duration` is always considered shorter than a positive one.
+   *
+   * It is always the case that `duration1.compareTo(duration2) < 0` iff
+   * `(someDate + duration1).compareTo(someDate + duration2) < 0`.
+   */
+  int compareTo(Duration other) => _duration.compareTo(other._duration);
+
+  /**
+   * Returns a string representation of this `Duration`.
+   *
+   * Returns a string with hours, minutes, seconds, and microseconds, in the
+   * following format: `HH:MM:SS.mmmmmm`. For example,
+   *
+   *     var d = new Duration(days:1, hours:1, minutes:33, microseconds: 500);
+   *     d.toString();  // "25:33:00.000500"
+   */
+  String toString() {
+    String sixDigits(int n) {
+      if (n >= 100000) return "$n";
+      if (n >= 10000) return "0$n";
+      if (n >= 1000) return "00$n";
+      if (n >= 100) return "000$n";
+      if (n >= 10) return "0000$n";
+      return "00000$n";
+    }
+
+    String twoDigits(int n) {
+      if (n >= 10) return "$n";
+      return "0$n";
+    }
+
+    if (inMicroseconds < 0) {
+      return "-${-this}";
+    }
+    String twoDigitMinutes = twoDigits(inMinutes.remainder(minutesPerHour));
+    String twoDigitSeconds = twoDigits(inSeconds.remainder(secondsPerMinute));
+    String sixDigitUs =
+        sixDigits(inMicroseconds.remainder(microsecondsPerSecond));
+    return "$inHours:$twoDigitMinutes:$twoDigitSeconds.$sixDigitUs";
+  }
+
+  /**
+   * Returns whether this `Duration` is negative.
+   *
+   * A negative `Duration` represents the difference from a later time to an
+   * earlier time.
+   */
+  bool get isNegative => _duration < 0;
+
+  /**
+   * Returns a new `Duration` representing the absolute value of this
+   * `Duration`.
+   *
+   * The returned `Duration` has the same length as this one, but is always
+   * positive.
+   */
+  Duration abs() => Duration._microseconds(_duration.abs());
+
+  /**
+   * Returns a new `Duration` representing this `Duration` negated.
+   *
+   * The returned `Duration` has the same length as this one, but will have the
+   * opposite sign of this one.
+   */
+  // Using subtraction helps dart2js avoid negative zeros.
+  Duration operator -() => Duration._microseconds(0 - _duration);
+}
diff --git a/sdk_nnbd/lib/core/errors.dart b/sdk_nnbd/lib/core/errors.dart
new file mode 100644
index 0000000..53f3d35
--- /dev/null
+++ b/sdk_nnbd/lib/core/errors.dart
@@ -0,0 +1,588 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.core;
+
+/**
+ * Error objects thrown in the case of a program failure.
+ *
+ * An `Error` object represents a program failure that the programmer
+ * should have avoided.
+ *
+ * Examples include calling a function with invalid arguments,
+ * or even with the wrong number of arguments,
+ * or calling it at a time when it is not allowed.
+ *
+ * These are not errors that a caller should expect or catch -
+ * if they occur, the program is erroneous,
+ * and terminating the program may be the safest response.
+ *
+ * When deciding that a function throws an error,
+ * the conditions where it happens should be clearly described,
+ * and they should be detectable and predictable,
+ * so the programmer using the function can avoid triggering the error.
+ *
+ * Such descriptions often uses words like
+ * "must" or "must not" to describe the condition,
+ * and if you see words like that in a function's documentation,
+ * then not satisfying the requirement
+ * is very likely to cause an error to be thrown.
+ *
+ * Example (from [String.contains]):
+ *
+ *        `startIndex` must not be negative or greater than `length`.
+ *
+ * In this case, an error will be thrown if `startIndex` is negative
+ * or too large.
+ *
+ * If the conditions are not detectable before calling a function,
+ * the called function should not throw an `Error`.
+ * It may still throw a value,
+ * but the caller will have to catch the thrown value,
+ * effectively making it an alternative result rather than an error.
+ * The thrown object can choose to implement [Exception]
+ * to document that it represents an exceptional, but not erroneous, occurrence,
+ * but it has no other effect than documentation.
+ *
+ * All non-`null` values can be thrown in Dart.
+ * Objects extending `Error` are handled specially:
+ * The first time they are thrown,
+ * the stack trace at the throw point is recorded
+ * and stored in the error object.
+ * It can be retrieved using the [stackTrace] getter.
+ * An error object that merely implements `Error`, and doesn't extend it,
+ * will not store the stack trace automatically.
+ *
+ * Error objects are also used for system wide failures
+ * like stack overflow or an out-of-memory situation.
+ *
+ * Since errors are not created to be caught,
+ * there is no need for subclasses to distinguish the errors.
+ * Instead subclasses have been created in order to make groups
+ * of related errors easy to create with consistent error messages.
+ * For example, the [String.contains] method will use a [RangeError]
+ * if its `startIndex` isn't in the range `0..length`,
+ * which is easily created by `new RangeError.range(startIndex, 0, length)`.
+ */
+class Error {
+  Error(); // Prevent use as mixin.
+
+  /**
+   * Safely convert a value to a [String] description.
+   *
+   * The conversion is guaranteed to not throw, so it won't use the object's
+   * toString method.
+   */
+  static String safeToString(Object object) {
+    if (object is num || object is bool || null == object) {
+      return object.toString();
+    }
+    if (object is String) {
+      return _stringToSafeString(object);
+    }
+    return _objectToString(object);
+  }
+
+  /** Convert string to a valid string literal with no control characters. */
+  external static String _stringToSafeString(String string);
+
+  external static String _objectToString(Object object);
+
+  external StackTrace get stackTrace;
+}
+
+/**
+ * Error thrown by the runtime system when an assert statement fails.
+ */
+class AssertionError extends Error {
+  /** Message describing the assertion error. */
+  final Object message;
+  AssertionError([this.message]);
+  String toString() => "Assertion failed";
+}
+
+/**
+ * Error thrown by the runtime system when a type assertion fails.
+ */
+class TypeError extends AssertionError {}
+
+/**
+ * Error thrown by the runtime system when a cast operation fails.
+ */
+class CastError extends Error {}
+
+/**
+ * Error thrown when attempting to throw [:null:].
+ */
+class NullThrownError extends Error {
+  @pragma("vm:entry-point")
+  NullThrownError();
+  String toString() => "Throw of null.";
+}
+
+/**
+ * Error thrown when a function is passed an unacceptable argument.
+ */
+class ArgumentError extends Error {
+  /** Whether value was provided. */
+  final bool _hasValue;
+  /** The invalid value. */
+  final invalidValue;
+  /** Name of the invalid argument, if available. */
+  final String name;
+  /** Message describing the problem. */
+  final message;
+
+  /**
+   * The [message] describes the erroneous argument.
+   *
+   * Existing code may be using `message` to hold the invalid value.
+   * If the `message` is not a [String], it is assumed to be a value instead
+   * of a message.
+   */
+  @pragma("vm:entry-point")
+  ArgumentError([this.message])
+      : invalidValue = null,
+        _hasValue = false,
+        name = null;
+
+  /**
+   * Creates error containing the invalid [value].
+   *
+   * A message is built by suffixing the [message] argument with
+   * the [name] argument (if provided) and the value. Example
+   *
+   *    "Invalid argument (foo): null"
+   *
+   * The `name` should match the argument name of the function, but if
+   * the function is a method implementing an interface, and its argument
+   * names differ from the interface, it might be more useful to use the
+   * interface method's argument name (or just rename arguments to match).
+   */
+  @pragma("vm:entry-point")
+  ArgumentError.value(value, [this.name, this.message])
+      : invalidValue = value,
+        _hasValue = true;
+
+  /**
+   * Create an argument error for a `null` argument that must not be `null`.
+   */
+  ArgumentError.notNull([this.name])
+      : _hasValue = false,
+        message = "Must not be null",
+        invalidValue = null;
+
+  /**
+   * Throws if [argument] is `null`.
+   */
+  @Since("2.1")
+  static void checkNotNull(Object argument, [String name]) {
+    if (argument == null) throw ArgumentError.notNull(name);
+  }
+
+  // Helper functions for toString overridden in subclasses.
+  String get _errorName => "Invalid argument${!_hasValue ? "(s)" : ""}";
+  String get _errorExplanation => "";
+
+  String toString() {
+    String nameString = "";
+    if (name != null) {
+      nameString = " ($name)";
+    }
+    var message = (this.message == null) ? "" : ": ${this.message}";
+    String prefix = "$_errorName$nameString$message";
+    if (!_hasValue) return prefix;
+    // If we know the invalid value, we can try to describe the problem.
+    String explanation = _errorExplanation;
+    String errorValue = Error.safeToString(invalidValue);
+    return "$prefix$explanation: $errorValue";
+  }
+}
+
+/**
+ * Error thrown due to an index being outside a valid range.
+ */
+class RangeError extends ArgumentError {
+  /** The minimum value that [value] is allowed to assume. */
+  final num start;
+  /** The maximum value that [value] is allowed to assume. */
+  final num end;
+
+  // TODO(lrn): This constructor should be called only with string values.
+  // It currently isn't in all cases.
+  /**
+   * Create a new [RangeError] with the given [message].
+   */
+  @pragma("vm:entry-point")
+  RangeError(var message)
+      : start = null,
+        end = null,
+        super(message);
+
+  /**
+   * Create a new [RangeError] with a message for the given [value].
+   *
+   * An optional [name] can specify the argument name that has the
+   * invalid value, and the [message] can override the default error
+   * description.
+   */
+  RangeError.value(num value, [String name, String message])
+      : start = null,
+        end = null,
+        super.value(
+            value, name, (message != null) ? message : "Value not in range");
+
+  /**
+   * Create a new [RangeError] for a value being outside the valid range.
+   *
+   * The allowed range is from [minValue] to [maxValue], inclusive.
+   * If `minValue` or `maxValue` are `null`, the range is infinite in
+   * that direction.
+   *
+   * For a range from 0 to the length of something, end exclusive, use
+   * [RangeError.index].
+   *
+   * An optional [name] can specify the argument name that has the
+   * invalid value, and the [message] can override the default error
+   * description.
+   */
+  @pragma("vm:entry-point")
+  RangeError.range(num invalidValue, int minValue, int maxValue,
+      [String name, String message])
+      : start = minValue,
+        end = maxValue,
+        super.value(
+            invalidValue, name, (message != null) ? message : "Invalid value");
+
+  /**
+   * Creates a new [RangeError] stating that [index] is not a valid index
+   * into [indexable].
+   *
+   * An optional [name] can specify the argument name that has the
+   * invalid value, and the [message] can override the default error
+   * description.
+   *
+   * The [length] is the length of [indexable] at the time of the error.
+   * If `length` is omitted, it defaults to `indexable.length`.
+   */
+  factory RangeError.index(int index, dynamic indexable,
+      [String name, String message, int length]) = IndexError;
+
+  /**
+   * Check that a [value] lies in a specific interval.
+   *
+   * Throws if [value] is not in the interval.
+   * The interval is from [minValue] to [maxValue], both inclusive.
+   */
+  static void checkValueInInterval(int value, int minValue, int maxValue,
+      [String name, String message]) {
+    if (value < minValue || value > maxValue) {
+      throw RangeError.range(value, minValue, maxValue, name, message);
+    }
+  }
+
+  /**
+   * Check that a value is a valid index into an indexable object.
+   *
+   * Throws if [index] is not a valid index into [indexable].
+   *
+   * An indexable object is one that has a `length` and a and index-operator
+   * `[]` that accepts an index if `0 <= index < length`.
+   *
+   * If [length] is provided, it is used as the length of the indexable object,
+   * otherwise the length is found as `indexable.length`.
+   */
+  static void checkValidIndex(int index, dynamic indexable,
+      [String name, int length, String message]) {
+    length ??= indexable.length;
+    // Comparing with `0` as receiver produces better dart2js type inference.
+    if (0 > index || index >= length) {
+      name ??= "index";
+      throw RangeError.index(index, indexable, name, message, length);
+    }
+  }
+
+  /**
+   * Check that a range represents a slice of an indexable object.
+   *
+   * Throws if the range is not valid for an indexable object with
+   * the given [length].
+   * A range is valid for an indexable object with a given [length]
+   *
+   * if `0 <= [start] <= [end] <= [length]`.
+   * An `end` of `null` is considered equivalent to `length`.
+   *
+   * The [startName] and [endName] defaults to `"start"` and `"end"`,
+   * respectively.
+   *
+   * Returns the actual `end` value, which is `length` if `end` is `null`,
+   * and `end` otherwise.
+   */
+  static int checkValidRange(int start, int end, int length,
+      [String startName, String endName, String message]) {
+    // Comparing with `0` as receiver produces better dart2js type inference.
+    // Ditto `start > end` below.
+    if (0 > start || start > length) {
+      startName ??= "start";
+      throw RangeError.range(start, 0, length, startName, message);
+    }
+    if (end != null) {
+      if (start > end || end > length) {
+        endName ??= "end";
+        throw RangeError.range(end, start, length, endName, message);
+      }
+      return end;
+    }
+    return length;
+  }
+
+  /**
+   * Check that an integer value isn't negative.
+   *
+   * Throws if the value is negative.
+   */
+  static void checkNotNegative(int value, [String name, String message]) {
+    if (value < 0) throw RangeError.range(value, 0, null, name, message);
+  }
+
+  String get _errorName => "RangeError";
+  String get _errorExplanation {
+    assert(_hasValue);
+    String explanation = "";
+    if (start == null) {
+      if (end != null) {
+        explanation = ": Not less than or equal to $end";
+      }
+      // If both are null, we don't add a description of the limits.
+    } else if (end == null) {
+      explanation = ": Not greater than or equal to $start";
+    } else if (end > start) {
+      explanation = ": Not in range $start..$end, inclusive";
+    } else if (end < start) {
+      explanation = ": Valid value range is empty";
+    } else {
+      // end == start.
+      explanation = ": Only valid value is $start";
+    }
+    return explanation;
+  }
+}
+
+/**
+ * A specialized [RangeError] used when an index is not in the range
+ * `0..indexable.length-1`.
+ *
+ * Also contains the indexable object, its length at the time of the error,
+ * and the invalid index itself.
+ */
+class IndexError extends ArgumentError implements RangeError {
+  /** The indexable object that [invalidValue] was not a valid index into. */
+  final indexable;
+  /** The length of [indexable] at the time of the error. */
+  final int length;
+
+  /**
+   * Creates a new [IndexError] stating that [invalidValue] is not a valid index
+   * into [indexable].
+   *
+   * The [length] is the length of [indexable] at the time of the error.
+   * If `length` is omitted, it defaults to `indexable.length`.
+   *
+   * The message is used as part of the string representation of the error.
+   */
+  IndexError(int invalidValue, dynamic indexable,
+      [String name, String message, int length])
+      : this.indexable = indexable,
+        this.length = length ?? indexable.length,
+        super.value(invalidValue, name,
+            (message != null) ? message : "Index out of range");
+
+  // Getters inherited from RangeError.
+  int get start => 0;
+  int get end => length - 1;
+
+  String get _errorName => "RangeError";
+  String get _errorExplanation {
+    assert(_hasValue);
+    int invalidValue = this.invalidValue;
+    if (invalidValue < 0) {
+      return ": index must not be negative";
+    }
+    if (length == 0) {
+      return ": no indices are valid";
+    }
+    return ": index should be less than $length";
+  }
+}
+
+/**
+ * Error thrown when control reaches the end of a switch case.
+ *
+ * The Dart specification requires this error to be thrown when
+ * control reaches the end of a switch case (except the last case
+ * of a switch) without meeting a break or similar end of the control
+ * flow.
+ */
+class FallThroughError extends Error {
+  FallThroughError();
+  @pragma("vm:entry-point")
+  external FallThroughError._create(String url, int line);
+
+  external String toString();
+}
+
+/**
+ * Error thrown when trying to instantiate an abstract class.
+ */
+class AbstractClassInstantiationError extends Error {
+  final String _className;
+  AbstractClassInstantiationError(String className) : _className = className;
+
+  external String toString();
+}
+
+/**
+ * Error thrown by the default implementation of [:noSuchMethod:] on [Object].
+ */
+class NoSuchMethodError extends Error {
+  /**
+   * Create a [NoSuchMethodError] corresponding to a failed method call.
+   *
+   * The [receiver] is the receiver of the method call.
+   * That is, the object on which the method was attempted called.
+   *
+   * The [invocation] represents the method call that failed. It
+   * should not be `null`.
+   */
+  external NoSuchMethodError.withInvocation(
+      Object receiver, Invocation invocation);
+
+  // Deprecated constructor to be removed after dart2js updates to the above.
+  /**
+   * Create a [NoSuchMethodError] corresponding to a failed method call.
+   *
+   * The [receiver] is the receiver of the method call.
+   * That is, the object on which the method was attempted called.
+   * If the receiver is `null`, it is interpreted as a call to a top-level
+   * function of a library.
+   *
+   * The [memberName] is a [Symbol] representing the name of the called method
+   * or accessor. It should not be `null`.
+   *
+   * The [positionalArguments] is a list of the positional arguments that the
+   * method was called with. If `null`, it is considered equivalent to the
+   * empty list.
+   *
+   * The [namedArguments] is a map from [Symbol]s to the values of named
+   * arguments that the method was called with.
+   *
+   * This constructor does not handle type arguments.
+   * To include type variables, create an [Invocation] and use
+   * [NoSuchMethodError.withInvocation].
+   */
+  @Deprecated("Use NoSuchMethod.withInvocation instead")
+  external NoSuchMethodError(Object receiver, Symbol memberName,
+      List positionalArguments, Map<Symbol, dynamic> namedArguments,
+      [@deprecated List existingArgumentNames]);
+
+  external String toString();
+}
+
+/**
+ * The operation was not allowed by the object.
+ *
+ * This [Error] is thrown when an instance cannot implement one of the methods
+ * in its signature.
+ */
+@pragma("vm:entry-point")
+class UnsupportedError extends Error {
+  final String message;
+  @pragma("vm:entry-point")
+  UnsupportedError(this.message);
+  String toString() => "Unsupported operation: $message";
+}
+
+/**
+ * Thrown by operations that have not been implemented yet.
+ *
+ * This [Error] is thrown by unfinished code that hasn't yet implemented
+ * all the features it needs.
+ *
+ * If a class is not intending to implement the feature, it should throw
+ * an [UnsupportedError] instead. This error is only intended for
+ * use during development.
+ */
+class UnimplementedError extends Error implements UnsupportedError {
+  final String message;
+  UnimplementedError([this.message]);
+  String toString() => (this.message != null
+      ? "UnimplementedError: $message"
+      : "UnimplementedError");
+}
+
+/**
+ * The operation was not allowed by the current state of the object.
+ *
+ * This is a generic error used for a variety of different erroneous
+ * actions. The message should be descriptive.
+ */
+class StateError extends Error {
+  final String message;
+  StateError(this.message);
+  String toString() => "Bad state: $message";
+}
+
+/**
+ * Error occurring when a collection is modified during iteration.
+ *
+ * Some modifications may be allowed for some collections, so each collection
+ * ([Iterable] or similar collection of values) should declare which operations
+ * are allowed during an iteration.
+ */
+class ConcurrentModificationError extends Error {
+  /** The object that was modified in an incompatible way. */
+  final Object modifiedObject;
+
+  ConcurrentModificationError([this.modifiedObject]);
+
+  String toString() {
+    if (modifiedObject == null) {
+      return "Concurrent modification during iteration.";
+    }
+    return "Concurrent modification during iteration: "
+        "${Error.safeToString(modifiedObject)}.";
+  }
+}
+
+class OutOfMemoryError implements Error {
+  @pragma("vm:entry-point")
+  const OutOfMemoryError();
+  String toString() => "Out of Memory";
+
+  StackTrace get stackTrace => null;
+}
+
+class StackOverflowError implements Error {
+  @pragma("vm:entry-point")
+  const StackOverflowError();
+  String toString() => "Stack Overflow";
+
+  StackTrace get stackTrace => null;
+}
+
+/**
+ * Error thrown when a lazily initialized variable cannot be initialized.
+ *
+ * A static/library variable with an initializer expression is initialized
+ * the first time it is read. If evaluating the initializer expression causes
+ * another read of the variable, this error is thrown.
+ */
+class CyclicInitializationError extends Error {
+  final String variableName;
+  @pragma("vm:entry-point")
+  CyclicInitializationError([this.variableName]);
+  String toString() => variableName == null
+      ? "Reading static variable during its initialization"
+      : "Reading static variable '$variableName' during its initialization";
+}
diff --git a/sdk_nnbd/lib/core/exceptions.dart b/sdk_nnbd/lib/core/exceptions.dart
new file mode 100644
index 0000000..2e137e5
--- /dev/null
+++ b/sdk_nnbd/lib/core/exceptions.dart
@@ -0,0 +1,184 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.core;
+
+// Exceptions are thrown either by the VM or from Dart code.
+
+/**
+ * A marker interface implemented by all core library exceptions.
+ *
+ * An [Exception] is intended to convey information to the user about a failure,
+ * so that the error can be addressed programmatically. It is intended to be
+ * caught, and it should contain useful data fields.
+ *
+ * Creating instances of [Exception] directly with [:new Exception("message"):]
+ * is discouraged, and only included as a temporary measure during development,
+ * until the actual exceptions used by a library are done.
+ */
+abstract class Exception {
+  factory Exception([var message]) => _Exception(message);
+}
+
+/** Default implementation of [Exception] which carries a message. */
+class _Exception implements Exception {
+  final message;
+
+  _Exception([this.message]);
+
+  String toString() {
+    if (message == null) return "Exception";
+    return "Exception: $message";
+  }
+}
+
+/**
+ * Exception thrown when a string or some other data does not have an expected
+ * format and cannot be parsed or processed.
+ */
+class FormatException implements Exception {
+  /**
+   * A message describing the format error.
+   */
+  final String message;
+
+  /**
+   * The actual source input which caused the error.
+   *
+   * This is usually a [String], but can be other types too.
+   * If it is a string, parts of it may be included in the [toString] message.
+   *
+   * The source is `null` if omitted or unknown.
+   */
+  final source;
+
+  /**
+   * The offset in [source] where the error was detected.
+   *
+   * A zero-based offset into the source that marks the format error causing
+   * this exception to be created. If `source` is a string, this should be a
+   * string index in the range `0 <= offset <= source.length`.
+   *
+   * If input is a string, the [toString] method may represent this offset as
+   * a line and character position. The offset should be inside the string,
+   * or at the end of the string.
+   *
+   * May be omitted. If present, [source] should also be present if possible.
+   */
+  final int offset;
+
+  /**
+   * Creates a new FormatException with an optional error [message].
+   *
+   * Optionally also supply the actual [source] with the incorrect format,
+   * and the [offset] in the format where a problem was detected.
+   */
+  @pragma("vm:entry-point")
+  const FormatException([this.message = "", this.source, this.offset]);
+
+  /**
+   * Returns a description of the format exception.
+   *
+   * The description always contains the [message].
+   *
+   * If [source] is present and is a string, the description will contain
+   * (at least a part of) the source.
+   * If [offset] is also provided, the part of the source included will
+   * contain that offset, and the offset will be marked.
+   *
+   * If the source is a string and it contains a line break before offset,
+   * only the line containing offset will be included, and its line number
+   * will also be part of the description. Line and character offsets are
+   * 1-based.
+   */
+  String toString() {
+    String report = "FormatException";
+    if (message != null && "" != message) {
+      report = "$report: $message";
+    }
+    int offset = this.offset;
+    Object objectSource = this.source;
+    if (objectSource is String) {
+      String source = objectSource;
+      if (offset != null && (offset < 0 || offset > source.length)) {
+        offset = null;
+      }
+      // Source is string and offset is null or valid.
+      if (offset == null) {
+        if (source.length > 78) {
+          source = source.substring(0, 75) + "...";
+        }
+        return "$report\n$source";
+      }
+      int lineNum = 1;
+      int lineStart = 0;
+      bool previousCharWasCR = false;
+      for (int i = 0; i < offset; i++) {
+        int char = source.codeUnitAt(i);
+        if (char == 0x0a) {
+          if (lineStart != i || !previousCharWasCR) {
+            lineNum++;
+          }
+          lineStart = i + 1;
+          previousCharWasCR = false;
+        } else if (char == 0x0d) {
+          lineNum++;
+          lineStart = i + 1;
+          previousCharWasCR = true;
+        }
+      }
+      if (lineNum > 1) {
+        report += " (at line $lineNum, character ${offset - lineStart + 1})\n";
+      } else {
+        report += " (at character ${offset + 1})\n";
+      }
+      int lineEnd = source.length;
+      for (int i = offset; i < source.length; i++) {
+        int char = source.codeUnitAt(i);
+        if (char == 0x0a || char == 0x0d) {
+          lineEnd = i;
+          break;
+        }
+      }
+      int length = lineEnd - lineStart;
+      int start = lineStart;
+      int end = lineEnd;
+      String prefix = "";
+      String postfix = "";
+      if (length > 78) {
+        // Can't show entire line. Try to anchor at the nearest end, if
+        // one is within reach.
+        int index = offset - lineStart;
+        if (index < 75) {
+          end = start + 75;
+          postfix = "...";
+        } else if (end - offset < 75) {
+          start = end - 75;
+          prefix = "...";
+        } else {
+          // Neither end is near, just pick an area around the offset.
+          start = offset - 36;
+          end = offset + 36;
+          prefix = postfix = "...";
+        }
+      }
+      String slice = source.substring(start, end);
+      int markOffset = offset - start + prefix.length;
+      return "$report$prefix$slice$postfix\n${" " * markOffset}^\n";
+    } else {
+      // The source is not a string.
+      if (offset != null) {
+        report += " (at offset $offset)";
+      }
+      return report;
+    }
+  }
+}
+
+// Exception thrown when doing integer division with a zero divisor.
+class IntegerDivisionByZeroException implements Exception {
+  @pragma("vm:entry-point")
+  const IntegerDivisionByZeroException();
+  String toString() => "IntegerDivisionByZeroException";
+}
diff --git a/sdk_nnbd/lib/core/expando.dart b/sdk_nnbd/lib/core/expando.dart
new file mode 100644
index 0000000..92cf90c
--- /dev/null
+++ b/sdk_nnbd/lib/core/expando.dart
@@ -0,0 +1,62 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.core;
+
+/**
+ * An [Expando] allows adding new properties to objects.
+ *
+ * Does not work on numbers, strings, booleans or null.
+ *
+ * An `Expando` does not hold on to the added property value after an object
+ * becomes inaccessible.
+ *
+ * Since you can always create a new number that is identical to an existing
+ * number, it means that an expando property on a number could never be
+ * released. To avoid this, expando properties cannot be added to numbers.
+ * The same argument applies to strings, booleans and null, which also have
+ * literals that evaluate to identical values when they occur more than once.
+ *
+ * There is no restriction on other classes, even for compile time constant
+ * objects. Be careful if adding expando properties to compile time constants,
+ * since they will stay alive forever.
+ */
+class Expando<T> {
+  /**
+   * The name of the this [Expando] as passed to the constructor. If
+   * no name was passed to the constructor, the name is [:null:].
+   */
+  final String name;
+
+  /**
+   * Creates a new [Expando]. The optional name is only used for
+   * debugging purposes and creating two different [Expando]s with the
+   * same name yields two [Expando]s that work on different properties
+   * of the objects they are used on.
+   */
+  external Expando([String name]);
+
+  /**
+   * Expando toString method override.
+   */
+  String toString() => "Expando:$name";
+
+  /**
+   * Gets the value of this [Expando]'s property on the given
+   * object. If the object hasn't been expanded, the method returns
+   * [:null:].
+   *
+   * The object must not be a number, a string, a boolean or null.
+   */
+  external T operator [](Object object);
+
+  /**
+   * Sets the value of this [Expando]'s property on the given
+   * object. Properties can effectively be removed again by setting
+   * their value to null.
+   *
+   * The object must not be a number, a string, a boolean or null.
+   */
+  external void operator []=(Object object, T value);
+}
diff --git a/sdk_nnbd/lib/core/function.dart b/sdk_nnbd/lib/core/function.dart
new file mode 100644
index 0000000..7ff40e9
--- /dev/null
+++ b/sdk_nnbd/lib/core/function.dart
@@ -0,0 +1,67 @@
+// Copyright (c) 2011, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.core;
+
+/**
+ * The base class for all function types.
+ *
+ * A function value, or an instance of a class with a "call" method, is a
+ * subtype of a function type, and as such, a subtype of [Function].
+ */
+abstract class Function {
+  /**
+   * Dynamically call [function] with the specified arguments.
+   *
+   * Acts the same as calling function with positional arguments
+   * corresponding to the elements of [positionalArguments] and
+   * named arguments corresponding to the elements of [namedArguments].
+   *
+   * This includes giving the same errors if [function] isn't callable or
+   * if it expects different parameters.
+   *
+   * Example:
+   * ```
+   * Function.apply(foo, [1,2,3], {#f: 4, #g: 5});
+   * ```
+   *
+   * gives exactly the same result as
+   * ```
+   * foo(1, 2, 3, f: 4, g: 5).
+   * ```
+   *
+   * If [positionalArguments] is null, it's considered an empty list.
+   * If [namedArguments] is omitted or null, it is considered an empty map.
+   */
+  external static apply(Function function, List positionalArguments,
+      [Map<Symbol, dynamic> namedArguments]);
+
+  /**
+   * Returns a hash code value that is compatible with `operator==`.
+   */
+  int get hashCode;
+
+  /**
+   * Test whether another object is equal to this function.
+   *
+   * System-created function objects are only equal to other functions.
+   *
+   * Two function objects are known to represent the same function if
+   *
+   * - It is the same object. Static and top-level functions are compile time
+   *   constants when used as values, so referring to the same function twice
+   *   always give the same object,
+   * - or if they refer to the same member method extracted from the same object.
+   *   Extracting a member method as a function value twice gives equal, but
+   *   not necessarily identical, function values.
+   *
+   * Function expressions never give rise to equal function objects. Each time
+   * a function expression is evaluated, it creates a new closure value that
+   * is not known to be equal to other closures created by the same expression.
+   *
+   * Classes implementing `Function` by having a `call` method should have their
+   * own `operator==` and `hashCode` depending on the object.
+   */
+  bool operator ==(Object other);
+}
diff --git a/sdk_nnbd/lib/core/identical.dart b/sdk_nnbd/lib/core/identical.dart
new file mode 100644
index 0000000..68da9f3
--- /dev/null
+++ b/sdk_nnbd/lib/core/identical.dart
@@ -0,0 +1,22 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.core;
+
+/**
+ * Check whether two references are to the same object.
+ */
+external bool identical(Object a, Object b);
+
+/**
+ * Returns the identity hash code of `object`.
+ *
+ * Returns the same value as `object.hashCode` if [object] has not overridden
+ * [Object.hashCode]. Returns the value that [Object.hashCode] would return
+ * on this object, even if `hashCode` has been overridden.
+ *
+ * This hash code is compatible with [identical].
+ */
+@pragma("vm:entry-point")
+external int identityHashCode(Object object);
diff --git a/sdk_nnbd/lib/core/int.dart b/sdk_nnbd/lib/core/int.dart
new file mode 100644
index 0000000..bc493fb
--- /dev/null
+++ b/sdk_nnbd/lib/core/int.dart
@@ -0,0 +1,355 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.core;
+
+/**
+ * An integer number.
+ *
+ * The default implementation of `int` is 64-bit two's complement integers
+ * with operations that wrap to that range on overflow.
+ *
+ * **Note:** When compiling to JavaScript, integers are restricted to values
+ * that can be represented exactly by double-precision floating point values.
+ * The available integer values include all integers between -2^53 and 2^53,
+ * and some integers with larger magnitude. That includes some integers larger
+ * than 2^63.
+ * The behavior of the operators and methods in the [int]
+ * class therefore sometimes differs between the Dart VM and Dart code
+ * compiled to JavaScript. For example, the bitwise operators truncate their
+ * operands to 32-bit integers when compiled to JavaScript.
+ *
+ * Classes cannot extend, implement, or mix in `int`.
+ */
+abstract class int extends num {
+  /**
+   * Returns the integer value of the given environment declaration [name].
+   *
+   * The result is the same as would be returned by:
+   * ```
+   * int.tryParse(const String.fromEnvironment(name, defaultValue: ""))
+   *     ?? defaultValue
+   * ```
+   * Example:
+   * ```
+   * const int.fromEnvironment("defaultPort", defaultValue: 80)
+   * ```
+   */
+  // The .fromEnvironment() constructors are special in that we do not want
+  // users to call them using "new". We prohibit that by giving them bodies
+  // that throw, even though const constructors are not allowed to have bodies.
+  // Disable those static errors.
+  //ignore: const_constructor_with_body
+  //ignore: const_factory
+  external const factory int.fromEnvironment(String name, {int defaultValue});
+
+  /**
+   * Bit-wise and operator.
+   *
+   * Treating both `this` and [other] as sufficiently large two's component
+   * integers, the result is a number with only the bits set that are set in
+   * both `this` and [other]
+   *
+   * Of both operands are negative, the result is negative, otherwise
+   * the result is non-negative.
+   */
+  int operator &(int other);
+
+  /**
+   * Bit-wise or operator.
+   *
+   * Treating both `this` and [other] as sufficiently large two's component
+   * integers, the result is a number with the bits set that are set in either
+   * of `this` and [other]
+   *
+   * If both operands are non-negative, the result is non-negative,
+   * otherwise the result is negative.
+   */
+  int operator |(int other);
+
+  /**
+   * Bit-wise exclusive-or operator.
+   *
+   * Treating both `this` and [other] as sufficiently large two's component
+   * integers, the result is a number with the bits set that are set in one,
+   * but not both, of `this` and [other]
+   *
+   * If the operands have the same sign, the result is non-negative,
+   * otherwise the result is negative.
+   */
+  int operator ^(int other);
+
+  /**
+   * The bit-wise negate operator.
+   *
+   * Treating `this` as a sufficiently large two's component integer,
+   * the result is a number with the opposite bits set.
+   *
+   * This maps any integer `x` to `-x - 1`.
+   */
+  int operator ~();
+
+  /**
+   * Shift the bits of this integer to the left by [shiftAmount].
+   *
+   * Shifting to the left makes the number larger, effectively multiplying
+   * the number by `pow(2, shiftIndex)`.
+   *
+   * There is no limit on the size of the result. It may be relevant to
+   * limit intermediate values by using the "and" operator with a suitable
+   * mask.
+   *
+   * It is an error if [shiftAmount] is negative.
+   */
+  int operator <<(int shiftAmount);
+
+  /**
+   * Shift the bits of this integer to the right by [shiftAmount].
+   *
+   * Shifting to the right makes the number smaller and drops the least
+   * significant bits, effectively doing an integer division by
+   *`pow(2, shiftIndex)`.
+   *
+   * It is an error if [shiftAmount] is negative.
+   */
+  int operator >>(int shiftAmount);
+
+  /**
+   * Returns this integer to the power of [exponent] modulo [modulus].
+   *
+   * The [exponent] must be non-negative and [modulus] must be
+   * positive.
+   */
+  int modPow(int exponent, int modulus);
+
+  /**
+   * Returns the modular multiplicative inverse of this integer
+   * modulo [modulus].
+   *
+   * The [modulus] must be positive.
+   *
+   * It is an error if no modular inverse exists.
+   */
+  int modInverse(int modulus);
+
+  /**
+   * Returns the greatest common divisor of this integer and [other].
+   *
+   * If either number is non-zero, the result is the numerically greatest
+   * integer dividing both `this` and `other`.
+   *
+   * The greatest common divisor is independent of the order,
+   * so `x.gcd(y)` is  always the same as `y.gcd(x)`.
+   *
+   * For any integer `x`, `x.gcd(x)` is `x.abs()`.
+   *
+   * If both `this` and `other` is zero, the result is also zero.
+   */
+  int gcd(int other);
+
+  /** Returns true if and only if this integer is even. */
+  bool get isEven;
+
+  /** Returns true if and only if this integer is odd. */
+  bool get isOdd;
+
+  /**
+   * Returns the minimum number of bits required to store this integer.
+   *
+   * The number of bits excludes the sign bit, which gives the natural length
+   * for non-negative (unsigned) values.  Negative values are complemented to
+   * return the bit position of the first bit that differs from the sign bit.
+   *
+   * To find the number of bits needed to store the value as a signed value,
+   * add one, i.e. use `x.bitLength + 1`.
+   * ```
+   * x.bitLength == (-x-1).bitLength
+   *
+   * 3.bitLength == 2;     // 00000011
+   * 2.bitLength == 2;     // 00000010
+   * 1.bitLength == 1;     // 00000001
+   * 0.bitLength == 0;     // 00000000
+   * (-1).bitLength == 0;  // 11111111
+   * (-2).bitLength == 1;  // 11111110
+   * (-3).bitLength == 2;  // 11111101
+   * (-4).bitLength == 2;  // 11111100
+   * ```
+   */
+  int get bitLength;
+
+  /**
+   * Returns the least significant [width] bits of this integer as a
+   * non-negative number (i.e. unsigned representation).  The returned value has
+   * zeros in all bit positions higher than [width].
+   * ```
+   * (-1).toUnsigned(5) == 31   // 11111111  ->  00011111
+   * ```
+   * This operation can be used to simulate arithmetic from low level languages.
+   * For example, to increment an 8 bit quantity:
+   * ```
+   * q = (q + 1).toUnsigned(8);
+   * ```
+   * `q` will count from `0` up to `255` and then wrap around to `0`.
+   *
+   * If the input fits in [width] bits without truncation, the result is the
+   * same as the input.  The minimum width needed to avoid truncation of `x` is
+   * given by `x.bitLength`, i.e.
+   * ```
+   * x == x.toUnsigned(x.bitLength);
+   * ```
+   */
+  int toUnsigned(int width);
+
+  /**
+   * Returns the least significant [width] bits of this integer, extending the
+   * highest retained bit to the sign.  This is the same as truncating the value
+   * to fit in [width] bits using an signed 2-s complement representation.  The
+   * returned value has the same bit value in all positions higher than [width].
+   *
+   * ```
+   *                                V--sign bit-V
+   * 16.toSigned(5) == -16   //  00010000 -> 11110000
+   * 239.toSigned(5) == 15   //  11101111 -> 00001111
+   *                                ^           ^
+   * ```
+   * This operation can be used to simulate arithmetic from low level languages.
+   * For example, to increment an 8 bit signed quantity:
+   * ```
+   * q = (q + 1).toSigned(8);
+   * ```
+   * `q` will count from `0` up to `127`, wrap to `-128` and count back up to
+   * `127`.
+   *
+   * If the input value fits in [width] bits without truncation, the result is
+   * the same as the input.  The minimum width needed to avoid truncation of `x`
+   * is `x.bitLength + 1`, i.e.
+   * ```
+   * x == x.toSigned(x.bitLength + 1);
+   * ```
+   */
+  int toSigned(int width);
+
+  /**
+   * Return the negative value of this integer.
+   *
+   * The result of negating an integer always has the opposite sign, except
+   * for zero, which is its own negation.
+   */
+  int operator -();
+
+  /**
+   * Returns the absolute value of this integer.
+   *
+   * For any integer `x`, the result is the same as `x < 0 ? -x : x`.
+   */
+  int abs();
+
+  /**
+   * Returns the sign of this integer.
+   *
+   * Returns 0 for zero, -1 for values less than zero and
+   * +1 for values greater than zero.
+   */
+  int get sign;
+
+  /** Returns `this`. */
+  int round();
+
+  /** Returns `this`. */
+  int floor();
+
+  /** Returns `this`. */
+  int ceil();
+
+  /** Returns `this`. */
+  int truncate();
+
+  /** Returns `this.toDouble()`. */
+  double roundToDouble();
+
+  /** Returns `this.toDouble()`. */
+  double floorToDouble();
+
+  /** Returns `this.toDouble()`. */
+  double ceilToDouble();
+
+  /** Returns `this.toDouble()`. */
+  double truncateToDouble();
+
+  /**
+   * Returns a string representation of this integer.
+   *
+   * The returned string is parsable by [parse].
+   * For any `int` `i`, it is guaranteed that
+   * `i == int.parse(i.toString())`.
+   */
+  String toString();
+
+  /**
+   * Converts [this] to a string representation in the given [radix].
+   *
+   * In the string representation, lower-case letters are used for digits above
+   * '9', with 'a' being 10 an 'z' being 35.
+   *
+   * The [radix] argument must be an integer in the range 2 to 36.
+   */
+  String toRadixString(int radix);
+
+  /**
+   * Parse [source] as a, possibly signed, integer literal and return its value.
+   *
+   * The [source] must be a non-empty sequence of base-[radix] digits,
+   * optionally prefixed with a minus or plus sign ('-' or '+').
+   * It must not be `null`.
+   *
+   * The [radix] must be in the range 2..36. The digits used are
+   * first the decimal digits 0..9, and then the letters 'a'..'z' with
+   * values 10 through 35. Also accepts upper-case letters with the same
+   * values as the lower-case ones.
+   *
+   * If no [radix] is given then it defaults to 10. In this case, the [source]
+   * digits may also start with `0x`, in which case the number is interpreted
+   * as a hexadecimal integer literal,
+   * When `int` is implemented by 64-bit signed integers,
+   * hexadecimal integer literals may represent values larger than
+   * 2<sup>63</sup>, in which case the value is parsed as if it is an
+   * *unsigned* number, and the resulting value is the corresponding
+   * signed integer value.
+   *
+   * For any int `n` and valid radix `r`, it is guaranteed that
+   * `n == int.parse(n.toRadixString(r), radix: r)`.
+   *
+   * If the [source] string does not contain a valid integer literal,
+   * optionally prefixed by a sign, a [FormatException] is thrown
+   * (unless the deprecated [onError] parameter is used, see below).
+   *
+   * Instead of throwing and immediately catching the [FormatException],
+   * instead use [tryParse] to handle a parsing error.
+   * Example:
+   * ```dart
+   * var value = int.tryParse(text);
+   * if (value == null) ... handle the problem
+   * ```
+   *
+   * The [onError] parameter is deprecated and will be removed.
+   * Instead of `int.parse(string, onError: (string) => ...)`,
+   * you should use `int.tryParse(string) ?? (...)`.
+   *
+   * When the source string is not valid and [onError] is provided,
+   * whenever a [FormatException] would be thrown,
+   * [onError] is instead called with [source] as argument,
+   * and the result of that call is returned by [parse].
+   */
+  external static int parse(String source,
+      {int radix, @deprecated int onError(String source)});
+
+  /**
+   * Parse [source] as a, possibly signed, integer literal and return its value.
+   *
+   * Like [parse] except that this function returns `null` where a
+   * similar call to [parse] would throw a [FormatException],
+   * and the [source] must still not be `null`.
+   */
+  external static int tryParse(String source, {int radix});
+}
diff --git a/sdk_nnbd/lib/core/invocation.dart b/sdk_nnbd/lib/core/invocation.dart
new file mode 100644
index 0000000..e9ea57e
--- /dev/null
+++ b/sdk_nnbd/lib/core/invocation.dart
@@ -0,0 +1,162 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.core;
+
+/**
+ * Representation of the invocation of a member on an object.
+ *
+ * This is the type of objects passed to [Object.noSuchMethod] when
+ * an object doesn't support the member invocation that was attempted
+ * on it.
+ */
+abstract class Invocation {
+  Invocation();
+
+  /**
+   * Creates an invocation corresponding to a method invocation.
+   *
+   * The method invocation has no type arguments.
+   * If the named arguments are omitted, they default to no named arguments.
+   */
+  factory Invocation.method(
+          Symbol memberName, Iterable<Object> positionalArguments,
+          [Map<Symbol, Object> namedArguments]) =>
+      _Invocation.method(memberName, null, positionalArguments, namedArguments);
+
+  /**
+   * Creates an invocation corresponding to a generic method invocation.
+   *
+   * If [typeArguments] is `null` or empty, the constructor is equivalent to
+   * calling [Invocation.method] with the remaining arguments.
+   * All the individual type arguments must be non-null.
+   *
+   * If the named arguments are omitted, they default to no named arguments.
+   */
+  factory Invocation.genericMethod(Symbol memberName,
+          Iterable<Type> typeArguments, Iterable<Object> positionalArguments,
+          [Map<Symbol, Object> namedArguments]) =>
+      _Invocation.method(
+          memberName, typeArguments, positionalArguments, namedArguments);
+
+  /**
+   * Creates an invocation corresponding to a getter invocation.
+   */
+  factory Invocation.getter(Symbol name) = _Invocation.getter;
+
+  /**
+   * Creates an invocation corresponding to a setter invocation.
+   *
+   * This constructor accepts any [Symbol] as [memberName], but remember that
+   * *actual setter names* end in `=`, so the invocation corresponding
+   * to `object.member = value` is
+   * ```dart
+   * Invocation.setter(const Symbol("member="), value)
+   * ```
+   */
+  factory Invocation.setter(Symbol memberName, Object argument) =
+      _Invocation.setter;
+
+  /** The name of the invoked member. */
+  Symbol get memberName;
+
+  /**
+   * An unmodifiable view of the type arguments of the call.
+   *
+   * If the member is a getter, setter or operator,
+   * the type argument list is always empty.
+   */
+  List<Type> get typeArguments => const <Type>[];
+
+  /**
+   * An unmodifiable view of the positional arguments of the call.
+   *
+   * If the member is a getter, the positional arguments list is
+   * always empty.
+   */
+  List<dynamic> get positionalArguments;
+
+  /**
+   * An unmodifiable view of the named arguments of the call.
+   *
+   * If the member is a getter, setter or operator,
+   * the named arguments map is always empty.
+   */
+  Map<Symbol, dynamic> get namedArguments;
+
+  /** Whether the invocation was a method call. */
+  bool get isMethod;
+
+  /**
+   * Whether the invocation was a getter call.
+   * If so, all three types of arguments lists are empty.
+   */
+  bool get isGetter;
+
+  /**
+   * Whether the invocation was a setter call.
+   *
+   * If so, [positionalArguments] has exactly one positional
+   * argument, [namedArguments] is empty, and typeArguments is
+   * empty.
+   */
+  bool get isSetter;
+
+  /** Whether the invocation was a getter or a setter call. */
+  bool get isAccessor => isGetter || isSetter;
+}
+
+/** Implementation of [Invocation] used by its factory constructors. */
+class _Invocation implements Invocation {
+  final Symbol memberName;
+  final List<Type> typeArguments;
+  // Positional arguments is `null` for getters only.
+  final List<Object> _positional;
+  // Named arguments is `null` for accessors only.
+  final Map<Symbol, Object> _named;
+
+  _Invocation.method(this.memberName, Iterable<Type> types,
+      Iterable<Object> positional, Map<Symbol, Object> named)
+      : typeArguments = _ensureNonNullTypes(_makeUnmodifiable<Type>(types)),
+        _positional = _makeUnmodifiable<Object>(positional) ?? const <Object>[],
+        _named = (named == null || named.isEmpty)
+            ? const <Symbol, Object>{}
+            : Map<Symbol, Object>.unmodifiable(named);
+
+  _Invocation.getter(this.memberName)
+      : typeArguments = const <Type>[],
+        _positional = null,
+        _named = null;
+
+  _Invocation.setter(this.memberName, Object argument)
+      : typeArguments = const <Type>[],
+        _positional = List<Object>.unmodifiable([argument]),
+        _named = null;
+
+  List<dynamic> get positionalArguments => _positional ?? const <Object>[];
+
+  Map<Symbol, dynamic> get namedArguments => _named ?? const <Symbol, Object>{};
+
+  bool get isMethod => _named != null;
+  bool get isGetter => _positional == null;
+  bool get isSetter => _positional != null && _named == null;
+  bool get isAccessor => _named == null;
+
+  /// Checks that the elements of [types] are not null.
+  static List<Type> _ensureNonNullTypes(List<Type> types) {
+    if (types == null) return const <Type>[];
+    for (int i = 0; i < types.length; i++) {
+      if (types[i] == null) {
+        throw ArgumentError(
+            "Type arguments must be non-null, was null at index $i.");
+      }
+    }
+    return types;
+  }
+
+  static List<T> _makeUnmodifiable<T>(Iterable<T> elements) {
+    if (elements == null) return null;
+    return List<T>.unmodifiable(elements);
+  }
+}
diff --git a/sdk_nnbd/lib/core/iterable.dart b/sdk_nnbd/lib/core/iterable.dart
new file mode 100644
index 0000000..0744937
--- /dev/null
+++ b/sdk_nnbd/lib/core/iterable.dart
@@ -0,0 +1,707 @@
+// Copyright (c) 2011, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.core;
+
+/**
+ * A collection of values, or "elements", that can be accessed sequentially.
+ *
+ * The elements of the iterable are accessed by getting an [Iterator]
+ * using the [iterator] getter, and using it to step through the values.
+ * Stepping with the iterator is done by calling [Iterator.moveNext],
+ * and if the call returns `true`,
+ * the iterator has now moved to the next element,
+ * which is then available as [Iterator.current].
+ * If the call returns `false`, there are no more elements,
+ * and `iterator.current` returns `null`.
+ *
+ * You can create more than one iterator from the same `Iterable`.
+ * Each time `iterator` is read, it returns a new iterator,
+ * and different iterators can be stepped through independently,
+ * each giving access to all the elements of the iterable.
+ * The iterators of the same iterable *should* provide the same values
+ * in the same order (unless the underlying collection is modified between
+ * the iterations, which some collections allow).
+ *
+ * You can also iterate over the elements of an `Iterable`
+ * using the for-in loop construct, which uses the `iterator` getter behind the
+ * scenes.
+ * For example, you can iterate over all of the keys of a [Map],
+ * because `Map` keys are iterable.
+ *
+ *     Map kidsBooks = {'Matilda': 'Roald Dahl',
+ *                      'Green Eggs and Ham': 'Dr Seuss',
+ *                      'Where the Wild Things Are': 'Maurice Sendak'};
+ *     for (var book in kidsBooks.keys) {
+ *       print('$book was written by ${kidsBooks[book]}');
+ *     }
+ *
+ * The [List] and [Set] classes are both `Iterable`,
+ * as are most classes in the `dart:collection` library.
+ *
+ * Some [Iterable] collections can be modified.
+ * Adding an element to a `List` or `Set` will change which elements it
+ * contains, and adding a new key to a `Map` changes the elements of [Map.keys].
+ * Iterators created after the change will provide the new elements, and may
+ * or may not preserve the order of existing elements
+ * (for example, a [HashSet] may completely change its order when a single
+ * element is added).
+ *
+ * Changing a collection *while* it is being iterated
+ * is generally *not* allowed.
+ * Doing so will break the iteration, which is typically signalled
+ * by throwing a [ConcurrentModificationError]
+ * the next time [Iterator.moveNext] is called.
+ * The current value of [Iterator.current] getter
+ * should not be affected by the change in the collection,
+ * the `current` value was set by the previous call to [Iterator.moveNext].
+ *
+ * Some iterables compute their elements dynamically every time they are
+ * iterated, like the one returned by [Iterable.generate] or the iterable
+ * returned by a `sync*` generator function. If the computation doesn't depend
+ * on other objects that may change, then the generated sequence should be
+ * the same one every time it's iterated.
+ *
+ * The members of `Iterable`, other than `iterator` itself,
+ * work by looking at the elements of the iterable.
+ * This can be implemented by running through the [iterator], but some classes
+ * may have more efficient ways of finding the result
+ * (like [last] or [length] on a [List], or [contains] on a [Set]).
+ *
+ * The methods that return another `Iterable` (like [map] and [where])
+ * are all *lazy* - they will iterate the original (as necessary)
+ * every time the returned iterable is iterated, and not before.
+ *
+ * Since an iterable may be iterated more than once, it's not recommended to
+ * have detectable side-effects in the iterator.
+ * For methods like [map] and [where], the returned iterable will execute the
+ * argument function on every iteration, so those functions should also not
+ * have side effects.
+ */
+abstract class Iterable<E> {
+  // TODO(lrn): When we allow forwarding const constructors through
+  // mixin applications, make this class implement [IterableMixin].
+  const Iterable();
+
+  /**
+   * Creates an `Iterable` which generates its elements dynamically.
+   *
+   * The generated iterable has [count] elements,
+   * and the element at index `n` is computed by calling `generator(n)`.
+   * Values are not cached, so each iteration computes the values again.
+   *
+   * If [generator] is omitted, it defaults to an identity function
+   * on integers `(int x) => x`, so it may only be omitted if the type
+   * parameter allows integer values. That is, if [E] is a super-type
+   * of [int].
+   *
+   * As an `Iterable`, `new Iterable.generate(n, generator))` is equivalent to
+   * `const [0, ..., n - 1].map(generator)`.
+   */
+  factory Iterable.generate(int count, [E generator(int index)]) {
+    if (count <= 0) return EmptyIterable<E>();
+    return _GeneratorIterable<E>(count, generator);
+  }
+
+  /**
+   * Creates an empty iterable.
+   *
+   * The empty iterable has no elements, and iterating it always stops
+   * immediately.
+   */
+  const factory Iterable.empty() = EmptyIterable<E>;
+
+  /**
+   * Adapts [source] to be an `Iterable<T>`.
+   *
+   * Any time the iterable would produce an element that is not a [T],
+   * the element access will throw. If all elements of [source] are actually
+   * instances of [T], or if only elements that are actually instances of [T]
+   * are accessed, then the resulting iterable can be used as an `Iterable<T>`.
+   */
+  static Iterable<T> castFrom<S, T>(Iterable<S> source) =>
+      CastIterable<S, T>(source);
+
+  /**
+   * Returns a new `Iterator` that allows iterating the elements of this
+   * `Iterable`.
+   *
+   * Iterable classes may specify the iteration order of their elements
+   * (for example [List] always iterate in index order),
+   * or they may leave it unspecified (for example a hash-based [Set]
+   * may iterate in any order).
+   *
+   * Each time `iterator` is read, it returns a new iterator,
+   * which can be used to iterate through all the elements again.
+   * The iterators of the same iterable can be stepped through independently,
+   * but should return the same elements in the same order,
+   * as long as the underlying collection isn't changed.
+   *
+   * Modifying the collection may cause new iterators to produce
+   * different elements, and may change the order of existing elements.
+   * A [List] specifies its iteration order precisely,
+   * so modifying the list changes the iteration order predictably.
+   * A hash-based [Set] may change its iteration order completely
+   * when adding a new element to the set.
+   *
+   * Modifying the underlying collection after creating the new iterator
+   * may cause an error the next time [Iterator.moveNext] is called
+   * on that iterator.
+   * Any *modifiable* iterable class should specify which operations will
+   * break iteration.
+   */
+  Iterator<E> get iterator;
+
+  /**
+   * Provides a view of this iterable as an iterable of [R] instances.
+   *
+   * If this iterable only contains instances of [R], all operations
+   * will work correctly. If any operation tries to access an element
+   * that is not an instance of [R], the access will throw instead.
+   *
+   * When the returned iterable creates a new object that depends on
+   * the type [R], e.g., from [toList], it will have exactly the type [R].
+   */
+  Iterable<R> cast<R>() => Iterable.castFrom<E, R>(this);
+  /**
+   * Returns the lazy concatentation of this iterable and [other].
+   *
+   * The returned iterable will provide the same elements as this iterable,
+   * and, after that, the elements of [other], in the same order as in the
+   * original iterables.
+   */
+  Iterable<E> followedBy(Iterable<E> other) {
+    if (this is EfficientLengthIterable<E>) {
+      return FollowedByIterable<E>.firstEfficient(this, other);
+    }
+    return FollowedByIterable<E>(this, other);
+  }
+
+  /**
+   * Returns a new lazy [Iterable] with elements that are created by
+   * calling `f` on each element of this `Iterable` in iteration order.
+   *
+   * This method returns a view of the mapped elements. As long as the
+   * returned [Iterable] is not iterated over, the supplied function [f] will
+   * not be invoked. The transformed elements will not be cached. Iterating
+   * multiple times over the returned [Iterable] will invoke the supplied
+   * function [f] multiple times on the same element.
+   *
+   * Methods on the returned iterable are allowed to omit calling `f`
+   * on any element where the result isn't needed.
+   * For example, [elementAt] may call `f` only once.
+   */
+  Iterable<T> map<T>(T f(E e)) => MappedIterable<E, T>(this, f);
+
+  /**
+   * Returns a new lazy [Iterable] with all elements that satisfy the
+   * predicate [test].
+   *
+   * The matching elements have the same order in the returned iterable
+   * as they have in [iterator].
+   *
+   * This method returns a view of the mapped elements.
+   * As long as the returned [Iterable] is not iterated over,
+   * the supplied function [test] will not be invoked.
+   * Iterating will not cache results, and thus iterating multiple times over
+   * the returned [Iterable] may invoke the supplied
+   * function [test] multiple times on the same element.
+   */
+  Iterable<E> where(bool test(E element)) => WhereIterable<E>(this, test);
+
+  /**
+   * Returns a new lazy [Iterable] with all elements that have type [T].
+   *
+   * The matching elements have the same order in the returned iterable
+   * as they have in [iterator].
+   *
+   * This method returns a view of the mapped elements.
+   * Iterating will not cache results, and thus iterating multiple times over
+   * the returned [Iterable] may yield different results,
+   * if the underlying elements change between iterations.
+   */
+  Iterable<T> whereType<T>() => WhereTypeIterable<T>(this);
+
+  /**
+   * Expands each element of this [Iterable] into zero or more elements.
+   *
+   * The resulting Iterable runs through the elements returned
+   * by [f] for each element of this, in iteration order.
+   *
+   * The returned [Iterable] is lazy, and calls [f] for each element
+   * of this every time it's iterated.
+   *
+   * Example:
+   *
+   *     var pairs = [[1, 2], [3, 4]];
+   *     var flattened = pairs.expand((pair) => pair).toList();
+   *     print(flattened); // => [1, 2, 3, 4];
+   *
+   *     var input = [1, 2, 3];
+   *     var duplicated = input.expand((i) => [i, i]).toList();
+   *     print(duplicated); // => [1, 1, 2, 2, 3, 3]
+   *
+   */
+  Iterable<T> expand<T>(Iterable<T> f(E element)) =>
+      ExpandIterable<E, T>(this, f);
+
+  /**
+   * Returns true if the collection contains an element equal to [element].
+   *
+   * This operation will check each element in order for being equal to
+   * [element], unless it has a more efficient way to find an element
+   * equal to [element].
+   *
+   * The equality used to determine whether [element] is equal to an element of
+   * the iterable defaults to the [Object.==] of the element.
+   *
+   * Some types of iterable may have a different equality used for its elements.
+   * For example, a [Set] may have a custom equality
+   * (see [Set.identity]) that its `contains` uses.
+   * Likewise the `Iterable` returned by a [Map.keys] call
+   * should use the same equality that the `Map` uses for keys.
+   */
+  bool contains(Object element) {
+    for (E e in this) {
+      if (e == element) return true;
+    }
+    return false;
+  }
+
+  /**
+   * Applies the function [f] to each element of this collection in iteration
+   * order.
+   */
+  void forEach(void f(E element)) {
+    for (E element in this) f(element);
+  }
+
+  /**
+   * Reduces a collection to a single value by iteratively combining elements
+   * of the collection using the provided function.
+   *
+   * The iterable must have at least one element.
+   * If it has only one element, that element is returned.
+   *
+   * Otherwise this method starts with the first element from the iterator,
+   * and then combines it with the remaining elements in iteration order,
+   * as if by:
+   *
+   *     E value = iterable.first;
+   *     iterable.skip(1).forEach((element) {
+   *       value = combine(value, element);
+   *     });
+   *     return value;
+   *
+   * Example of calculating the sum of an iterable:
+   *
+   *     iterable.reduce((value, element) => value + element);
+   *
+   */
+  E reduce(E combine(E value, E element)) {
+    Iterator<E> iterator = this.iterator;
+    if (!iterator.moveNext()) {
+      throw IterableElementError.noElement();
+    }
+    E value = iterator.current;
+    while (iterator.moveNext()) {
+      value = combine(value, iterator.current);
+    }
+    return value;
+  }
+
+  /**
+   * Reduces a collection to a single value by iteratively combining each
+   * element of the collection with an existing value
+   *
+   * Uses [initialValue] as the initial value,
+   * then iterates through the elements and updates the value with
+   * each element using the [combine] function, as if by:
+   *
+   *     var value = initialValue;
+   *     for (E element in this) {
+   *       value = combine(value, element);
+   *     }
+   *     return value;
+   *
+   * Example of calculating the sum of an iterable:
+   *
+   *     iterable.fold(0, (prev, element) => prev + element);
+   *
+   */
+  T fold<T>(T initialValue, T combine(T previousValue, E element)) {
+    var value = initialValue;
+    for (E element in this) value = combine(value, element);
+    return value;
+  }
+
+  /**
+   * Checks whether every element of this iterable satisfies [test].
+   *
+   * Checks every element in iteration order, and returns `false` if
+   * any of them make [test] return `false`, otherwise returns `true`.
+   */
+  bool every(bool test(E element)) {
+    for (E element in this) {
+      if (!test(element)) return false;
+    }
+    return true;
+  }
+
+  /**
+   * Converts each element to a [String] and concatenates the strings.
+   *
+   * Iterates through elements of this iterable,
+   * converts each one to a [String] by calling [Object.toString],
+   * and then concatenates the strings, with the
+   * [separator] string interleaved between the elements.
+   */
+  String join([String separator = ""]) {
+    Iterator<E> iterator = this.iterator;
+    if (!iterator.moveNext()) return "";
+    StringBuffer buffer = StringBuffer();
+    if (separator == null || separator == "") {
+      do {
+        buffer.write("${iterator.current}");
+      } while (iterator.moveNext());
+    } else {
+      buffer.write("${iterator.current}");
+      while (iterator.moveNext()) {
+        buffer.write(separator);
+        buffer.write("${iterator.current}");
+      }
+    }
+    return buffer.toString();
+  }
+
+  /**
+   * Checks whether any element of this iterable satisfies [test].
+   *
+   * Checks every element in iteration order, and returns `true` if
+   * any of them make [test] return `true`, otherwise returns false.
+   */
+  bool any(bool test(E element)) {
+    for (E element in this) {
+      if (test(element)) return true;
+    }
+    return false;
+  }
+
+  /**
+   * Creates a [List] containing the elements of this [Iterable].
+   *
+   * The elements are in iteration order.
+   * The list is fixed-length if [growable] is false.
+   */
+  List<E> toList({bool growable = true}) {
+    return List<E>.from(this, growable: growable);
+  }
+
+  /**
+   * Creates a [Set] containing the same elements as this iterable.
+   *
+   * The set may contain fewer elements than the iterable,
+   * if the iterable contains an element more than once,
+   * or it contains one or more elements that are equal.
+   * The order of the elements in the set is not guaranteed to be the same
+   * as for the iterable.
+   */
+  Set<E> toSet() => Set<E>.from(this);
+
+  /**
+   * Returns the number of elements in [this].
+   *
+   * Counting all elements may involve iterating through all elements and can
+   * therefore be slow.
+   * Some iterables have a more efficient way to find the number of elements.
+   */
+  int get length {
+    assert(this is! EfficientLengthIterable);
+    int count = 0;
+    Iterator it = iterator;
+    while (it.moveNext()) {
+      count++;
+    }
+    return count;
+  }
+
+  /**
+   * Returns `true` if there are no elements in this collection.
+   *
+   * May be computed by checking if `iterator.moveNext()` returns `false`.
+   */
+  bool get isEmpty => !iterator.moveNext();
+
+  /**
+   * Returns true if there is at least one element in this collection.
+   *
+   * May be computed by checking if `iterator.moveNext()` returns `true`.
+   */
+  bool get isNotEmpty => !isEmpty;
+
+  /**
+   * Returns a lazy iterable of the [count] first elements of this iterable.
+   *
+   * The returned `Iterable` may contain fewer than `count` elements, if `this`
+   * contains fewer than `count` elements.
+   *
+   * The elements can be computed by stepping through [iterator] until [count]
+   * elements have been seen.
+   *
+   * The `count` must not be negative.
+   */
+  Iterable<E> take(int count) {
+    return TakeIterable<E>(this, count);
+  }
+
+  /**
+   * Returns a lazy iterable of the leading elements satisfying [test].
+   *
+   * The filtering happens lazily. Every new iterator of the returned
+   * iterable starts iterating over the elements of `this`.
+   *
+   * The elements can be computed by stepping through [iterator] until an
+   * element is found where `test(element)` is false. At that point,
+   * the returned iterable stops (its `moveNext()` returns false).
+   */
+  Iterable<E> takeWhile(bool test(E value)) {
+    return TakeWhileIterable<E>(this, test);
+  }
+
+  /**
+   * Returns an [Iterable] that provides all but the first [count] elements.
+   *
+   * When the returned iterable is iterated, it starts iterating over `this`,
+   * first skipping past the initial [count] elements.
+   * If `this` has fewer than `count` elements, then the resulting Iterable is
+   * empty.
+   * After that, the remaining elements are iterated in the same order as
+   * in this iterable.
+   *
+   * Some iterables may be able to find later elements without first iterating
+   * through earlier elements, for example when iterating a [List].
+   * Such iterables are allowed to ignore the initial skipped elements.
+   *
+   * The [count] must not be negative.
+   */
+  Iterable<E> skip(int count) {
+    return SkipIterable<E>(this, count);
+  }
+
+  /**
+   * Returns an `Iterable` that skips leading elements while [test] is satisfied.
+   *
+   * The filtering happens lazily. Every new [Iterator] of the returned
+   * iterable iterates over all elements of `this`.
+   *
+   * The returned iterable provides elements by iterating this iterable,
+   * but skipping over all initial elements where `test(element)` returns
+   * true. If all elements satisfy `test` the resulting iterable is empty,
+   * otherwise it iterates the remaining elements in their original order,
+   * starting with the first element for which `test(element)` returns `false`.
+   */
+  Iterable<E> skipWhile(bool test(E value)) {
+    return SkipWhileIterable<E>(this, test);
+  }
+
+  /**
+   * Returns the first element.
+   *
+   * Throws a [StateError] if `this` is empty.
+   * Otherwise returns the first element in the iteration order,
+   * equivalent to `this.elementAt(0)`.
+   */
+  E get first {
+    Iterator<E> it = iterator;
+    if (!it.moveNext()) {
+      throw IterableElementError.noElement();
+    }
+    return it.current;
+  }
+
+  /**
+   * Returns the last element.
+   *
+   * Throws a [StateError] if `this` is empty.
+   * Otherwise may iterate through the elements and returns the last one
+   * seen.
+   * Some iterables may have more efficient ways to find the last element
+   * (for example a list can directly access the last element,
+   * without iterating through the previous ones).
+   */
+  E get last {
+    Iterator<E> it = iterator;
+    if (!it.moveNext()) {
+      throw IterableElementError.noElement();
+    }
+    E result;
+    do {
+      result = it.current;
+    } while (it.moveNext());
+    return result;
+  }
+
+  /**
+   * Checks that this iterable has only one element, and returns that element.
+   *
+   * Throws a [StateError] if `this` is empty or has more than one element.
+   */
+  E get single {
+    Iterator<E> it = iterator;
+    if (!it.moveNext()) throw IterableElementError.noElement();
+    E result = it.current;
+    if (it.moveNext()) throw IterableElementError.tooMany();
+    return result;
+  }
+
+  /**
+   * Returns the first element that satisfies the given predicate [test].
+   *
+   * Iterates through elements and returns the first to satisfy [test].
+   *
+   * If no element satisfies [test], the result of invoking the [orElse]
+   * function is returned.
+   * If [orElse] is omitted, it defaults to throwing a [StateError].
+   */
+  E firstWhere(bool test(E element), {E orElse()}) {
+    for (E element in this) {
+      if (test(element)) return element;
+    }
+    if (orElse != null) return orElse();
+    throw IterableElementError.noElement();
+  }
+
+  /**
+   * Returns the last element that satisfies the given predicate [test].
+   *
+   * An iterable that can access its elements directly may check its
+   * elements in any order (for example a list starts by checking the
+   * last element and then moves towards the start of the list).
+   * The default implementation iterates elements in iteration order,
+   * checks `test(element)` for each,
+   * and finally returns that last one that matched.
+   *
+   * If no element satisfies [test], the result of invoking the [orElse]
+   * function is returned.
+   * If [orElse] is omitted, it defaults to throwing a [StateError].
+   */
+  E lastWhere(bool test(E element), {E orElse()}) {
+    E result;
+    bool foundMatching = false;
+    for (E element in this) {
+      if (test(element)) {
+        result = element;
+        foundMatching = true;
+      }
+    }
+    if (foundMatching) return result;
+    if (orElse != null) return orElse();
+    throw IterableElementError.noElement();
+  }
+
+  /**
+   * Returns the single element that satisfies [test].
+   *
+   * Checks elements to see if `test(element)` returns true.
+   * If exactly one element satisfies [test], that element is returned.
+   * If more than one matching element is found, throws [StateError].
+   * If no matching element is found, returns the result of [orElse].
+   * If [orElse] is omitted, it defaults to throwing a [StateError].
+   */
+  E singleWhere(bool test(E element), {E orElse()}) {
+    E result;
+    bool foundMatching = false;
+    for (E element in this) {
+      if (test(element)) {
+        if (foundMatching) {
+          throw IterableElementError.tooMany();
+        }
+        result = element;
+        foundMatching = true;
+      }
+    }
+    if (foundMatching) return result;
+    if (orElse != null) return orElse();
+    throw IterableElementError.noElement();
+  }
+
+  /**
+   * Returns the [index]th element.
+   *
+   * The [index] must be non-negative and less than [length].
+   * Index zero represents the first element (so `iterable.elementAt(0)` is
+   * equivalent to `iterable.first`).
+   *
+   * May iterate through the elements in iteration order, ignoring the
+   * first [index] elements and then returning the next.
+   * Some iterables may have more a efficient way to find the element.
+   */
+  E elementAt(int index) {
+    ArgumentError.checkNotNull(index, "index");
+    RangeError.checkNotNegative(index, "index");
+    int elementIndex = 0;
+    for (E element in this) {
+      if (index == elementIndex) return element;
+      elementIndex++;
+    }
+    throw RangeError.index(index, this, "index", null, elementIndex);
+  }
+
+  /**
+   * Returns a string representation of (some of) the elements of `this`.
+   *
+   * Elements are represented by their own `toString` results.
+   *
+   * The default representation always contains the first three elements.
+   * If there are less than a hundred elements in the iterable, it also
+   * contains the last two elements.
+   *
+   * If the resulting string isn't above 80 characters, more elements are
+   * included from the start of the iterable.
+   *
+   * The conversion may omit calling `toString` on some elements if they
+   * are known to not occur in the output, and it may stop iterating after
+   * a hundred elements.
+   */
+  String toString() => IterableBase.iterableToShortString(this, '(', ')');
+}
+
+typedef _Generator<E> = E Function(int index);
+
+class _GeneratorIterable<E> extends ListIterable<E> {
+  /// The length of the generated iterable.
+  final int length;
+
+  /// The function mapping indices to values.
+  final _Generator<E> _generator;
+
+  /// Creates the generated iterable.
+  ///
+  /// If [generator] is `null`, it is checked that `int` is assignable to [E].
+  _GeneratorIterable(this.length, E generator(int index))
+      : // The `as` below is used as check to make sure that `int` is assignable
+        // to [E].
+        _generator = (generator != null) ? generator : _id as _Generator<E>;
+
+  E elementAt(int index) {
+    RangeError.checkValidIndex(index, this);
+    return _generator(index);
+  }
+
+  /// Helper function used as default _generator function.
+  static int _id(int n) => n;
+}
+
+/**
+ * An Iterator that allows moving backwards as well as forwards.
+ */
+abstract class BidirectionalIterator<E> implements Iterator<E> {
+  /**
+   * Move back to the previous element.
+   *
+   * Returns true and updates [current] if successful. Returns false
+   * and sets [current] to null if there is no previous element.
+   */
+  bool movePrevious();
+}
diff --git a/sdk_nnbd/lib/core/iterator.dart b/sdk_nnbd/lib/core/iterator.dart
new file mode 100644
index 0000000..cd0ad32
--- /dev/null
+++ b/sdk_nnbd/lib/core/iterator.dart
@@ -0,0 +1,62 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.core;
+
+/**
+ * An interface for getting items, one at a time, from an object.
+ *
+ * The for-in construct transparently uses `Iterator` to test for the end
+ * of the iteration, and to get each item (or _element_).
+ *
+ * If the object iterated over is changed during the iteration, the
+ * behavior is unspecified.
+ *
+ * The `Iterator` is initially positioned before the first element.
+ * Before accessing the first element the iterator must thus be advanced using
+ * [moveNext] to point to the first element.
+ * If no element is left, then [moveNext] returns false, [current]
+ * returns `null`, and all further calls to [moveNext] will also return false.
+ *
+ * A typical usage of an Iterator looks as follows:
+ *
+ *     var it = obj.iterator;
+ *     while (it.moveNext()) {
+ *       use(it.current);
+ *     }
+ *
+ * **See also:**
+ * [Iteration](http://www.dartlang.org/docs/dart-up-and-running/contents/ch03.html#iteration)
+ * in the [library tour](http://www.dartlang.org/docs/dart-up-and-running/contents/ch03.html)
+ */
+abstract class Iterator<E> {
+  /**
+   * Moves to the next element.
+   *
+   * Returns true if [current] contains the next element.
+   * Returns false if no elements are left.
+   *
+   * It is safe to invoke [moveNext] even when the iterator is already
+   * positioned after the last element.
+   * In this case [moveNext] returns false again and has no effect.
+   *
+   * A call to `moveNext` may throw if iteration has been broken by
+   * changing the underlying collection.
+   */
+  bool moveNext();
+
+  /**
+   * Returns the current element.
+   *
+   * Returns `null` if the iterator has not yet been moved to the first
+   * element, or if the iterator has been moved past the last element of the
+   * [Iterable].
+   *
+   * The `current` getter should keep its value until the next call to
+   * [moveNext], even if an underlying collection changes.
+   * After a successful call to `moveNext`, the user doesn't need to cache
+   * the current value, but can keep reading it from the iterator.
+   */
+  E get current;
+}
diff --git a/sdk_nnbd/lib/core/list.dart b/sdk_nnbd/lib/core/list.dart
new file mode 100644
index 0000000..27e1653
--- /dev/null
+++ b/sdk_nnbd/lib/core/list.dart
@@ -0,0 +1,731 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.core;
+
+/**
+ * An indexable collection of objects with a length.
+ *
+ * Subclasses of this class implement different kinds of lists.
+ * The most common kinds of lists are:
+ *
+ * * Fixed-length list.
+ *   An error occurs when attempting to use operations
+ *   that can change the length of the list.
+ *
+ * * Growable list. Full implementation of the API defined in this class.
+ *
+ * The default growable list, as returned by `new List()` or `[]`, keeps
+ * an internal buffer, and grows that buffer when necessary. This guarantees
+ * that a sequence of [add] operations will each execute in amortized constant
+ * time. Setting the length directly may take time proportional to the new
+ * length, and may change the internal capacity so that a following add
+ * operation will need to immediately increase the buffer capacity.
+ * Other list implementations may have different performance behavior.
+ *
+ * The following code illustrates that some List implementations support
+ * only a subset of the API.
+ *
+ *     List<int> fixedLengthList = new List(5);
+ *     fixedLengthList.length = 0;  // Error
+ *     fixedLengthList.add(499);    // Error
+ *     fixedLengthList[0] = 87;
+ *     List<int> growableList = [1, 2];
+ *     growableList.length = 0;
+ *     growableList.add(499);
+ *     growableList[0] = 87;
+ *
+ * Lists are [Iterable]. Iteration occurs over values in index order. Changing
+ * the values does not affect iteration, but changing the valid
+ * indices&mdash;that is, changing the list's length&mdash;between iteration
+ * steps causes a [ConcurrentModificationError]. This means that only growable
+ * lists can throw ConcurrentModificationError. If the length changes
+ * temporarily and is restored before continuing the iteration, the iterator
+ * does not detect it.
+ *
+ * It is generally not allowed to modify the list's length (adding or removing
+ * elements) while an operation on the list is being performed,
+ * for example during a call to [forEach] or [sort].
+ * Changing the list's length while it is being iterated, either by iterating it
+ * directly or through iterating an [Iterable] that is backed by the list, will
+ * break the iteration.
+ */
+abstract class List<E> implements EfficientLengthIterable<E> {
+  /**
+   * Creates a list of the given length.
+   *
+   * The created list is fixed-length if [length] is provided.
+   *
+   *     List fixedLengthList = new List(3);
+   *     fixedLengthList.length;     // 3
+   *     fixedLengthList.length = 1; // Error
+   *
+   * The list has length 0 and is growable if [length] is omitted.
+   *
+   *     List growableList = new List();
+   *     growableList.length; // 0;
+   *     growableList.length = 3;
+   *
+   * To create a growable list with a given length, just assign the length
+   * right after creation:
+   *
+   *     List growableList = new List()..length = 500;
+   *
+   * The [length] must not be negative or null, if it is provided.
+   */
+  external factory List([int length]);
+
+  /**
+   * Creates a list of the given length with [fill] at each position.
+   *
+   * The [length] must be a non-negative integer.
+   *
+   * Example:
+   * ```dart
+   * new List<int>.filled(3, 0, growable: true); // [0, 0, 0]
+   * ```
+   *
+   * The created list is fixed-length if [growable] is false (the default)
+   * and growable if [growable] is true.
+   * If the list is growable, changing its length will not initialize new
+   * entries with [fill].
+   * After being created and filled, the list is no different from any other
+   * growable or fixed-length list created using [List].
+   *
+   * All elements of the returned list share the same [fill] value.
+   * ```
+   * var shared = new List.filled(3, []);
+   * shared[0].add(499);
+   * print(shared);  // => [[499], [499], [499]]
+   * ```
+   *
+   * You can use [List.generate] to create a list with a new object at
+   * each position.
+   * ```
+   * var unique = new List.generate(3, (_) => []);
+   * unique[0].add(499);
+   * print(unique); // => [[499], [], []]
+   * ```
+   */
+  external factory List.filled(int length, E fill, {bool growable = false});
+
+  /**
+   * Creates a list containing all [elements].
+   *
+   * The [Iterator] of [elements] provides the order of the elements.
+   *
+   * All the [elements] should be instances of [E].
+   * The `elements` iterable itself may have any element type, so this
+   * constructor can be used to down-cast a `List`, for example as:
+   * ```dart
+   * List<SuperType> superList = ...;
+   * List<SubType> subList =
+   *     new List<SubType>.from(superList.whereType<SubType>());
+   * ```
+   *
+   * This constructor creates a growable list when [growable] is true;
+   * otherwise, it returns a fixed-length list.
+   */
+  external factory List.from(Iterable elements, {bool growable = true});
+
+  /**
+   * Creates a list from [elements].
+   *
+   * The [Iterator] of [elements] provides the order of the elements.
+   *
+   * This constructor creates a growable list when [growable] is true;
+   * otherwise, it returns a fixed-length list.
+   */
+  factory List.of(Iterable<E> elements, {bool growable = true}) =>
+      List<E>.from(elements, growable: growable);
+
+  /**
+   * Generates a list of values.
+   *
+   * Creates a list with [length] positions and fills it with values created by
+   * calling [generator] for each index in the range `0` .. `length - 1`
+   * in increasing order.
+   *
+   *     new List<int>.generate(3, (int index) => index * index); // [0, 1, 4]
+   *
+   * The created list is fixed-length unless [growable] is true.
+   */
+  factory List.generate(int length, E generator(int index),
+      {bool growable = true}) {
+    List<E> result;
+    if (growable) {
+      result = <E>[]..length = length;
+    } else {
+      result = List<E>(length);
+    }
+    for (int i = 0; i < length; i++) {
+      result[i] = generator(i);
+    }
+    return result;
+  }
+
+  /**
+   * Creates an unmodifiable list containing all [elements].
+   *
+   * The [Iterator] of [elements] provides the order of the elements.
+   *
+   * An unmodifiable list cannot have its length or elements changed.
+   * If the elements are themselves immutable, then the resulting list
+   * is also immutable.
+   */
+  external factory List.unmodifiable(Iterable elements);
+
+  /**
+   * Adapts [source] to be a `List<T>`.
+   *
+   * Any time the list would produce an element that is not a [T],
+   * the element access will throw.
+   *
+   * Any time a [T] value is attempted stored into the adapted list,
+   * the store will throw unless the value is also an instance of [S].
+   *
+   * If all accessed elements of [source] are actually instances of [T],
+   * and if all elements stored into the returned list are actually instance
+   * of [S],
+   * then the returned list can be used as a `List<T>`.
+   */
+  static List<T> castFrom<S, T>(List<S> source) => CastList<S, T>(source);
+
+  /**
+   * Copy a range of one list into another list.
+   *
+   * This is a utility function that can be used to implement methods like
+   * [setRange].
+   *
+   * The range from [start] to [end] must be a valid range of [source],
+   * and there must be room for `end - start` elements from position [at].
+   * If [start] is omitted, it defaults to zero.
+   * If [end] is omitted, it defaults to [source.length].
+   *
+   * If [source] and [target] is the same list, overlapping source and target
+   * ranges are respected so that the target range ends up containing the
+   * initial content of the source range.
+   * Otherwise the order of element copying is not guaranteed.
+   */
+  static void copyRange<T>(List<T> target, int at, List<T> source,
+      [int start, int end]) {
+    start ??= 0;
+    end = RangeError.checkValidRange(start, end, source.length);
+    int length = end - start;
+    if (target.length < at + length) {
+      throw ArgumentError.value(target, "target",
+          "Not big enough to hold $length elements at position $at");
+    }
+    if (!identical(source, target) || start >= at) {
+      for (int i = 0; i < length; i++) {
+        target[at + i] = source[start + i];
+      }
+    } else {
+      for (int i = length; --i >= 0;) {
+        target[at + i] = source[start + i];
+      }
+    }
+  }
+
+  /**
+   * Write the elements of an iterable into a list.
+   *
+   * This is a utility function that can be used to implement methods like
+   * [setAll].
+   *
+   * The elements of [source] are written into [target] from position [at].
+   * The [source] must not contain more elements after writing the last
+   * position of [target].
+   *
+   * If the source is a list, the [copyRange] function is likely to be more
+   * efficient.
+   */
+  static void writeIterable<T>(List<T> target, int at, Iterable<T> source) {
+    RangeError.checkValueInInterval(at, 0, target.length, "at");
+    int index = at;
+    int targetLength = target.length;
+    for (var element in source) {
+      if (index == targetLength) {
+        throw IndexError(targetLength, target);
+      }
+      target[index] = element;
+      index++;
+    }
+  }
+
+  /**
+   * Returns a view of this list as a list of [R] instances.
+   *
+   * If this list contains only instances of [R], all read operations
+   * will work correctly. If any operation tries to access an element
+   * that is not an instance of [R], the access will throw instead.
+   *
+   * Elements added to the list (e.g., by using [add] or [addAll])
+   * must be instance of [R] to be valid arguments to the adding function,
+   * and they must be instances of [E] as well to be accepted by
+   * this list as well.
+   *
+   * Typically implemented as `List.castFrom<E, R>(this)`.
+   */
+  List<R> cast<R>();
+  /**
+   * Returns the object at the given [index] in the list
+   * or throws a [RangeError] if [index] is out of bounds.
+   */
+  E operator [](int index);
+
+  /**
+   * Sets the value at the given [index] in the list to [value]
+   * or throws a [RangeError] if [index] is out of bounds.
+   */
+  void operator []=(int index, E value);
+
+  /**
+   * Updates the first position of the list to contain [value].
+   *
+   * Equivalent to `theList[0] = value;`.
+   *
+   * The list must be non-empty.
+   */
+  void set first(E value);
+
+  /**
+   * Updates the last position of the list to contain [value].
+   *
+   * Equivalent to `theList[theList.length - 1] = value;`.
+   *
+   * The list must be non-empty.
+   */
+  void set last(E value);
+
+  /**
+   * Returns the number of objects in this list.
+   *
+   * The valid indices for a list are `0` through `length - 1`.
+   */
+  int get length;
+
+  /**
+   * Changes the length of this list.
+   *
+   * If [newLength] is greater than
+   * the current length, entries are initialized to [:null:].
+   *
+   * Throws an [UnsupportedError] if the list is fixed-length.
+   */
+  set length(int newLength);
+
+  /**
+   * Adds [value] to the end of this list,
+   * extending the length by one.
+   *
+   * Throws an [UnsupportedError] if the list is fixed-length.
+   */
+  void add(E value);
+
+  /**
+   * Appends all objects of [iterable] to the end of this list.
+   *
+   * Extends the length of the list by the number of objects in [iterable].
+   * Throws an [UnsupportedError] if this list is fixed-length.
+   */
+  void addAll(Iterable<E> iterable);
+
+  /**
+   * Returns an [Iterable] of the objects in this list in reverse order.
+   */
+  Iterable<E> get reversed;
+
+  /**
+   * Sorts this list according to the order specified by the [compare] function.
+   *
+   * The [compare] function must act as a [Comparator].
+   *
+   *     List<String> numbers = ['two', 'three', 'four'];
+   *     // Sort from shortest to longest.
+   *     numbers.sort((a, b) => a.length.compareTo(b.length));
+   *     print(numbers);  // [two, four, three]
+   *
+   * The default List implementations use [Comparable.compare] if
+   * [compare] is omitted.
+   *
+   *     List<int> nums = [13, 2, -11];
+   *     nums.sort();
+   *     print(nums);  // [-11, 2, 13]
+   *
+   * A [Comparator] may compare objects as equal (return zero), even if they
+   * are distinct objects.
+   * The sort function is not guaranteed to be stable, so distinct objects
+   * that compare as equal may occur in any order in the result:
+   *
+   *     List<String> numbers = ['one', 'two', 'three', 'four'];
+   *     numbers.sort((a, b) => a.length.compareTo(b.length));
+   *     print(numbers);  // [one, two, four, three] OR [two, one, four, three]
+   */
+  void sort([int compare(E a, E b)]);
+
+  /**
+   * Shuffles the elements of this list randomly.
+   */
+  void shuffle([Random random]);
+
+  /**
+   * Returns the first index of [element] in this list.
+   *
+   * Searches the list from index [start] to the end of the list.
+   * The first time an object [:o:] is encountered so that [:o == element:],
+   * the index of [:o:] is returned.
+   *
+   *     List<String> notes = ['do', 're', 'mi', 're'];
+   *     notes.indexOf('re');    // 1
+   *     notes.indexOf('re', 2); // 3
+   *
+   * Returns -1 if [element] is not found.
+   *
+   *     notes.indexOf('fa');    // -1
+   */
+  int indexOf(E element, [int start = 0]);
+
+  /**
+   * Returns the first index in the list that satisfies the provided [test].
+   *
+   * Searches the list from index [start] to the end of the list.
+   * The first time an object `o` is encountered so that `test(o)` is true,
+   * the index of `o` is returned.
+   *
+   * ```
+   * List<String> notes = ['do', 're', 'mi', 're'];
+   * notes.indexWhere((note) => note.startsWith('r'));       // 1
+   * notes.indexWhere((note) => note.startsWith('r'), 2);    // 3
+   * ```
+   *
+   * Returns -1 if [element] is not found.
+   * ```
+   * notes.indexWhere((note) => note.startsWith('k'));    // -1
+   * ```
+   */
+  int indexWhere(bool test(E element), [int start = 0]);
+
+  /**
+   * Returns the last index in the list that satisfies the provided [test].
+   *
+   * Searches the list from index [start] to 0.
+   * The first time an object `o` is encountered so that `test(o)` is true,
+   * the index of `o` is returned.
+   *
+   * ```
+   * List<String> notes = ['do', 're', 'mi', 're'];
+   * notes.lastIndexWhere((note) => note.startsWith('r'));       // 3
+   * notes.lastIndexWhere((note) => note.startsWith('r'), 2);    // 1
+   * ```
+   *
+   * Returns -1 if [element] is not found.
+   * ```
+   * notes.lastIndexWhere((note) => note.startsWith('k'));    // -1
+   * ```
+   */
+  int lastIndexWhere(bool test(E element), [int start]);
+
+  /**
+   * Returns the last index of [element] in this list.
+   *
+   * Searches the list backwards from index [start] to 0.
+   *
+   * The first time an object [:o:] is encountered so that [:o == element:],
+   * the index of [:o:] is returned.
+   *
+   *     List<String> notes = ['do', 're', 'mi', 're'];
+   *     notes.lastIndexOf('re', 2); // 1
+   *
+   * If [start] is not provided, this method searches from the end of the
+   * list./Returns
+   *
+   *     notes.lastIndexOf('re');  // 3
+   *
+   * Returns -1 if [element] is not found.
+   *
+   *     notes.lastIndexOf('fa');  // -1
+   */
+  int lastIndexOf(E element, [int start]);
+
+  /**
+   * Removes all objects from this list;
+   * the length of the list becomes zero.
+   *
+   * Throws an [UnsupportedError], and retains all objects, if this
+   * is a fixed-length list.
+   */
+  void clear();
+
+  /**
+   * Inserts the object at position [index] in this list.
+   *
+   * This increases the length of the list by one and shifts all objects
+   * at or after the index towards the end of the list.
+   *
+   * The list must be growable.
+   * The [index] value must be non-negative and no greater than [length].
+   */
+  void insert(int index, E element);
+
+  /**
+   * Inserts all objects of [iterable] at position [index] in this list.
+   *
+   * This increases the length of the list by the length of [iterable] and
+   * shifts all later objects towards the end of the list.
+   *
+   * The list must be growable.
+   * The [index] value must be non-negative and no greater than [length].
+   */
+  void insertAll(int index, Iterable<E> iterable);
+
+  /**
+   * Overwrites objects of `this` with the objects of [iterable], starting
+   * at position [index] in this list.
+   *
+   *     List<String> list = ['a', 'b', 'c'];
+   *     list.setAll(1, ['bee', 'sea']);
+   *     list.join(', '); // 'a, bee, sea'
+   *
+   * This operation does not increase the length of `this`.
+   *
+   * The [index] must be non-negative and no greater than [length].
+   *
+   * The [iterable] must not have more elements than what can fit from [index]
+   * to [length].
+   *
+   * If `iterable` is based on this list, its values may change /during/ the
+   * `setAll` operation.
+   */
+  void setAll(int index, Iterable<E> iterable);
+
+  /**
+   * Removes the first occurrence of [value] from this list.
+   *
+   * Returns true if [value] was in the list, false otherwise.
+   *
+   *     List<String> parts = ['head', 'shoulders', 'knees', 'toes'];
+   *     parts.remove('head'); // true
+   *     parts.join(', ');     // 'shoulders, knees, toes'
+   *
+   * The method has no effect if [value] was not in the list.
+   *
+   *     // Note: 'head' has already been removed.
+   *     parts.remove('head'); // false
+   *     parts.join(', ');     // 'shoulders, knees, toes'
+   *
+   * An [UnsupportedError] occurs if the list is fixed-length.
+   */
+  bool remove(Object value);
+
+  /**
+   * Removes the object at position [index] from this list.
+   *
+   * This method reduces the length of `this` by one and moves all later objects
+   * down by one position.
+   *
+   * Returns the removed object.
+   *
+   * The [index] must be in the range `0 ≤ index < length`.
+   *
+   * Throws an [UnsupportedError] if this is a fixed-length list. In that case
+   * the list is not modified.
+   */
+  E removeAt(int index);
+
+  /**
+   * Pops and returns the last object in this list.
+   *
+   * The list must not be empty.
+   *
+   * Throws an [UnsupportedError] if this is a fixed-length list.
+   */
+  E removeLast();
+
+  /**
+   * Removes all objects from this list that satisfy [test].
+   *
+   * An object [:o:] satisfies [test] if [:test(o):] is true.
+   *
+   *     List<String> numbers = ['one', 'two', 'three', 'four'];
+   *     numbers.removeWhere((item) => item.length == 3);
+   *     numbers.join(', '); // 'three, four'
+   *
+   * Throws an [UnsupportedError] if this is a fixed-length list.
+   */
+  void removeWhere(bool test(E element));
+
+  /**
+   * Removes all objects from this list that fail to satisfy [test].
+   *
+   * An object [:o:] satisfies [test] if [:test(o):] is true.
+   *
+   *     List<String> numbers = ['one', 'two', 'three', 'four'];
+   *     numbers.retainWhere((item) => item.length == 3);
+   *     numbers.join(', '); // 'one, two'
+   *
+   * Throws an [UnsupportedError] if this is a fixed-length list.
+   */
+  void retainWhere(bool test(E element));
+
+  /**
+   * Returns the concatenation of this list and [other].
+   *
+   * Returns a new list containing the elements of this list followed by
+   * the elements of [other].
+   *
+   * The default behavior is to return a normal growable list.
+   * Some list types may choose to return a list of the same type as themselves
+   * (see [Uint8List.+]);
+   */
+  List<E> operator +(List<E> other);
+
+  /**
+   * Returns a new list containing the elements between [start] and [end].
+   *
+   * The new list is a `List<E>` containing the elements of this list at
+   * positions greater than or equal to [start] and less than [end] in the same
+   * order as they occur in this list.
+   *
+   * ```dart
+   * var colors = ["red", "green", "blue", "orange", "pink"];
+   * print(colors.sublist(1, 3)); // [green, blue]
+   * ```
+   *
+   * If [end] is omitted, it defaults to the [length] of this list.
+   *
+   * ```dart
+   * print(colors.sublist(1)); // [green, blue, orange, pink]
+   * ```
+   *
+   * The `start` and `end` positions must satisfy the relations
+   * 0 ≤ `start` ≤ `end` ≤ `this.length`
+   * If `end` is equal to `start`, then the returned list is empty.
+   */
+  List<E> sublist(int start, [int end]);
+
+  /**
+   * Returns an [Iterable] that iterates over the objects in the range
+   * [start] inclusive to [end] exclusive.
+   *
+   * The provided range, given by [start] and [end], must be valid at the time
+   * of the call.
+   *
+   * A range from [start] to [end] is valid if `0 <= start <= end <= len`, where
+   * `len` is this list's `length`. The range starts at `start` and has length
+   * `end - start`. An empty range (with `end == start`) is valid.
+   *
+   * The returned [Iterable] behaves like `skip(start).take(end - start)`.
+   * That is, it does *not* throw if this list changes size.
+   *
+   *     List<String> colors = ['red', 'green', 'blue', 'orange', 'pink'];
+   *     Iterable<String> range = colors.getRange(1, 4);
+   *     range.join(', ');  // 'green, blue, orange'
+   *     colors.length = 3;
+   *     range.join(', ');  // 'green, blue'
+   */
+  Iterable<E> getRange(int start, int end);
+
+  /**
+   * Copies the objects of [iterable], skipping [skipCount] objects first,
+   * into the range [start], inclusive, to [end], exclusive, of the list.
+   *
+   *     List<int> list1 = [1, 2, 3, 4];
+   *     List<int> list2 = [5, 6, 7, 8, 9];
+   *     // Copies the 4th and 5th items in list2 as the 2nd and 3rd items
+   *     // of list1.
+   *     list1.setRange(1, 3, list2, 3);
+   *     list1.join(', '); // '1, 8, 9, 4'
+   *
+   * The provided range, given by [start] and [end], must be valid.
+   * A range from [start] to [end] is valid if `0 <= start <= end <= len`, where
+   * `len` is this list's `length`. The range starts at `start` and has length
+   * `end - start`. An empty range (with `end == start`) is valid.
+   *
+   * The [iterable] must have enough objects to fill the range from `start`
+   * to `end` after skipping [skipCount] objects.
+   *
+   * If `iterable` is this list, the operation copies the elements
+   * originally in the range from `skipCount` to `skipCount + (end - start)` to
+   * the range `start` to `end`, even if the two ranges overlap.
+   *
+   * If `iterable` depends on this list in some other way, no guarantees are
+   * made.
+   */
+  void setRange(int start, int end, Iterable<E> iterable, [int skipCount = 0]);
+
+  /**
+   * Removes the objects in the range [start] inclusive to [end] exclusive.
+   *
+   * The provided range, given by [start] and [end], must be valid.
+   * A range from [start] to [end] is valid if `0 <= start <= end <= len`, where
+   * `len` is this list's `length`. The range starts at `start` and has length
+   * `end - start`. An empty range (with `end == start`) is valid.
+   *
+   * Throws an [UnsupportedError] if this is a fixed-length list. In that case
+   * the list is not modified.
+   */
+  void removeRange(int start, int end);
+
+  /**
+   * Sets the objects in the range [start] inclusive to [end] exclusive
+   * to the given [fillValue].
+   *
+   * The provided range, given by [start] and [end], must be valid.
+   * A range from [start] to [end] is valid if `0 <= start <= end <= len`, where
+   * `len` is this list's `length`. The range starts at `start` and has length
+   * `end - start`. An empty range (with `end == start`) is valid.
+   *
+   * Example:
+   * ```dart
+   *  List<int> list = new List(3);
+   *     list.fillRange(0, 2, 1);
+   *     print(list); //  [1, 1, null]
+   * ```
+   *
+   */
+  void fillRange(int start, int end, [E fillValue]);
+
+  /**
+   * Removes the objects in the range [start] inclusive to [end] exclusive
+   * and inserts the contents of [replacement] in its place.
+   *
+   *     List<int> list = [1, 2, 3, 4, 5];
+   *     list.replaceRange(1, 4, [6, 7]);
+   *     list.join(', '); // '1, 6, 7, 5'
+   *
+   * The provided range, given by [start] and [end], must be valid.
+   * A range from [start] to [end] is valid if `0 <= start <= end <= len`, where
+   * `len` is this list's `length`. The range starts at `start` and has length
+   * `end - start`. An empty range (with `end == start`) is valid.
+   *
+   * This method does not work on fixed-length lists, even when [replacement]
+   * has the same number of elements as the replaced range. In that case use
+   * [setRange] instead.
+   */
+  void replaceRange(int start, int end, Iterable<E> replacement);
+
+  /**
+   * Returns an unmodifiable [Map] view of `this`.
+   *
+   * The map uses the indices of this list as keys and the corresponding objects
+   * as values. The `Map.keys` [Iterable] iterates the indices of this list
+   * in numerical order.
+   *
+   *     List<String> words = ['fee', 'fi', 'fo', 'fum'];
+   *     Map<int, String> map = words.asMap();
+   *     map[0] + map[1];   // 'feefi';
+   *     map.keys.toList(); // [0, 1, 2, 3]
+   */
+  Map<int, E> asMap();
+
+  /**
+  * Whether this list is equal to [other].
+  *
+  * Lists are, by default, only equal to themselves.
+  * Even if [other] is also a list, the equality comparison
+  * does not compare the elements of the two lists.
+  */
+ bool operator ==(Object other);
+}
diff --git a/sdk_nnbd/lib/core/map.dart b/sdk_nnbd/lib/core/map.dart
new file mode 100644
index 0000000..f914fe1
--- /dev/null
+++ b/sdk_nnbd/lib/core/map.dart
@@ -0,0 +1,404 @@
+// Copyright (c) 2011, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.core;
+
+/**
+ * A collection of key/value pairs, from which you retrieve a value
+ * using its associated key.
+ *
+ * There is a finite number of keys in the map,
+ * and each key has exactly one value associated with it.
+ *
+ * Maps, and their keys and values, can be iterated.
+ * The order of iteration is defined by the individual type of map.
+ * Examples:
+ *
+ * * The plain [HashMap] is unordered (no order is guaranteed),
+ * * the [LinkedHashMap] iterates in key insertion order,
+ * * and a sorted map like [SplayTreeMap] iterates the keys in sorted order.
+ *
+ * It is generally not allowed to modify the map (add or remove keys) while
+ * an operation is being performed on the map, for example in functions called
+ * during a [forEach] or [putIfAbsent] call.
+ * Modifying the map while iterating the keys or values
+ * may also break the iteration.
+ *
+ * It is generally not allowed to modify the equality of keys (and thus not
+ * their hashcode) while they are in the map. Some specialized subtypes may be
+ * more permissive, in which case they should document this behavior.
+ */
+abstract class Map<K, V> {
+  /**
+   * Creates a Map instance with the default implementation, [LinkedHashMap].
+   *
+   * This constructor is equivalent to the non-const map literal `<K,V>{}`.
+   *
+   * A `LinkedHashMap` requires the keys to implement compatible
+   * `operator==` and `hashCode`, and it allows null as a key.
+   * It iterates in key insertion order.
+   */
+  external factory Map();
+
+  /**
+   * Creates a [LinkedHashMap] instance that contains all key/value pairs of
+   * [other].
+   *
+   * The keys must all be instances of [K] and the values of [V].
+   * The [other] map itself can have any type.
+   *
+   * A `LinkedHashMap` requires the keys to implement compatible
+   * `operator==` and `hashCode`, and it allows `null` as a key.
+   * It iterates in key insertion order.
+   */
+  factory Map.from(Map other) = LinkedHashMap<K, V>.from;
+
+  /**
+   * Creates a [LinkedHashMap] with the same keys and values as [other].
+   *
+   * A `LinkedHashMap` requires the keys to implement compatible
+   * `operator==` and `hashCode`, and it allows `null` as a key.
+   * It iterates in key insertion order.
+   */
+  factory Map.of(Map<K, V> other) = LinkedHashMap<K, V>.of;
+
+  /**
+   * Creates an unmodifiable hash based map containing the entries of [other].
+   *
+   * The keys must all be instances of [K] and the values of [V].
+   * The [other] map itself can have any type.
+   *
+   * The map requires the keys to implement compatible
+   * `operator==` and `hashCode`, and it allows `null` as a key.
+   * The created map iterates keys in a fixed order,
+   * preserving the order provided by [other].
+   *
+   * The resulting map behaves like the result of [Map.from],
+   * except that the map returned by this constructor is not modifiable.
+   */
+  external factory Map.unmodifiable(Map other);
+
+  /**
+   * Creates an identity map with the default implementation, [LinkedHashMap].
+   *
+   * An identity map uses [identical] for equality and [identityHashCode]
+   * for hash codes of keys instead of the intrinsic [Object.operator==] and
+   * [Object.hashCode] of the keys.
+   *
+   * The returned map allows `null` as a key.
+   * It iterates in key insertion order.
+   */
+  factory Map.identity() = LinkedHashMap<K, V>.identity;
+
+  /**
+   * Creates a Map instance in which the keys and values are computed from the
+   * [iterable].
+   *
+   * The created map is a [LinkedHashMap].
+   * A `LinkedHashMap` requires the keys to implement compatible
+   * `operator==` and `hashCode`, and it allows null as a key.
+   * It iterates in key insertion order.
+   *
+   * For each element of the [iterable] this constructor computes a key/value
+   * pair, by applying [key] and [value] respectively.
+   *
+   * The example below creates a new Map from a List. The keys of `map` are
+   * `list` values converted to strings, and the values of the `map` are the
+   * squares of the `list` values:
+   *
+   *     List<int> list = [1, 2, 3];
+   *     Map<String, int> map = new Map.fromIterable(list,
+   *         key: (item) => item.toString(),
+   *         value: (item) => item * item);
+   *
+   *     map['1'] + map['2']; // 1 + 4
+   *     map['3'] - map['2']; // 9 - 4
+   *
+   * If no values are specified for [key] and [value] the default is the
+   * identity function.
+   *
+   * In the following example, the keys and corresponding values of `map`
+   * are `list` values:
+   *
+   *     map = new Map.fromIterable(list);
+   *     map[1] + map[2]; // 1 + 2
+   *     map[3] - map[2]; // 3 - 2
+   *
+   * The keys computed by the source [iterable] do not need to be unique. The
+   * last occurrence of a key will simply overwrite any previous value.
+   */
+  factory Map.fromIterable(Iterable iterable,
+      {K key(element), V value(element)}) = LinkedHashMap<K, V>.fromIterable;
+
+  /**
+   * Creates a Map instance associating the given [keys] to [values].
+   *
+   * The created map is a [LinkedHashMap].
+   * A `LinkedHashMap` requires the keys to implement compatible
+   * `operator==` and `hashCode`, and it allows null as a key.
+   * It iterates in key insertion order.
+   *
+   * This constructor iterates over [keys] and [values] and maps each element of
+   * [keys] to the corresponding element of [values].
+   *
+   *     List<String> letters = ['b', 'c'];
+   *     List<String> words = ['bad', 'cat'];
+   *     Map<String, String> map = new Map.fromIterables(letters, words);
+   *     map['b'] + map['c'];  // badcat
+   *
+   * If [keys] contains the same object multiple times, the last occurrence
+   * overwrites the previous value.
+   *
+   * The two [Iterable]s must have the same length.
+   */
+  factory Map.fromIterables(Iterable<K> keys, Iterable<V> values) =
+      LinkedHashMap<K, V>.fromIterables;
+
+  /**
+   * Adapts [source] to be a `Map<K2, V2>`.
+   *
+   * Any time the set would produce a key or value that is not a [K2] or [V2],
+   * the access will throw.
+   *
+   * Any time [K2] key or [V2] value is attempted added into the adapted map,
+   * the store will throw unless the key is also an instance of [K] and
+   * the value is also an instance of [V].
+   *
+   * If all accessed entries of [source] are have [K2] keys and [V2] values
+   * and if all entries added to the returned map have [K] keys and [V]] values,
+   * then the returned map can be used as a `Map<K2, V2>`.
+   */
+  static Map<K2, V2> castFrom<K, V, K2, V2>(Map<K, V> source) =>
+      CastMap<K, V, K2, V2>(source);
+
+  /**
+   * Creates a new map and adds all entries.
+   *
+   * Returns a new `Map<K, V>` where all entries of [entries]
+   * have been added in iteration order.
+   *
+   * If multiple [entries] have the same key,
+   * later occurrences overwrite the earlier ones.
+   */
+  factory Map.fromEntries(Iterable<MapEntry<K, V>> entries) =>
+      <K, V>{}..addEntries(entries);
+
+  /**
+   * Provides a view of this map as having [RK] keys and [RV] instances,
+   * if necessary.
+   *
+   * If this map is already a `Map<RK, RV>`, it is returned unchanged.
+   *
+   * If this set contains only keys of type [RK] and values of type [RV],
+   * all read operations will work correctly.
+   * If any operation exposes a non-[RK] key or non-[RV] value,
+   * the operation will throw instead.
+   *
+   * Entries added to the map must be valid for both a `Map<K, V>` and a
+   * `Map<RK, RV>`.
+   */
+  Map<RK, RV> cast<RK, RV>();
+  /**
+   * Returns true if this map contains the given [value].
+   *
+   * Returns true if any of the values in the map are equal to `value`
+   * according to the `==` operator.
+   */
+  bool containsValue(Object value);
+
+  /**
+   * Returns true if this map contains the given [key].
+   *
+   * Returns true if any of the keys in the map are equal to `key`
+   * according to the equality used by the map.
+   */
+  bool containsKey(Object key);
+
+  /**
+   * Returns the value for the given [key] or null if [key] is not in the map.
+   *
+   * Some maps allow keys to have `null` as a value.
+   * For those maps, a lookup using this operator cannot distinguish between a
+   * key not being in the map and the key having a `null` value.
+   * Methods like [containsKey] or [putIfAbsent] can be used if the distinction
+   * is important.
+   */
+  V operator [](Object key);
+
+  /**
+   * Associates the [key] with the given [value].
+   *
+   * If the key was already in the map, its associated value is changed.
+   * Otherwise the key/value pair is added to the map.
+   */
+  void operator []=(K key, V value);
+
+  /**
+   * The map entries of [this].
+   */
+  Iterable<MapEntry<K, V>> get entries;
+
+  /**
+   * Returns a new map where all entries of this map are transformed by
+   * the given [f] function.
+   */
+  Map<K2, V2> map<K2, V2>(MapEntry<K2, V2> f(K key, V value));
+
+  /**
+   * Adds all key/value pairs of [newEntries] to this map.
+   *
+   * If a key of [newEntries] is already in this map,
+   * the corresponding value is overwritten.
+   *
+   * The operation is equivalent to doing `this[entry.key] = entry.value`
+   * for each [MapEntry] of the iterable.
+   */
+  void addEntries(Iterable<MapEntry<K, V>> newEntries);
+
+  /**
+   * Updates the value for the provided [key].
+   *
+   * Returns the new value of the key.
+   *
+   * If the key is present, invokes [update] with the current value and stores
+   * the new value in the map.
+   *
+   * If the key is not present and [ifAbsent] is provided, calls [ifAbsent]
+   * and adds the key with the returned value to the map.
+   *
+   * It's an error if the key is not present and [ifAbsent] is not provided.
+   */
+  V update(K key, V update(V value), {V ifAbsent()});
+
+  /**
+   * Updates all values.
+   *
+   * Iterates over all entries in the map and updates them with the result
+   * of invoking [update].
+   */
+  void updateAll(V update(K key, V value));
+
+  /**
+   * Removes all entries of this map that satisfy the given [predicate].
+   */
+  void removeWhere(bool predicate(K key, V value));
+
+  /**
+   * Look up the value of [key], or add a new value if it isn't there.
+   *
+   * Returns the value associated to [key], if there is one.
+   * Otherwise calls [ifAbsent] to get a new value, associates [key] to
+   * that value, and then returns the new value.
+   *
+   *     Map<String, int> scores = {'Bob': 36};
+   *     for (var key in ['Bob', 'Rohan', 'Sophena']) {
+   *       scores.putIfAbsent(key, () => key.length);
+   *     }
+   *     scores['Bob'];      // 36
+   *     scores['Rohan'];    //  5
+   *     scores['Sophena'];  //  7
+   *
+   * Calling [ifAbsent] must not add or remove keys from the map.
+   */
+  V putIfAbsent(K key, V ifAbsent());
+
+  /**
+   * Adds all key/value pairs of [other] to this map.
+   *
+   * If a key of [other] is already in this map, its value is overwritten.
+   *
+   * The operation is equivalent to doing `this[key] = value` for each key
+   * and associated value in other. It iterates over [other], which must
+   * therefore not change during the iteration.
+   */
+  void addAll(Map<K, V> other);
+
+  /**
+   * Removes [key] and its associated value, if present, from the map.
+   *
+   * Returns the value associated with `key` before it was removed.
+   * Returns `null` if `key` was not in the map.
+   *
+   * Note that values can be `null` and a returned `null` value doesn't
+   * always mean that the key was absent.
+   */
+  V remove(Object key);
+
+  /**
+   * Removes all pairs from the map.
+   *
+   * After this, the map is empty.
+   */
+  void clear();
+
+  /**
+   * Applies [f] to each key/value pair of the map.
+   *
+   * Calling `f` must not add or remove keys from the map.
+   */
+  void forEach(void f(K key, V value));
+
+  /**
+   * The keys of [this].
+   *
+   * The returned iterable has efficient `length` and `contains` operations,
+   * based on [length] and [containsKey] of the map.
+   *
+   * The order of iteration is defined by the individual `Map` implementation,
+   * but must be consistent between changes to the map.
+   *
+   * Modifying the map while iterating the keys
+   * may break the iteration.
+   */
+  Iterable<K> get keys;
+
+  /**
+   * The values of [this].
+   *
+   * The values are iterated in the order of their corresponding keys.
+   * This means that iterating [keys] and [values] in parallel will
+   * provide matching pairs of keys and values.
+   *
+   * The returned iterable has an efficient `length` method based on the
+   * [length] of the map. Its [Iterable.contains] method is based on
+   * `==` comparison.
+   *
+   * Modifying the map while iterating the
+   * values may break the iteration.
+   */
+  Iterable<V> get values;
+
+  /**
+   * The number of key/value pairs in the map.
+   */
+  int get length;
+
+  /**
+   * Returns true if there is no key/value pair in the map.
+   */
+  bool get isEmpty;
+
+  /**
+   * Returns true if there is at least one key/value pair in the map.
+   */
+  bool get isNotEmpty;
+}
+
+/**
+ * A key/value pair representing an entry in a [Map].
+ */
+class MapEntry<K, V> {
+  /** The key of the entry. */
+  final K key;
+
+  /** The value associated to [key] in the map. */
+  final V value;
+
+  /** Creates an entry with [key] and [value]. */
+  const factory MapEntry(K key, V value) = MapEntry<K, V>._;
+
+  const MapEntry._(this.key, this.value);
+
+  String toString() => "MapEntry($key: $value)";
+}
diff --git a/sdk_nnbd/lib/core/null.dart b/sdk_nnbd/lib/core/null.dart
new file mode 100644
index 0000000..af7d86d
--- /dev/null
+++ b/sdk_nnbd/lib/core/null.dart
@@ -0,0 +1,24 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.core;
+
+/**
+ * The reserved word [:null:] denotes an object that is the sole instance of 
+ * this class.
+ * 
+ * It is a compile-time error for a class to attempt to extend or implement
+ * Null.
+ */
+@pragma("vm:entry-point")
+class Null {
+  factory Null._uninstantiable() {
+    throw UnsupportedError('class Null cannot be instantiated');
+  }
+
+  external int get hashCode;
+
+  /** Returns the string `"null"`. */
+  String toString() => "null";
+}
diff --git a/sdk_nnbd/lib/core/num.dart b/sdk_nnbd/lib/core/num.dart
new file mode 100644
index 0000000..e04112c
--- /dev/null
+++ b/sdk_nnbd/lib/core/num.dart
@@ -0,0 +1,493 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.core;
+
+/**
+ * An integer or floating-point number.
+ *
+ * It is a compile-time error for any type other than [int] or [double]
+ * to attempt to extend or implement num.
+ */
+abstract class num implements Comparable<num> {
+  /**
+   * Test whether this value is numerically equal to `other`.
+   *
+   * If both operands are doubles, they are equal if they have the same
+   * representation, except that:
+   *
+   *   * zero and minus zero (0.0 and -0.0) are considered equal. They
+   *     both have the numerical value zero.
+   *   * NaN is not equal to anything, including NaN. If either operand is
+   *     NaN, the result is always false.
+   *
+   * If one operand is a double and the other is an int, they are equal if
+   * the double has an integer value (finite with no fractional part) and
+   * `identical(doubleValue.toInt(), intValue)` is true.
+   *
+   * If both operands are integers, they are equal if they have the same value.
+   *
+   * Returns false if `other` is not a [num].
+   *
+   * Notice that the behavior for NaN is non-reflexive. This means that
+   * equality of double values is not a proper equality relation, as is
+   * otherwise required of `operator==`. Using NaN in, e.g., a [HashSet]
+   * will fail to work. The behavior is the standard IEEE-754 equality of
+   * doubles.
+   *
+   * If you can avoid NaN values, the remaining doubles do have a proper
+   * equality relation, and can be used safely.
+   *
+   * Use [compareTo] for a comparison that distinguishes zero and minus zero,
+   * and that considers NaN values as equal.
+   */
+  bool operator ==(Object other);
+
+  /**
+   * Returns a hash code for a numerical value.
+   *
+   * The hash code is compatible with equality. It returns the same value
+   * for an [int] and a [double] with the same numerical value, and therefore
+   * the same value for the doubles zero and minus zero.
+   *
+   * No guarantees are made about the hash code of NaN values.
+   */
+  int get hashCode;
+
+  /**
+   * Compares this to `other`.
+   *
+   * Returns a negative number if `this` is less than `other`, zero if they are
+   * equal, and a positive number if `this` is greater than `other`.
+   *
+   * The ordering represented by this method is a total ordering of [num]
+   * values. All distinct doubles are non-equal, as are all distinct integers,
+   * but integers are equal to doubles if they have the same numerical
+   * value.
+   *
+   * For doubles, the `compareTo` operation is different from the partial
+   * ordering given by [operator==], [operator<] and [operator>]. For example,
+   * IEEE doubles impose that `0.0 == -0.0` and all comparison operations on
+   * NaN return false.
+   *
+   * This function imposes a complete ordering for doubles. When using
+   * `compareTo` the following properties hold:
+   *
+   * - All NaN values are considered equal, and greater than any numeric value.
+   * - -0.0 is less than 0.0 (and the integer 0), but greater than any non-zero
+   *    negative value.
+   * - Negative infinity is less than all other values and positive infinity is
+   *   greater than all non-NaN values.
+   * - All other values are compared using their numeric value.
+   *
+   * Examples:
+   * ```
+   * print(1.compareTo(2)); // => -1
+   * print(2.compareTo(1)); // => 1
+   * print(1.compareTo(1)); // => 0
+   *
+   * // The following comparisons yield different results than the
+   * // corresponding comparison operators.
+   * print((-0.0).compareTo(0.0));  // => -1
+   * print(double.nan.compareTo(double.nan));  // => 0
+   * print(double.infinity.compareTo(double.nan)); // => -1
+   *
+   * // -0.0, and NaN comparison operators have rules imposed by the IEEE
+   * // standard.
+   * print(-0.0 == 0.0); // => true
+   * print(double.nan == double.nan);  // => false
+   * print(double.infinity < double.nan);  // => false
+   * print(double.nan < double.infinity);  // => false
+   * print(double.nan == double.infinity);  // => false
+   * ```
+   */
+  int compareTo(num other);
+
+  /** Addition operator. */
+  num operator +(num other);
+
+  /** Subtraction operator. */
+  num operator -(num other);
+
+  /** Multiplication operator. */
+  num operator *(num other);
+
+  /**
+   * Euclidean modulo operator.
+   *
+   * Returns the remainder of the Euclidean division. The Euclidean division of
+   * two integers `a` and `b` yields two integers `q` and `r` such that
+   * `a == b * q + r` and `0 <= r < b.abs()`.
+   *
+   * The Euclidean division is only defined for integers, but can be easily
+   * extended to work with doubles. In that case `r` may have a non-integer
+   * value, but it still verifies `0 <= r < |b|`.
+   *
+   * The sign of the returned value `r` is always positive.
+   *
+   * See [remainder] for the remainder of the truncating division.
+   */
+  num operator %(num other);
+
+  /** Division operator. */
+  double operator /(num other);
+
+  /**
+   * Truncating division operator.
+   *
+   * If either operand is a [double] then the result of the truncating division
+   * `a ~/ b` is equivalent to `(a / b).truncate().toInt()`.
+   *
+   * If both operands are [int]s then `a ~/ b` performs the truncating
+   * integer division.
+   */
+  int operator ~/(num other);
+
+  /** Negate operator. */
+  num operator -();
+
+  /**
+   * Returns the remainder of the truncating division of `this` by [other].
+   *
+   * The result `r` of this operation satisfies:
+   * `this == (this ~/ other) * other + r`.
+   * As a consequence the remainder `r` has the same sign as the divider `this`.
+   */
+  num remainder(num other);
+
+  /** Relational less than operator. */
+  bool operator <(num other);
+
+  /** Relational less than or equal operator. */
+  bool operator <=(num other);
+
+  /** Relational greater than operator. */
+  bool operator >(num other);
+
+  /** Relational greater than or equal operator. */
+  bool operator >=(num other);
+
+  /** True if the number is the double Not-a-Number value; otherwise, false. */
+  bool get isNaN;
+
+  /**
+   * True if the number is negative; otherwise, false.
+   *
+   * Negative numbers are those less than zero, and the double `-0.0`.
+   */
+  bool get isNegative;
+
+  /**
+   * True if the number is positive infinity or negative infinity; otherwise,
+   * false.
+   */
+  bool get isInfinite;
+
+  /**
+   * True if the number is finite; otherwise, false.
+   *
+   * The only non-finite numbers are NaN, positive infinity, and
+   * negative infinity.
+   */
+  bool get isFinite;
+
+  /** Returns the absolute value of this [num]. */
+  num abs();
+
+  /**
+   * Returns minus one, zero or plus one depending on the sign and
+   * numerical value of the number.
+   *
+   * Returns minus one if the number is less than zero,
+   * plus one if the number is greater than zero,
+   * and zero if the number is equal to zero.
+   *
+   * Returns NaN if the number is the double NaN value.
+   *
+   * Returns a number of the same type as this number.
+   * For doubles, `-0.0.sign == -0.0`.
+
+   * The result satisfies:
+   *
+   *     n == n.sign * n.abs()
+   *
+   * for all numbers `n` (except NaN, because NaN isn't `==` to itself).
+   */
+  num get sign;
+
+  /**
+   * Returns the integer closest to `this`.
+   *
+   * Rounds away from zero when there is no closest integer:
+   *  `(3.5).round() == 4` and `(-3.5).round() == -4`.
+   *
+   * If `this` is not finite (`NaN` or infinity), throws an [UnsupportedError].
+   */
+  int round();
+
+  /**
+   * Returns the greatest integer no greater than `this`.
+   *
+   * If `this` is not finite (`NaN` or infinity), throws an [UnsupportedError].
+   */
+  int floor();
+
+  /**
+   * Returns the least integer no smaller than `this`.
+   *
+   * If `this` is not finite (`NaN` or infinity), throws an [UnsupportedError].
+   */
+  int ceil();
+
+  /**
+   * Returns the integer obtained by discarding any fractional
+   * digits from `this`.
+   *
+   * If `this` is not finite (`NaN` or infinity), throws an [UnsupportedError].
+   */
+  int truncate();
+
+  /**
+   * Returns the double integer value closest to `this`.
+   *
+   * Rounds away from zero when there is no closest integer:
+   *  `(3.5).roundToDouble() == 4` and `(-3.5).roundToDouble() == -4`.
+   *
+   * If this is already an integer valued double, including `-0.0`, or it is a
+   * non-finite double value, the value is returned unmodified.
+   *
+   * For the purpose of rounding, `-0.0` is considered to be below `0.0`,
+   * and `-0.0` is therefore considered closer to negative numbers than `0.0`.
+   * This means that for a value, `d` in the range `-0.5 < d < 0.0`,
+   * the result is `-0.0`.
+   *
+   * The result is always a double.
+   * If this is a numerically large integer, the result may be an infinite
+   * double.
+   */
+  double roundToDouble();
+
+  /**
+   * Returns the greatest double integer value no greater than `this`.
+   *
+   * If this is already an integer valued double, including `-0.0`, or it is a
+   * non-finite double value, the value is returned unmodified.
+   *
+   * For the purpose of rounding, `-0.0` is considered to be below `0.0`.
+   * A number `d` in the range `0.0 < d < 1.0` will return `0.0`.
+   *
+   * The result is always a double.
+   * If this is a numerically large integer, the result may be an infinite
+   * double.
+   */
+  double floorToDouble();
+
+  /**
+   * Returns the least double integer value no smaller than `this`.
+   *
+   * If this is already an integer valued double, including `-0.0`, or it is a
+   * non-finite double value, the value is returned unmodified.
+   *
+   * For the purpose of rounding, `-0.0` is considered to be below `0.0`.
+   * A number `d` in the range `-1.0 < d < 0.0` will return `-0.0`.
+   *
+   * The result is always a double.
+   * If this is a numerically large integer, the result may be an infinite
+   * double.
+   */
+  double ceilToDouble();
+
+  /**
+   * Returns the double integer value obtained by discarding any fractional
+   * digits from the double value of `this`.
+   *
+   * If this is already an integer valued double, including `-0.0`, or it is a
+   * non-finite double value, the value is returned unmodified.
+   *
+   * For the purpose of rounding, `-0.0` is considered to be below `0.0`.
+   * A number `d` in the range `-1.0 < d < 0.0` will return `-0.0`, and
+   * in the range `0.0 < d < 1.0` it will return 0.0.
+   *
+   * The result is always a double.
+   * If this is a numerically large integer, the result may be an infinite
+   * double.
+   */
+  double truncateToDouble();
+
+  /**
+   * Returns this [num] clamped to be in the range [lowerLimit]-[upperLimit].
+   *
+   * The comparison is done using [compareTo] and therefore takes `-0.0` into
+   * account. This also implies that [double.nan] is treated as the maximal
+   * double value.
+   *
+   * The arguments [lowerLimit] and [upperLimit] must form a valid range where
+   * `lowerLimit.compareTo(upperLimit) <= 0`.
+   */
+  num clamp(num lowerLimit, num upperLimit);
+
+  /** Truncates this [num] to an integer and returns the result as an [int]. */
+  int toInt();
+
+  /**
+   * Return this [num] as a [double].
+   *
+   * If the number is not representable as a [double], an
+   * approximation is returned. For numerically large integers, the
+   * approximation may be infinite.
+   */
+  double toDouble();
+
+  /**
+   * Returns a decimal-point string-representation of `this`.
+   *
+   * Converts `this` to a [double] before computing the string representation.
+   *
+   * If the absolute value of `this` is greater or equal to `10^21` then this
+   * methods returns an exponential representation computed by
+   * `this.toStringAsExponential()`. Otherwise the result
+   * is the closest string representation with exactly [fractionDigits] digits
+   * after the decimal point. If [fractionDigits] equals 0 then the decimal
+   * point is omitted.
+   *
+   * The parameter [fractionDigits] must be an integer satisfying:
+   * `0 <= fractionDigits <= 20`.
+   *
+   * Examples:
+   *
+   *     1.toStringAsFixed(3);  // 1.000
+   *     (4321.12345678).toStringAsFixed(3);  // 4321.123
+   *     (4321.12345678).toStringAsFixed(5);  // 4321.12346
+   *     123456789012345678901.toStringAsFixed(3);  // 123456789012345683968.000
+   *     1000000000000000000000.toStringAsFixed(3); // 1e+21
+   *     5.25.toStringAsFixed(0); // 5
+   */
+  String toStringAsFixed(int fractionDigits);
+
+  /**
+   * Returns an exponential string-representation of `this`.
+   *
+   * Converts `this` to a [double] before computing the string representation.
+   *
+   * If [fractionDigits] is given then it must be an integer satisfying:
+   * `0 <= fractionDigits <= 20`. In this case the string contains exactly
+   * [fractionDigits] after the decimal point. Otherwise, without the parameter,
+   * the returned string uses the shortest number of digits that accurately
+   * represent [this].
+   *
+   * If [fractionDigits] equals 0 then the decimal point is omitted.
+   * Examples:
+   *
+   *     1.toStringAsExponential();       // 1e+0
+   *     1.toStringAsExponential(3);      // 1.000e+0
+   *     123456.toStringAsExponential();  // 1.23456e+5
+   *     123456.toStringAsExponential(3); // 1.235e+5
+   *     123.toStringAsExponential(0);    // 1e+2
+   */
+  String toStringAsExponential([int fractionDigits]);
+
+  /**
+   * Converts `this` to a double and returns a string representation with
+   * exactly [precision] significant digits.
+   *
+   * The parameter [precision] must be an integer satisfying:
+   * `1 <= precision <= 21`.
+   *
+   * Examples:
+   *
+   *     1.toStringAsPrecision(2);       // 1.0
+   *     1e15.toStringAsPrecision(3);    // 1.00e+15
+   *     1234567.toStringAsPrecision(3); // 1.23e+6
+   *     1234567.toStringAsPrecision(9); // 1234567.00
+   *     12345678901234567890.toStringAsPrecision(20); // 12345678901234567168
+   *     12345678901234567890.toStringAsPrecision(14); // 1.2345678901235e+19
+   *     0.00000012345.toStringAsPrecision(15); // 1.23450000000000e-7
+   *     0.0000012345.toStringAsPrecision(15);  // 0.00000123450000000000
+   */
+  String toStringAsPrecision(int precision);
+
+  /**
+   * Returns the shortest string that correctly represent the input number.
+   *
+   * All [double]s in the range `10^-6` (inclusive) to `10^21` (exclusive)
+   * are converted to their decimal representation with at least one digit
+   * after the decimal point. For all other doubles,
+   * except for special values like `NaN` or `Infinity`, this method returns an
+   * exponential representation (see [toStringAsExponential]).
+   *
+   * Returns `"NaN"` for [double.nan], `"Infinity"` for [double.infinity], and
+   * `"-Infinity"` for [double.negativeInfinity].
+   *
+   * An [int] is converted to a decimal representation with no decimal point.
+   *
+   * Examples:
+   *
+   *     (0.000001).toString();  // "0.000001"
+   *     (0.0000001).toString(); // "1e-7"
+   *     (111111111111111111111.0).toString();  // "111111111111111110000.0"
+   *     (100000000000000000000.0).toString();  // "100000000000000000000.0"
+   *     (1000000000000000000000.0).toString(); // "1e+21"
+   *     (1111111111111111111111.0).toString(); // "1.1111111111111111e+21"
+   *     1.toString(); // "1"
+   *     111111111111111111111.toString();  // "111111111111111110000"
+   *     100000000000000000000.toString();  // "100000000000000000000"
+   *     1000000000000000000000.toString(); // "1000000000000000000000"
+   *     1111111111111111111111.toString(); // "1111111111111111111111"
+   *     1.234e5.toString();   // 123400
+   *     1234.5e6.toString();  // 1234500000
+   *     12.345e67.toString(); // 1.2345e+68
+   *
+   * Note: the conversion may round the output if the returned string
+   * is accurate enough to uniquely identify the input-number.
+   * For example the most precise representation of the [double] `9e59` equals
+   * `"899999999999999918767229449717619953810131273674690656206848"`, but
+   * this method returns the shorter (but still uniquely identifying) `"9e59"`.
+   *
+   */
+  String toString();
+
+  /**
+   * Parses a string containing a number literal into a number.
+   *
+   * The method first tries to read the [input] as integer (similar to
+   * [int.parse] without a radix).
+   * If that fails, it tries to parse the [input] as a double (similar to
+   * [double.parse]).
+   * If that fails, too, it invokes [onError] with [input], and the result
+   * of that invocation becomes the result of calling `parse`.
+   *
+   * If no [onError] is supplied, it defaults to a function that throws a
+   * [FormatException].
+   *
+   * For any number `n`, this function satisfies
+   * `identical(n, num.parse(n.toString()))` (except when `n` is a NaN `double`
+   * with a payload).
+   *
+   * The [onError] parameter is deprecated and will be removed.
+   * Instead of `num.parse(string, (string) { ... })`,
+   * you should use `num.tryParse(string) ?? (...)`.
+   */
+  static num parse(String input, [@deprecated num onError(String input)]) {
+    num result = tryParse(input);
+    if (result != null) return result;
+    if (onError == null) throw FormatException(input);
+    return onError(input);
+  }
+
+  /**
+   * Parses a string containing a number literal into a number.
+   *
+   * Like [parse] except that this function returns `null` for invalid inputs
+   * instead of throwing.
+   */
+  static num tryParse(String input) {
+    String source = input.trim();
+    // TODO(lrn): Optimize to detect format and result type in one check.
+    return int.tryParse(source) ?? double.tryParse(source);
+  }
+
+  /** Helper functions for [parse]. */
+  static int _returnIntNull(String _) => null;
+  static double _returnDoubleNull(String _) => null;
+}
diff --git a/sdk_nnbd/lib/core/object.dart b/sdk_nnbd/lib/core/object.dart
new file mode 100644
index 0000000..505efdf
--- /dev/null
+++ b/sdk_nnbd/lib/core/object.dart
@@ -0,0 +1,115 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.core;
+
+/**
+ * The base class for all Dart objects.
+ *
+ * Because Object is the root of the Dart class hierarchy,
+ * every other Dart class is a subclass of Object.
+ *
+ * When you define a class, you should override [toString]
+ * to return a string describing an instance of that class.
+ * You might also need to define [hashCode] and [operator ==], as described in the
+ * [Implementing map
+ * keys](https://www.dartlang.org/docs/dart-up-and-running/ch03.html#implementing-map-keys)
+ * section of the [library
+ * tour](http://www.dartlang.org/docs/dart-up-and-running/contents/ch03.html).
+ */
+@pragma("vm:entry-point")
+class Object {
+  /**
+   * Creates a new [Object] instance.
+   *
+   * [Object] instances have no meaningful state, and are only useful
+   * through their identity. An [Object] instance is equal to itself
+   * only.
+   */
+  const Object();
+
+  /**
+   * The equality operator.
+   *
+   * The default behavior for all [Object]s is to return true if and
+   * only if `this` and [other] are the same object.
+   *
+   * Override this method to specify a different equality relation on
+   * a class. The overriding method must still be an equivalence relation.
+   * That is, it must be:
+   *
+   *  * Total: It must return a boolean for all arguments. It should never throw
+   *    or return `null`.
+   *
+   *  * Reflexive: For all objects `o`, `o == o` must be true.
+   *
+   *  * Symmetric: For all objects `o1` and `o2`, `o1 == o2` and `o2 == o1` must
+   *    either both be true, or both be false.
+   *
+   *  * Transitive: For all objects `o1`, `o2`, and `o3`, if `o1 == o2` and
+   *    `o2 == o3` are true, then `o1 == o3` must be true.
+   *
+   * The method should also be consistent over time,
+   * so whether two objects are equal should only change
+   * if at least one of the objects was modified.
+   *
+   * If a subclass overrides the equality operator it should override
+   * the [hashCode] method as well to maintain consistency.
+   */
+  external bool operator ==(other);
+
+  /**
+   * The hash code for this object.
+   *
+   * A hash code is a single integer which represents the state of the object
+   * that affects [operator ==] comparisons.
+   *
+   * All objects have hash codes.
+   * The default hash code represents only the identity of the object,
+   * the same way as the default [operator ==] implementation only considers objects
+   * equal if they are identical (see [identityHashCode]).
+   *
+   * If [operator ==] is overridden to use the object state instead,
+   * the hash code must also be changed to represent that state.
+   *
+   * Hash codes must be the same for objects that are equal to each other
+   * according to [operator ==].
+   * The hash code of an object should only change if the object changes
+   * in a way that affects equality.
+   * There are no further requirements for the hash codes.
+   * They need not be consistent between executions of the same program
+   * and there are no distribution guarantees.
+   *
+   * Objects that are not equal are allowed to have the same hash code,
+   * it is even technically allowed that all instances have the same hash code,
+   * but if clashes happen too often, it may reduce the efficiency of hash-based
+   * data structures like [HashSet] or [HashMap].
+   *
+   * If a subclass overrides [hashCode], it should override the
+   * [operator ==] operator as well to maintain consistency.
+   */
+  external int get hashCode;
+
+  /**
+   * Returns a string representation of this object.
+   */
+  external String toString();
+
+  /**
+   * Invoked when a non-existent method or property is accessed.
+   *
+   * Classes can override [noSuchMethod] to provide custom behavior.
+   *
+   * If a value is returned, it becomes the result of the original invocation.
+   *
+   * The default behavior is to throw a [NoSuchMethodError].
+   */
+  @pragma("vm:entry-point")
+  external dynamic noSuchMethod(Invocation invocation);
+
+  /**
+   * A representation of the runtime type of the object.
+   */
+  external Type get runtimeType;
+}
diff --git a/sdk_nnbd/lib/core/pattern.dart b/sdk_nnbd/lib/core/pattern.dart
new file mode 100644
index 0000000..6749340
--- /dev/null
+++ b/sdk_nnbd/lib/core/pattern.dart
@@ -0,0 +1,131 @@
+// Copyright (c) 2011, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.core;
+
+/**
+ * An interface for basic searches within strings.
+ */
+abstract class Pattern {
+  // NOTE: When using "start" index from the language library, call
+  // without an argument if start is zero. This allows backwards compatibility
+  // with implementations of the older interface that didn't have the start
+  // index argument.
+  /**
+   * Match this pattern against the string repeatedly.
+   *
+   * If [start] is provided, matching will start at that index.
+   *
+   * The returned iterable lazily computes all the non-overlapping matches
+   * of the pattern on the string, ordered by start index.
+   * If a user only requests the first
+   * match, this function should not compute all possible matches.
+   *
+   * The matches are found by repeatedly finding the first match
+   * of the pattern on the string, starting from the end of the previous
+   * match, and initially starting from index zero.
+   *
+   * If the pattern matches the empty string at some point, the next
+   * match is found by starting at the previous match's end plus one.
+   */
+  Iterable<Match> allMatches(String string, [int start = 0]);
+
+  /**
+   * Match this pattern against the start of `string`.
+   *
+   * If [start] is provided, it must be an integer in the range `0` ..
+   * `string.length`. In that case, this patten is tested against the
+   * string at the [start] position. That is, a [Match] is returned if the
+   * pattern can match a part of the string starting from position [start].
+   * Returns `null` if the pattern doesn't match.
+   */
+  Match matchAsPrefix(String string, [int start = 0]);
+}
+
+/**
+ * A result from searching within a string.
+ *
+ * A Match or an [Iterable] of Match objects is returned from [Pattern]
+ * matching methods.
+ *
+ * The following example finds all matches of a [RegExp] in a [String]
+ * and iterates through the returned iterable of Match objects.
+ *
+ *     RegExp exp = new RegExp(r"(\w+)");
+ *     String str = "Parse my string";
+ *     Iterable<Match> matches = exp.allMatches(str);
+ *     for (Match m in matches) {
+ *       String match = m.group(0);
+ *       print(match);
+ *     }
+ *
+ * The output of the example is:
+ *
+ *     Parse
+ *     my
+ *     string
+ *
+ * Some patterns, regular expressions in particular, may record substrings
+ * that were part of the matching. These are called _groups_ in the Match
+ * object. Some patterns may never have any groups, and their matches always
+ * have zero [groupCount].
+ */
+abstract class Match {
+  /**
+   * Returns the index in the string where the match starts.
+   */
+  int get start;
+
+  /**
+   * Returns the index in the string after the last character of the
+   * match.
+   */
+  int get end;
+
+  /**
+   * Returns the string matched by the given [group].
+   *
+   * If [group] is 0, returns the match of the pattern.
+   *
+   * The result may be `null` if the pattern didn't assign a value to it
+   * as part of this match.
+   */
+  String group(int group);
+
+  /**
+   * Returns the string matched by the given [group].
+   *
+   * If [group] is 0, returns the match of the pattern.
+   *
+   * Short alias for [Match.group].
+   */
+  String operator [](int group);
+
+  /**
+   * Returns a list of the groups with the given indices.
+   *
+   * The list contains the strings returned by [group] for each index in
+   * [groupIndices].
+   */
+  List<String> groups(List<int> groupIndices);
+
+  /**
+   * Returns the number of captured groups in the match.
+   *
+   * Some patterns may capture parts of the input that was used to
+   * compute the full match. This is the number of captured groups,
+   * which is also the maximal allowed argument to the [group] method.
+   */
+  int get groupCount;
+
+  /**
+   * The string on which this match was computed.
+   */
+  String get input;
+
+  /**
+   * The pattern used to search in [input].
+   */
+  Pattern get pattern;
+}
diff --git a/sdk_nnbd/lib/core/print.dart b/sdk_nnbd/lib/core/print.dart
new file mode 100644
index 0000000..42c7d1c
--- /dev/null
+++ b/sdk_nnbd/lib/core/print.dart
@@ -0,0 +1,15 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.core;
+
+/// Prints a string representation of the object to the console.
+void print(Object object) {
+  String line = "$object";
+  if (printToZone == null) {
+    printToConsole(line);
+  } else {
+    printToZone(line);
+  }
+}
diff --git a/sdk_nnbd/lib/core/regexp.dart b/sdk_nnbd/lib/core/regexp.dart
new file mode 100644
index 0000000..b3046cc
--- /dev/null
+++ b/sdk_nnbd/lib/core/regexp.dart
@@ -0,0 +1,189 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.core;
+
+/**
+ * A regular expression pattern.
+ *
+ * Regular expressions are [Pattern]s, and can as such be used to match strings
+ * or parts of strings.
+ *
+ * Dart regular expressions have the same syntax and semantics as
+ * JavaScript regular expressions. See
+ * <https://ecma-international.org/ecma-262/9.0/#sec-regexp-regular-expression-objects>
+ * for the specification of JavaScript regular expressions.
+ *
+ * [firstMatch] is the main implementation method that applies a regular
+ * expression to a string and returns the first [RegExpMatch]. All
+ * other methods in [RegExp] can build on it.
+ *
+ * Use [allMatches] to look for all matches of a regular expression in
+ * a string.
+ *
+ * The following example finds all matches of a regular expression in
+ * a string.
+ * ```dart
+ * RegExp exp = new RegExp(r"(\w+)");
+ * String str = "Parse my string";
+ * Iterable<RegExpMatch> matches = exp.allMatches(str);
+ * ```
+ *
+ * Note the use of a _raw string_ (a string prefixed with `r`)
+ * in the example above. Use a raw string to treat each character in a string
+ * as a literal character.
+ */
+abstract class RegExp implements Pattern {
+  /**
+   * Constructs a regular expression.
+   *
+   * Throws a [FormatException] if [source] is not valid regular
+   * expression syntax.
+   *
+   * If `multiLine` is enabled, then `^` and `$` will match the beginning and
+   * end of a _line_, in addition to matching beginning and end of input,
+   * respectively.
+   *
+   * If `caseSensitive` is disabled, then case is ignored.
+   *
+   * If `unicode` is enabled, then the pattern is treated as a Unicode
+   * pattern as described by the ECMAScript standard.
+   *
+   * If `dotAll` is enabled, then the `.` pattern will match _all_ characters,
+   * including line terminators.
+   *
+   * Example:
+   *
+   * ```dart
+   * var wordPattern = RegExp(r"(\w+)");
+   * var bracketedNumberValue = RegExp("$key: \\[\\d+\\]");
+   * ```
+   *
+   * Notice the use of a _raw string_ in the first example, and a regular
+   * string in the second. Because of the many character classes used in
+   * regular expressions, it is common to use a raw string here, unless string
+   * interpolation is required.
+   */
+  external factory RegExp(String source,
+      {bool multiLine = false,
+      bool caseSensitive = true,
+      @Since("2.4") bool unicode = false,
+      @Since("2.4") bool dotAll = false});
+
+  /**
+   * Returns a regular expression that matches [text].
+   *
+   * If [text] contains characters that are meaningful in regular expressions,
+   * the resulting regular expression will match those characters literally.
+   * If [text] contains no characters that have special meaning in a regular
+   * expression, it is returned unmodified.
+   *
+   * The characters that have special meaning in regular expressions are:
+   * `(`, `)`, `[`, `]`, `{`, `}`, `*`, `+`, `?`, `.`, `^`, `$`, `|` and `\`.
+   */
+  external static String escape(String text);
+
+  /**
+   * Searches for the first match of the regular expression
+   * in the string [input]. Returns `null` if there is no match.
+   */
+  RegExpMatch firstMatch(String input);
+
+  /**
+   * Returns an iterable of the matches of the regular expression on [input].
+   *
+   * If [start] is provided, only start looking for matches at `start`.
+   */
+  Iterable<RegExpMatch> allMatches(String input, [int start = 0]);
+
+  /**
+   * Returns whether the regular expression has a match in the string [input].
+   */
+  bool hasMatch(String input);
+
+  /**
+   * Returns the first substring match of this regular expression in [input].
+   */
+  String stringMatch(String input);
+
+  /**
+   * The source regular expression string used to create this `RegExp`.
+   */
+  String get pattern;
+
+  /**
+   * Whether this regular expression matches multiple lines.
+   *
+   * If the regexp does match multiple lines, the "^" and "$" characters
+   * match the beginning and end of lines. If not, the character match the
+   * beginning and end of the input.
+   */
+  bool get isMultiLine;
+
+  /**
+   * Whether this regular expression is case sensitive.
+   *
+   * If the regular expression is not case sensitive, it will match an input
+   * letter with a pattern letter even if the two letters are different case
+   * versions of the same letter.
+   */
+  bool get isCaseSensitive;
+
+  /**
+   * Whether this regular expression is in Unicode mode.
+   *
+   * In Unicode mode, UTF-16 surrogate pairs in the original string will be
+   * treated as a single code point and will not match separately. Otherwise,
+   * the target string will be treated purely as a sequence of individual code
+   * units and surrogates will not be treated specially.
+   *
+   * In Unicode mode, the syntax of the RegExp pattern is more restricted, but
+   * some pattern features, like Unicode property escapes, are only available in
+   * this mode.
+   */
+  @Since("2.4")
+  bool get isUnicode;
+
+  /**
+   * Whether "." in this regular expression matches line terminators.
+   *
+   * When false, the "." character matches a single character, unless that
+   * character is a line terminator. When true, then the "." character will
+   * match any single character including line terminators.
+   *
+   * This feature is distinct from [isMultiline], as they affect the behavior
+   * of different pattern characters, and so they can be used together or
+   * separately.
+   */
+  @Since("2.4")
+  bool get isDotAll;
+}
+
+/**
+ * A regular expression match.
+ *
+ * Regular expression matches are [Match]es, but also include the ability
+ * to retrieve the names for any named capture groups and to retrieve
+ * matches for named capture groups by name instead of their index.
+ */
+@Since("2.3")
+abstract class RegExpMatch implements Match {
+  /**
+   * The string matched by the group named [name].
+   *
+   * Returns the string matched by the capture group named [name], or
+   * `null` if no string was matched by that capture group as part of
+   * this match.
+   *
+   * The [name] must be the name of a named capture group in the regular
+   * expression creating this match (that is, the name must be in
+   * [groupNames]).
+   */
+  String namedGroup(String name);
+
+  /**
+   * The names of the captured groups in the match.
+   */
+  Iterable<String> get groupNames;
+}
diff --git a/sdk_nnbd/lib/core/set.dart b/sdk_nnbd/lib/core/set.dart
new file mode 100644
index 0000000..e57d974
--- /dev/null
+++ b/sdk_nnbd/lib/core/set.dart
@@ -0,0 +1,264 @@
+// Copyright (c) 2011, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.core;
+
+/**
+ * A collection of objects in which each object can occur only once.
+ *
+ * That is, for each object of the element type, the object is either considered
+ * to be in the set, or to _not_ be in the set.
+ *
+ * Set implementations may consider some elements indistinguishable. These
+ * elements are treated as being the same for any operation on the set.
+ *
+ * The default [Set] implementation, [LinkedHashSet], considers objects
+ * indistinguishable if they are equal with regard to
+ * operator [Object.==].
+ *
+ * Iterating over elements of a set may be either unordered
+ * or ordered in some way. Examples:
+ *
+ * * A [HashSet] is unordered, which means that its iteration order is
+ *   unspecified,
+ * * [LinkedHashSet] iterates in the insertion order of its elements, and
+ * * a sorted set like [SplayTreeSet] iterates the elements in sorted order.
+ *
+ * It is generally not allowed to modify the set (add or remove elements) while
+ * an operation on the set is being performed, for example during a call to
+ * [forEach] or [containsAll]. Nor is it allowed to modify the set while
+ * iterating either the set itself or any [Iterable] that is backed by the set,
+ * such as the ones returned by methods like [where] and [map].
+ *
+ * It is generally not allowed to modify the equality of elements (and thus not
+ * their hashcode) while they are in the set. Some specialized subtypes may be
+ * more permissive, in which case they should document this behavior.
+ */
+abstract class Set<E> extends EfficientLengthIterable<E> {
+  /**
+   * Creates an empty [Set].
+   *
+   * The created [Set] is a plain [LinkedHashSet].
+   * As such, it considers elements that are equal (using [operator ==]) to be
+   * indistinguishable, and requires them to have a compatible
+   * [Object.hashCode] implementation.
+   *
+   * The set is equivalent to one created by `new LinkedHashSet<E>()`.
+   */
+  factory Set() = LinkedHashSet<E>;
+
+  /**
+   * Creates an empty identity [Set].
+   *
+   * The created [Set] is a [LinkedHashSet] that uses identity as equality
+   * relation.
+   *
+   * The set is equivalent to one created by `new LinkedHashSet<E>.identity()`.
+   */
+  factory Set.identity() = LinkedHashSet<E>.identity;
+
+  /**
+   * Creates a [Set] that contains all [elements].
+   *
+   * All the [elements] should be instances of [E].
+   * The `elements` iterable itself can have any type,
+   * so this constructor can be used to down-cast a `Set`, for example as:
+   *
+   *     Set<SuperType> superSet = ...;
+   *     Set<SubType> subSet =
+   *         new Set<SubType>.from(superSet.where((e) => e is SubType));
+   *
+   * The created [Set] is a [LinkedHashSet]. As such, it considers elements that
+   * are equal (using [operator ==]) to be indistinguishable, and requires them to
+   * have a compatible [Object.hashCode] implementation.
+   *
+   * The set is equivalent to one created by
+   * `new LinkedHashSet<E>.from(elements)`.
+   */
+  factory Set.from(Iterable elements) = LinkedHashSet<E>.from;
+
+  /**
+   * Creates a [Set] from [elements].
+   *
+   * The created [Set] is a [LinkedHashSet]. As such, it considers elements that
+   * are equal (using [operator ==]) to be indistinguishable, and requires them to
+   * have a compatible [Object.hashCode] implementation.
+   *
+   * The set is equivalent to one created by
+   * `new LinkedHashSet<E>.of(elements)`.
+   */
+  factory Set.of(Iterable<E> elements) = LinkedHashSet<E>.of;
+
+  /**
+   * Adapts [source] to be a `Set<T>`.
+   *
+   * If [newSet] is provided, it is used to create the new sets returned
+   * by [toSet], [union], and is also used for [intersection] and [difference].
+   * If [newSet] is omitted, it defaults to creating a new set using the
+   * default [Set] constructor, and [intersection] and [difference]
+   * returns an adapted version of calling the same method on the source.
+   *
+   * Any time the set would produce an element that is not a [T],
+   * the element access will throw.
+   *
+   * Any time a [T] value is attempted added into the adapted set,
+   * the store will throw unless the value is also an instance of [S].
+   *
+   * If all accessed elements of [source] are actually instances of [T],
+   * and if all elements added to the returned set are actually instance
+   * of [S],
+   * then the returned set can be used as a `Set<T>`.
+   */
+  static Set<T> castFrom<S, T>(Set<S> source, {Set<R> Function<R>() newSet}) =>
+      CastSet<S, T>(source, newSet);
+
+  /**
+   * Provides a view of this set as a set of [R] instances.
+   *
+   * If this set contains only instances of [R], all read operations
+   * will work correctly. If any operation tries to access an element
+   * that is not an instance of [R], the access will throw instead.
+   *
+   * Elements added to the set (e.g., by using [add] or [addAll])
+   * must be instance of [R] to be valid arguments to the adding function,
+   * and they must be instances of [E] as well to be accepted by
+   * this set as well.
+   */
+  Set<R> cast<R>();
+  /**
+   * Provides an iterator that iterates over the elements of this set.
+   *
+   * The order of iteration is defined by the individual `Set` implementation,
+   * but must be consistent between changes to the set.
+   */
+  Iterator<E> get iterator;
+
+  /**
+   * Returns true if [value] is in the set.
+   */
+  bool contains(Object value);
+
+  /**
+   * Adds [value] to the set.
+   *
+   * Returns `true` if [value] (or an equal value) was not yet in the set.
+   * Otherwise returns `false` and the set is not changed.
+   *
+   * Example:
+   *
+   *     var set = new Set();
+   *     var time1 = new DateTime.fromMillisecondsSinceEpoch(0);
+   *     var time2 = new DateTime.fromMillisecondsSinceEpoch(0);
+   *     // time1 and time2 are equal, but not identical.
+   *     Expect.isTrue(time1 == time2);
+   *     Expect.isFalse(identical(time1, time2));
+   *     set.add(time1);  // => true.
+   *     // A value equal to time2 exists already in the set, and the call to
+   *     // add doesn't change the set.
+   *     set.add(time2);  // => false.
+   *     Expect.isTrue(set.length == 1);
+   *     Expect.isTrue(identical(time1, set.first));
+   */
+  bool add(E value);
+
+  /**
+   * Adds all [elements] to this Set.
+   *
+   * Equivalent to adding each element in [elements] using [add],
+   * but some collections may be able to optimize it.
+   */
+  void addAll(Iterable<E> elements);
+
+  /**
+   * Removes [value] from the set. Returns true if [value] was
+   * in the set. Returns false otherwise. The method has no effect
+   * if [value] value was not in the set.
+   */
+  bool remove(Object value);
+
+  /**
+   * If an object equal to [object] is in the set, return it.
+   *
+   * Checks whether [object] is in the set, like [contains], and if so,
+   * returns the object in the set, otherwise returns `null`.
+   *
+   * If the equality relation used by the set is not identity,
+   * then the returned object may not be *identical* to [object].
+   * Some set implementations may not be able to implement this method.
+   * If the [contains] method is computed,
+   * rather than being based on an actual object instance,
+   * then there may not be a specific object instance representing the
+   * set element.
+   */
+  E lookup(Object object);
+
+  /**
+   * Removes each element of [elements] from this set.
+   */
+  void removeAll(Iterable<Object> elements);
+
+  /**
+   * Removes all elements of this set that are not elements in [elements].
+   *
+   * Checks for each element of [elements] whether there is an element in this
+   * set that is equal to it (according to `this.contains`), and if so, the
+   * equal element in this set is retained, and elements that are not equal
+   * to any element in `elements` are removed.
+   */
+  void retainAll(Iterable<Object> elements);
+
+  /**
+   * Removes all elements of this set that satisfy [test].
+   */
+  void removeWhere(bool test(E element));
+
+  /**
+   * Removes all elements of this set that fail to satisfy [test].
+   */
+  void retainWhere(bool test(E element));
+
+  /**
+   * Returns whether this Set contains all the elements of [other].
+   */
+  bool containsAll(Iterable<Object> other);
+
+  /**
+   * Returns a new set which is the intersection between this set and [other].
+   *
+   * That is, the returned set contains all the elements of this [Set] that
+   * are also elements of [other] according to `other.contains`.
+   */
+  Set<E> intersection(Set<Object> other);
+
+  /**
+   * Returns a new set which contains all the elements of this set and [other].
+   *
+   * That is, the returned set contains all the elements of this [Set] and
+   * all the elements of [other].
+   */
+  Set<E> union(Set<E> other);
+
+  /**
+   * Returns a new set with the elements of this that are not in [other].
+   *
+   * That is, the returned set contains all the elements of this [Set] that
+   * are not elements of [other] according to `other.contains`.
+   */
+  Set<E> difference(Set<Object> other);
+
+  /**
+   * Removes all elements in the set.
+   */
+  void clear();
+
+  /* Creates a [Set] with the same elements and behavior as this `Set`.
+   *
+   * The returned set behaves the same as this set
+   * with regard to adding and removing elements.
+   * It initially contains the same elements.
+   * If this set specifies an ordering of the elements,
+   * the returned set will have the same order.
+   */
+  Set<E> toSet();
+}
diff --git a/sdk_nnbd/lib/core/sink.dart b/sdk_nnbd/lib/core/sink.dart
new file mode 100644
index 0000000..c79214b
--- /dev/null
+++ b/sdk_nnbd/lib/core/sink.dart
@@ -0,0 +1,31 @@
+// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.core;
+
+/**
+ * A generic destination for data.
+ *
+ * Multiple data values can be put into a sink, and when no more data is
+ * available, the sink should be closed.
+ *
+ * This is a generic interface that other data receivers can implement.
+ */
+abstract class Sink<T> {
+  /**
+   * Adds [data] to the sink.
+   *
+   * Must not be called after a call to [close].
+   */
+  void add(T data);
+
+  /**
+   * Closes the sink.
+   *
+   * The [add] method must not be called after this method.
+   *
+   * Calling this method more than once is allowed, but does nothing.
+   */
+  void close();
+}
diff --git a/sdk_nnbd/lib/core/stacktrace.dart b/sdk_nnbd/lib/core/stacktrace.dart
new file mode 100644
index 0000000..2eb1493
--- /dev/null
+++ b/sdk_nnbd/lib/core/stacktrace.dart
@@ -0,0 +1,60 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.core;
+
+/**
+ * An interface implemented by all stack trace objects.
+ *
+ * A [StackTrace] is intended to convey information to the user about the call
+ * sequence that triggered an exception.
+ *
+ * These objects are created by the runtime, it is not possible to create
+ * them programmatically.
+ */
+abstract class StackTrace {
+  StackTrace(); // In case existing classes extend StackTrace.
+
+  /**
+   * Create a `StackTrace` object from [stackTraceString].
+   *
+   * The created stack trace will have a `toString` method returning
+   * `stackTraceString`.
+   *
+   * The `stackTraceString` can be a string returned by some other
+   * stack trace, or it can be any string at all.
+   * If the string doesn't look like a stack trace, code that interprets
+   * stack traces is likely to fail, so fake stack traces should be used
+   * with care.
+   */
+  factory StackTrace.fromString(String stackTraceString) = _StringStackTrace;
+
+  /**
+   * Returns a representation of the current stack trace.
+   *
+   * This is similar to what can be achieved by doing:
+   *
+   *     try { throw 0; } catch (_, stack) { return stack; }
+   *
+   * The getter achieves this without throwing, except on platforms that
+   * have no other way to get a stack trace.
+   */
+  external static StackTrace get current;
+
+  /**
+   * Returns a [String] representation of the stack trace.
+   *
+   * The string represents the full stack trace starting from
+   * the point where a throw occurred to the top of the current call sequence.
+   *
+   * The exact format of the string representation is not final.
+   */
+  String toString();
+}
+
+class _StringStackTrace implements StackTrace {
+  final String _stackTrace;
+  _StringStackTrace(this._stackTrace);
+  String toString() => _stackTrace;
+}
diff --git a/sdk_nnbd/lib/core/stopwatch.dart b/sdk_nnbd/lib/core/stopwatch.dart
new file mode 100644
index 0000000..45d71ca
--- /dev/null
+++ b/sdk_nnbd/lib/core/stopwatch.dart
@@ -0,0 +1,123 @@
+// Copyright (c) 2011, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.core;
+
+/**
+ * A simple stopwatch interface to measure elapsed time.
+ */
+class Stopwatch {
+  /**
+   * Cached frequency of the system in Hz (ticks per second).
+   *
+   * Must be initialized in [_initTicker];
+   */
+  static int _frequency;
+
+  // The _start and _stop fields capture the time when [start] and [stop]
+  // are called respectively.
+  // If _stop is null, the stopwatch is running.
+  int _start = 0;
+  int _stop = 0;
+
+  /**
+   * Creates a [Stopwatch] in stopped state with a zero elapsed count.
+   *
+   * The following example shows how to start a [Stopwatch]
+   * immediately after allocation.
+   * ```
+   * var stopwatch = new Stopwatch()..start();
+   * ```
+   */
+  Stopwatch() {
+    if (_frequency == null) _initTicker();
+  }
+
+  /**
+   * Frequency of the elapsed counter in Hz.
+   */
+  int get frequency => _frequency;
+
+  /**
+   * Starts the [Stopwatch].
+   *
+   * The [elapsed] count is increasing monotonically. If the [Stopwatch] has
+   * been stopped, then calling start again restarts it without resetting the
+   * [elapsed] count.
+   *
+   * If the [Stopwatch] is currently running, then calling start does nothing.
+   */
+  void start() {
+    if (_stop != null) {
+      // (Re)start this stopwatch.
+      // Don't count the time while the stopwatch has been stopped.
+      _start += _now() - _stop;
+      _stop = null;
+    }
+  }
+
+  /**
+   * Stops the [Stopwatch].
+   *
+   * The [elapsedTicks] count stops increasing after this call. If the
+   * [Stopwatch] is currently not running, then calling this method has no
+   * effect.
+   */
+  void stop() {
+    _stop ??= _now();
+  }
+
+  /**
+   * Resets the [elapsed] count to zero.
+   *
+   * This method does not stop or start the [Stopwatch].
+   */
+  void reset() {
+    _start = _stop ?? _now();
+  }
+
+  /**
+   * The elapsed number of clock ticks since calling [start] while the
+   * [Stopwatch] is running.
+   *
+   * This is the elapsed number of clock ticks between calling [start] and
+   * calling [stop].
+   *
+   * Is 0 if the [Stopwatch] has never been started.
+   *
+   * The elapsed number of clock ticks increases by [frequency] every second.
+   */
+  int get elapsedTicks {
+    return (_stop ?? _now()) - _start;
+  }
+
+  /**
+   * The [elapsedTicks] counter converted to a [Duration].
+   */
+  Duration get elapsed {
+    return Duration(microseconds: elapsedMicroseconds);
+  }
+
+  /**
+   * The [elapsedTicks] counter converted to microseconds.
+   */
+  external int get elapsedMicroseconds;
+
+  /**
+   * The [elapsedTicks] counter converted to milliseconds.
+   */
+  external int get elapsedMilliseconds;
+
+  /**
+   * Whether the [Stopwatch] is currently running.
+   */
+  bool get isRunning => _stop == null;
+
+  /**
+   * Initializes the time-measuring system. *Must* initialize the [_frequency]
+   * variable.
+   */
+  external static void _initTicker();
+  external static int _now();
+}
diff --git a/sdk_nnbd/lib/core/string.dart b/sdk_nnbd/lib/core/string.dart
new file mode 100644
index 0000000..c611bd5
--- /dev/null
+++ b/sdk_nnbd/lib/core/string.dart
@@ -0,0 +1,829 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.core;
+
+/**
+ * A sequence of UTF-16 code units.
+ *
+ * Strings are mainly used to represent text. A character may be represented by
+ * multiple code points, each code point consisting of one or two code
+ * units. For example the Papua New Guinea flag character requires four code
+ * units to represent two code points, but should be treated like a single
+ * character: "🇵🇬". Platforms that do not support the flag character may show
+ * the letters "PG" instead. If the code points are swapped, it instead becomes
+ * the Guadeloupe flag "🇬🇵" ("GP").
+ *
+ * A string can be either single or multiline. Single line strings are
+ * written using matching single or double quotes, and multiline strings are
+ * written using triple quotes. The following are all valid Dart strings:
+ *
+ *     'Single quotes';
+ *     "Double quotes";
+ *     'Double quotes in "single" quotes';
+ *     "Single quotes in 'double' quotes";
+ *
+ *     '''A
+ *     multiline
+ *     string''';
+ *
+ *     """
+ *     Another
+ *     multiline
+ *     string""";
+ *
+ * Strings are immutable. Although you cannot change a string, you can perform
+ * an operation on a string and assign the result to a new string:
+ *
+ *     var string = 'Dart is fun';
+ *     var newString = string.substring(0, 5);
+ *
+ * You can use the plus (`+`) operator to concatenate strings:
+ *
+ *     'Dart ' + 'is ' + 'fun!'; // 'Dart is fun!'
+ *
+ * You can also use adjacent string literals for concatenation:
+ *
+ *     'Dart ' 'is ' 'fun!';    // 'Dart is fun!'
+ *
+ * You can use `${}` to interpolate the value of Dart expressions
+ * within strings. The curly braces can be omitted when evaluating identifiers:
+ *
+ *     string = 'dartlang';
+ *     '$string has ${string.length} letters'; // 'dartlang has 8 letters'
+ *
+ * A string is represented by a sequence of Unicode UTF-16 code units
+ * accessible through the [codeUnitAt] or the [codeUnits] members:
+ *
+ *     string = 'Dart';
+ *     string.codeUnitAt(0); // 68
+ *     string.codeUnits;     // [68, 97, 114, 116]
+ *
+ * The string representation of code units is accessible through the index
+ * operator:
+ *
+ *     string[0];            // 'D'
+ *
+ * The characters of a string are encoded in UTF-16. Decoding UTF-16, which
+ * combines surrogate pairs, yields Unicode code points. Following a similar
+ * terminology to Go, we use the name 'rune' for an integer representing a
+ * Unicode code point. Use the [runes] property to get the runes of a string:
+ *
+ *     string.runes.toList(); // [68, 97, 114, 116]
+ *
+ * For a character outside the Basic Multilingual Plane (plane 0) that is
+ * composed of a surrogate pair, [runes] combines the pair and returns a
+ * single integer.  For example, the Unicode character for a
+ * musical G-clef ('𝄞') with rune value 0x1D11E consists of a UTF-16 surrogate
+ * pair: `0xD834` and `0xDD1E`. Using [codeUnits] returns the surrogate pair,
+ * and using `runes` returns their combined value:
+ *
+ *     var clef = '\u{1D11E}';
+ *     clef.codeUnits;         // [0xD834, 0xDD1E]
+ *     clef.runes.toList();    // [0x1D11E]
+ *
+ * The String class can not be extended or implemented. Attempting to do so
+ * yields a compile-time error.
+ *
+ * ## Other resources
+ *
+ * See [StringBuffer] to efficiently build a string incrementally. See
+ * [RegExp] to work with regular expressions.
+ *
+ * Also see:
+ *
+ * * [Dart Cookbook](https://www.dartlang.org/docs/cookbook/#strings)
+ *   for String examples and recipes.
+ * * [Dart Up and Running](https://www.dartlang.org/docs/dart-up-and-running/ch03.html#strings-and-regular-expressions)
+ */
+abstract class String implements Comparable<String>, Pattern {
+  /**
+   * Allocates a new String for the specified [charCodes].
+   *
+   * The [charCodes] can be UTF-16 code units or runes. If a char-code value is
+   * 16-bit, it is copied verbatim:
+   *
+   *     new String.fromCharCodes([68]); // 'D'
+   *
+   * If a char-code value is greater than 16-bits, it is decomposed into a
+   * surrogate pair:
+   *
+   *     var clef = new String.fromCharCodes([0x1D11E]);
+   *     clef.codeUnitAt(0); // 0xD834
+   *     clef.codeUnitAt(1); // 0xDD1E
+   *
+   * If [start] and [end] is provided, only the values of [charCodes]
+   * at positions from `start` to, but not including, `end`, are used.
+   * The `start` and `end` values must satisfy
+   * `0 <= start <= end <= charCodes.length`.
+   */
+  external factory String.fromCharCodes(Iterable<int> charCodes,
+      [int start = 0, int end]);
+
+  /**
+   * Allocates a new String for the specified [charCode].
+   *
+   * If the [charCode] can be represented by a single UTF-16 code unit, the new
+   * string contains a single code unit. Otherwise, the [length] is 2 and
+   * the code units form a surrogate pair. See documentation for
+   * [fromCharCodes].
+   *
+   * Creating a String with half of a surrogate pair is allowed.
+   */
+  external factory String.fromCharCode(int charCode);
+
+  /**
+   * Returns the string value of the environment declaration [name].
+   *
+   * Environment declarations are provided by the surrounding system compiling
+   * or running the Dart program. Declarations map a string key to a string
+   * value.
+   *
+   * If [name] is not declared in the environment, the result is instead
+   * [defaultValue].
+   *
+   * Example of getting a value:
+   *
+   *     const String.fromEnvironment("defaultFloo", defaultValue: "no floo")
+   *
+   * Example of checking whether a declaration is there at all:
+   *
+   *     var isDeclared = const String.fromEnvironment("maybeDeclared") != null;
+   */
+  // The .fromEnvironment() constructors are special in that we do not want
+  // users to call them using "new". We prohibit that by giving them bodies
+  // that throw, even though const constructors are not allowed to have bodies.
+  // Disable those static errors.
+  //ignore: const_constructor_with_body
+  //ignore: const_factory
+  external const factory String.fromEnvironment(String name,
+      {String defaultValue});
+
+  /**
+   * Gets the character (as a single-code-unit [String]) at the given [index].
+   *
+   * The returned string represents exactly one UTF-16 code unit, which may be
+   * half of a surrogate pair. A single member of a surrogate pair is an
+   * invalid UTF-16 string:
+   *
+   *     var clef = '\u{1D11E}';
+   *     // These represent invalid UTF-16 strings.
+   *     clef[0].codeUnits;      // [0xD834]
+   *     clef[1].codeUnits;      // [0xDD1E]
+   *
+   * This method is equivalent to
+   * `new String.fromCharCode(this.codeUnitAt(index))`.
+   */
+  String operator [](int index);
+
+  /**
+   * Returns the 16-bit UTF-16 code unit at the given [index].
+   */
+  int codeUnitAt(int index);
+
+  /**
+   * The length of the string.
+   *
+   * Returns the number of UTF-16 code units in this string. The number
+   * of [runes] might be fewer, if the string contains characters outside
+   * the Basic Multilingual Plane (plane 0):
+   *
+   *     'Dart'.length;          // 4
+   *     'Dart'.runes.length;    // 4
+   *
+   *     var clef = '\u{1D11E}';
+   *     clef.length;            // 2
+   *     clef.runes.length;      // 1
+   */
+  int get length;
+
+  /**
+   * Returns a hash code derived from the code units of the string.
+   *
+   * This is compatible with [operator ==]. Strings with the same sequence
+   * of code units have the same hash code.
+   */
+  int get hashCode;
+
+  /**
+   * Returns true if other is a `String` with the same sequence of code units.
+   *
+   * This method compares each individual code unit of the strings.
+   * It does not check for Unicode equivalence.
+   * For example, both the following strings represent the string 'Amélie',
+   * but due to their different encoding, are not equal:
+   *
+   *     'Am\xe9lie' == 'Ame\u{301}lie'; // false
+   *
+   * The first string encodes 'é' as a single unicode code unit (also
+   * a single rune), whereas the second string encodes it as 'e' with the
+   * combining accent character '◌́'.
+   */
+  bool operator ==(Object other);
+
+  /**
+   * Compares this string to [other].
+   *
+   * Returns a negative value if `this` is ordered before `other`,
+   * a positive value if `this` is ordered after `other`,
+   * or zero if `this` and `other` are equivalent.
+   *
+   * The ordering is the same as the ordering of the code points at the first
+   * position where the two strings differ.
+   * If one string is a prefix of the other,
+   * then the shorter string is ordered before the longer string.
+   * If the strings have exactly the same content, they are equivalent with
+   * regard to the ordering.
+   * Ordering does not check for Unicode equivalence.
+   * The comparison is case sensitive.
+   */
+  int compareTo(String other);
+
+  /**
+   * Returns true if this string ends with [other]. For example:
+   *
+   *     'Dart'.endsWith('t'); // true
+   */
+  bool endsWith(String other);
+
+  /**
+   * Returns true if this string starts with a match of [pattern].
+   *
+   *     var string = 'Dart';
+   *     string.startsWith('D');                       // true
+   *     string.startsWith(new RegExp(r'[A-Z][a-z]')); // true
+   *
+   * If [index] is provided, this method checks if the substring starting
+   * at that index starts with a match of [pattern]:
+   *
+   *     string.startsWith('art', 1);                  // true
+   *     string.startsWith(new RegExp(r'\w{3}'));      // true
+   *
+   * [index] must not be negative or greater than [length].
+   *
+   * A [RegExp] containing '^' does not match if the [index] is greater than
+   * zero. The pattern works on the string as a whole, and does not extract
+   * a substring starting at [index] first:
+   *
+   *     string.startsWith(new RegExp(r'^art'), 1);    // false
+   *     string.startsWith(new RegExp(r'art'), 1);     // true
+   */
+  bool startsWith(Pattern pattern, [int index = 0]);
+
+  /**
+   * Returns the position of the first match of [pattern] in this string,
+   * starting at [start], inclusive:
+   *
+   *     var string = 'Dartisans';
+   *     string.indexOf('art');                     // 1
+   *     string.indexOf(new RegExp(r'[A-Z][a-z]')); // 0
+   *
+   * Returns -1 if no match is found:
+   *
+   *     string.indexOf(new RegExp(r'dart'));       // -1
+   *
+   * [start] must be non-negative and not greater than [length].
+   */
+  int indexOf(Pattern pattern, [int start]);
+
+  /**
+   * Returns the position of the last match [pattern] in this string, searching
+   * backward starting at [start], inclusive:
+   *
+   *     var string = 'Dartisans';
+   *     string.lastIndexOf('a');                    // 6
+   *     string.lastIndexOf(new RegExp(r'a(r|n)'));  // 6
+   *
+   * Returns -1 if [pattern] could not be found in this string.
+   *
+   *     string.lastIndexOf(new RegExp(r'DART'));    // -1
+   *
+   * The [start] must be non-negative and not greater than [length].
+   */
+  int lastIndexOf(Pattern pattern, [int start]);
+
+  /**
+   * Returns true if this string is empty.
+   */
+  bool get isEmpty;
+
+  /**
+   * Returns true if this string is not empty.
+   */
+  bool get isNotEmpty;
+
+  /**
+   * Creates a new string by concatenating this string with [other].
+   *
+   *     'dart' + 'lang'; // 'dartlang'
+   */
+  String operator +(String other);
+
+  /**
+   * Returns the substring of this string that extends from [startIndex],
+   * inclusive, to [endIndex], exclusive.
+   *
+   *     var string = 'dartlang';
+   *     string.substring(1);    // 'artlang'
+   *     string.substring(1, 4); // 'art'
+   */
+  String substring(int startIndex, [int endIndex]);
+
+  /**
+   * Returns the string without any leading and trailing whitespace.
+   *
+   * If the string contains leading or trailing whitespace, a new string with no
+   * leading and no trailing whitespace is returned:
+   * ```dart
+   * '\tDart is fun\n'.trim(); // 'Dart is fun'
+   * ```
+   * Otherwise, the original string itself is returned:
+   * ```dart
+   * var str1 = 'Dart';
+   * var str2 = str1.trim();
+   * identical(str1, str2);    // true
+   * ```
+   * Whitespace is defined by the Unicode White_Space property (as defined in
+   * version 6.2 or later) and the BOM character, 0xFEFF.
+   *
+   * Here is the list of trimmed characters according to Unicode version 6.3:
+   * ```
+   *     0009..000D    ; White_Space # Cc   <control-0009>..<control-000D>
+   *     0020          ; White_Space # Zs   SPACE
+   *     0085          ; White_Space # Cc   <control-0085>
+   *     00A0          ; White_Space # Zs   NO-BREAK SPACE
+   *     1680          ; White_Space # Zs   OGHAM SPACE MARK
+   *     2000..200A    ; White_Space # Zs   EN QUAD..HAIR SPACE
+   *     2028          ; White_Space # Zl   LINE SEPARATOR
+   *     2029          ; White_Space # Zp   PARAGRAPH SEPARATOR
+   *     202F          ; White_Space # Zs   NARROW NO-BREAK SPACE
+   *     205F          ; White_Space # Zs   MEDIUM MATHEMATICAL SPACE
+   *     3000          ; White_Space # Zs   IDEOGRAPHIC SPACE
+   *
+   *     FEFF          ; BOM                ZERO WIDTH NO_BREAK SPACE
+   * ```
+   * Some later versions of Unicode do not include U+0085 as a whitespace
+   * character. Whether it is trimmed depends on the Unicode version
+   * used by the system.
+   */
+  String trim();
+
+  /**
+   * Returns the string without any leading whitespace.
+   *
+   * As [trim], but only removes leading whitespace.
+   */
+  String trimLeft();
+
+  /**
+   * Returns the string without any trailing whitespace.
+   *
+   * As [trim], but only removes trailing whitespace.
+   */
+  String trimRight();
+
+  /**
+   * Creates a new string by concatenating this string with itself a number
+   * of times.
+   *
+   * The result of `str * n` is equivalent to
+   * `str + str + ...`(n times)`... + str`.
+   *
+   * Returns an empty string if [times] is zero or negative.
+   */
+  String operator *(int times);
+
+  /**
+   * Pads this string on the left if it is shorter than [width].
+   *
+   * Return a new string that prepends [padding] onto this string
+   * one time for each position the length is less than [width].
+   *
+   * If [width] is already smaller than or equal to `this.length`,
+   * no padding is added. A negative `width` is treated as zero.
+   *
+   * If [padding] has length different from 1, the result will not
+   * have length `width`. This may be useful for cases where the
+   * padding is a longer string representing a single character, like
+   * `"&nbsp;"` or `"\u{10002}`".
+   * In that case, the user should make sure that `this.length` is
+   * the correct measure of the strings length.
+   */
+  String padLeft(int width, [String padding = ' ']);
+
+  /**
+   * Pads this string on the right if it is shorter than [width].
+   *
+   * Return a new string that appends [padding] after this string
+   * one time for each position the length is less than [width].
+   *
+   * If [width] is already smaller than or equal to `this.length`,
+   * no padding is added. A negative `width` is treated as zero.
+   *
+   * If [padding] has length different from 1, the result will not
+   * have length `width`. This may be useful for cases where the
+   * padding is a longer string representing a single character, like
+   * `"&nbsp;"` or `"\u{10002}`".
+   * In that case, the user should make sure that `this.length` is
+   * the correct measure of the strings length.
+   */
+  String padRight(int width, [String padding = ' ']);
+
+  /**
+   * Returns true if this string contains a match of [other]:
+   *
+   *     var string = 'Dart strings';
+   *     string.contains('D');                     // true
+   *     string.contains(new RegExp(r'[A-Z]'));    // true
+   *
+   * If [startIndex] is provided, this method matches only at or after that
+   * index:
+   *
+   *     string.contains('X', 1);                  // false
+   *     string.contains(new RegExp(r'[A-Z]'), 1); // false
+   *
+   * [startIndex] must not be negative or greater than [length].
+   */
+  bool contains(Pattern other, [int startIndex = 0]);
+
+  /**
+   * Returns a new string in which the first occurrence of [from] in this string
+   * is replaced with [to], starting from [startIndex]:
+   *
+   *     '0.0001'.replaceFirst(new RegExp(r'0'), ''); // '.0001'
+   *     '0.0001'.replaceFirst(new RegExp(r'0'), '7', 1); // '0.7001'
+   */
+  String replaceFirst(Pattern from, String to, [int startIndex = 0]);
+
+  /**
+   * Replace the first occurrence of [from] in this string.
+   *
+   * Returns a new string, which is this string
+   * except that the first match of [from], starting from [startIndex],
+   * is replaced by the result of calling [replace] with the match object.
+   *
+   * The optional [startIndex] is by default set to 0. If provided, it must be
+   * an integer in the range `[0 .. len]`, where `len` is this string's length.
+   */
+  String replaceFirstMapped(Pattern from, String replace(Match match),
+      [int startIndex = 0]);
+
+  /**
+   * Replaces all substrings that match [from] with [replace].
+   *
+   * Returns a new string in which the non-overlapping substrings matching
+   * [from] (the ones iterated by `from.allMatches(thisString)`) are replaced
+   * by the literal string [replace].
+   *
+   *     'resume'.replaceAll(new RegExp(r'e'), 'é'); // 'résumé'
+   *
+   * Notice that the [replace] string is not interpreted. If the replacement
+   * depends on the match (for example on a [RegExp]'s capture groups), use
+   * the [replaceAllMapped] method instead.
+   */
+  String replaceAll(Pattern from, String replace);
+
+  /**
+   * Replace all substrings that match [from] by a string computed from the
+   * match.
+   *
+   * Returns a new string in which the non-overlapping substrings that match
+   * [from] (the ones iterated by `from.allMatches(thisString)`) are replaced
+   * by the result of calling [replace] on the corresponding [Match] object.
+   *
+   * This can be used to replace matches with new content that depends on the
+   * match, unlike [replaceAll] where the replacement string is always the same.
+   *
+   * The [replace] function is called with the [Match] generated
+   * by the pattern, and its result is used as replacement.
+   *
+   * The function defined below converts each word in a string to simplified
+   * 'pig latin' using [replaceAllMapped]:
+   *
+   *     pigLatin(String words) => words.replaceAllMapped(
+   *         new RegExp(r'\b(\w*?)([aeiou]\w*)', caseSensitive: false),
+   *         (Match m) => "${m[2]}${m[1]}${m[1].isEmpty ? 'way' : 'ay'}");
+   *
+   *     pigLatin('I have a secret now!'); // 'Iway avehay away ecretsay ownay!'
+   */
+  String replaceAllMapped(Pattern from, String replace(Match match));
+
+  /**
+   * Replaces the substring from [start] to [end] with [replacement].
+   *
+   * Returns a new string equivalent to:
+   *
+   *     this.substring(0, start) + replacement + this.substring(end)
+   *
+   * The [start] and [end] indices must specify a valid range of this string.
+   * That is `0 <= start <= end <= this.length`.
+   * If [end] is `null`, it defaults to [length].
+   */
+  String replaceRange(int start, int end, String replacement);
+
+  /**
+   * Splits the string at matches of [pattern] and returns a list of substrings.
+   *
+   * Finds all the matches of `pattern` in this string,
+   * and returns the list of the substrings between the matches.
+   *
+   *     var string = "Hello world!";
+   *     string.split(" ");                      // ['Hello', 'world!'];
+   *
+   * Empty matches at the beginning and end of the strings are ignored,
+   * and so are empty matches right after another match.
+   *
+   *     var string = "abba";
+   *     string.split(new RegExp(r"b*"));        // ['a', 'a']
+   *                                             // not ['', 'a', 'a', '']
+   *
+   * If this string is empty, the result is an empty list if `pattern` matches
+   * the empty string, and it is `[""]` if the pattern doesn't match.
+   *
+   *     var string = '';
+   *     string.split('');                       // []
+   *     string.split("a");                      // ['']
+   *
+   * Splitting with an empty pattern splits the string into single-code unit
+   * strings.
+   *
+   *     var string = 'Pub';
+   *     string.split('');                       // ['P', 'u', 'b']
+   *
+   *     string.codeUnits.map((unit) {
+   *       return new String.fromCharCode(unit);
+   *     }).toList();                            // ['P', 'u', 'b']
+   *
+   * Splitting happens at UTF-16 code unit boundaries,
+   * and not at rune boundaries:
+   *
+   *     // String made up of two code units, but one rune.
+   *     string = '\u{1D11E}';
+   *     string.split('').length;                 // 2 surrogate values
+   *
+   * To get a list of strings containing the individual runes of a string,
+   * you should not use split. You can instead map each rune to a string
+   * as follows:
+   *
+   *     string.runes.map((rune) => new String.fromCharCode(rune)).toList();
+   */
+  List<String> split(Pattern pattern);
+
+  /**
+   * Splits the string, converts its parts, and combines them into a new
+   * string.
+   *
+   * [pattern] is used to split the string into parts and separating matches.
+   *
+   * Each match is converted to a string by calling [onMatch]. If [onMatch]
+   * is omitted, the matched string is used.
+   *
+   * Each non-matched part is converted by a call to [onNonMatch]. If
+   * [onNonMatch] is omitted, the non-matching part is used.
+   *
+   * Then all the converted parts are combined into the resulting string.
+   *
+   *     'Eats shoots leaves'.splitMapJoin((new RegExp(r'shoots')),
+   *         onMatch:    (m) => '${m.group(0)}',
+   *         onNonMatch: (n) => '*'); // *shoots*
+   */
+  String splitMapJoin(Pattern pattern,
+      {String onMatch(Match match), String onNonMatch(String nonMatch)});
+
+  /**
+   * Returns an unmodifiable list of the UTF-16 code units of this string.
+   */
+  List<int> get codeUnits;
+
+  /**
+   * Returns an [Iterable] of Unicode code-points of this string.
+   *
+   * If the string contains surrogate pairs, they are combined and returned
+   * as one integer by this iterator. Unmatched surrogate halves are treated
+   * like valid 16-bit code-units.
+   */
+  Runes get runes;
+
+  /**
+   * Converts all characters in this string to lower case.
+   * If the string is already in all lower case, this method returns [:this:].
+   *
+   *     'ALPHABET'.toLowerCase(); // 'alphabet'
+   *     'abc'.toLowerCase();      // 'abc'
+   *
+   * This function uses the language independent Unicode mapping and thus only
+   * works in some languages.
+   */
+  // TODO(floitsch): document better. (See EcmaScript for description).
+  String toLowerCase();
+
+  /**
+   * Converts all characters in this string to upper case.
+   * If the string is already in all upper case, this method returns [:this:].
+   *
+   *     'alphabet'.toUpperCase(); // 'ALPHABET'
+   *     'ABC'.toUpperCase();      // 'ABC'
+   *
+   * This function uses the language independent Unicode mapping and thus only
+   * works in some languages.
+   */
+  // TODO(floitsch): document better. (See EcmaScript for description).
+  String toUpperCase();
+}
+
+/**
+ * The runes (integer Unicode code points) of a [String].
+ */
+class Runes extends Iterable<int> {
+  final String string;
+  Runes(this.string);
+
+  RuneIterator get iterator => RuneIterator(string);
+
+  int get last {
+    if (string.length == 0) {
+      throw StateError('No elements.');
+    }
+    int length = string.length;
+    int code = string.codeUnitAt(length - 1);
+    if (_isTrailSurrogate(code) && string.length > 1) {
+      int previousCode = string.codeUnitAt(length - 2);
+      if (_isLeadSurrogate(previousCode)) {
+        return _combineSurrogatePair(previousCode, code);
+      }
+    }
+    return code;
+  }
+}
+
+// Is then code (a 16-bit unsigned integer) a UTF-16 lead surrogate.
+bool _isLeadSurrogate(int code) => (code & 0xFC00) == 0xD800;
+
+// Is then code (a 16-bit unsigned integer) a UTF-16 trail surrogate.
+bool _isTrailSurrogate(int code) => (code & 0xFC00) == 0xDC00;
+
+// Combine a lead and a trail surrogate value into a single code point.
+int _combineSurrogatePair(int start, int end) {
+  return 0x10000 + ((start & 0x3FF) << 10) + (end & 0x3FF);
+}
+
+/** [Iterator] for reading runes (integer Unicode code points) out of a Dart
+  * string.
+  */
+class RuneIterator implements BidirectionalIterator<int> {
+  /** String being iterated. */
+  final String string;
+  /** Position before the current code point. */
+  int _position;
+  /** Position after the current code point. */
+  int _nextPosition;
+  /**
+   * Current code point.
+   *
+   * If the iterator has hit either end, the [_currentCodePoint] is null
+   * and [: _position == _nextPosition :].
+   */
+  int _currentCodePoint;
+
+  /** Create an iterator positioned at the beginning of the string. */
+  RuneIterator(String string)
+      : this.string = string,
+        _position = 0,
+        _nextPosition = 0;
+
+  /**
+   * Create an iterator positioned before the [index]th code unit of the string.
+   *
+   * When created, there is no [current] value.
+   * A [moveNext] will use the rune starting at [index] the current value,
+   * and a [movePrevious] will use the rune ending just before [index] as the
+   * the current value.
+   *
+   * The [index] position must not be in the middle of a surrogate pair.
+   */
+  RuneIterator.at(String string, int index)
+      : string = string,
+        _position = index,
+        _nextPosition = index {
+    RangeError.checkValueInInterval(index, 0, string.length);
+    _checkSplitSurrogate(index);
+  }
+
+  /** Throw an error if the index is in the middle of a surrogate pair. */
+  void _checkSplitSurrogate(int index) {
+    if (index > 0 &&
+        index < string.length &&
+        _isLeadSurrogate(string.codeUnitAt(index - 1)) &&
+        _isTrailSurrogate(string.codeUnitAt(index))) {
+      throw ArgumentError('Index inside surrogate pair: $index');
+    }
+  }
+
+  /**
+   * Returns the starting position of the current rune in the string.
+   *
+   * Returns null if the [current] rune is null.
+   */
+  int get rawIndex => (_position != _nextPosition) ? _position : null;
+
+  /**
+   * Resets the iterator to the rune at the specified index of the string.
+   *
+   * Setting a negative [rawIndex], or one greater than or equal to
+   * [:string.length:],
+   * is an error. So is setting it in the middle of a surrogate pair.
+   *
+   * Setting the position to the end of then string will set [current] to null.
+   */
+  void set rawIndex(int rawIndex) {
+    RangeError.checkValidIndex(rawIndex, string, "rawIndex");
+    reset(rawIndex);
+    moveNext();
+  }
+
+  /**
+   * Resets the iterator to the given index into the string.
+   *
+   * After this the [current] value is unset.
+   * You must call [moveNext] make the rune at the position current,
+   * or [movePrevious] for the last rune before the position.
+   *
+   * Setting a negative [rawIndex], or one greater than [:string.length:],
+   * is an error. So is setting it in the middle of a surrogate pair.
+   */
+  void reset([int rawIndex = 0]) {
+    RangeError.checkValueInInterval(rawIndex, 0, string.length, "rawIndex");
+    _checkSplitSurrogate(rawIndex);
+    _position = _nextPosition = rawIndex;
+    _currentCodePoint = null;
+  }
+
+  /** The rune (integer Unicode code point) starting at the current position in
+   *  the string.
+   */
+  int get current => _currentCodePoint;
+
+  /**
+   * The number of code units comprising the current rune.
+   *
+   * Returns zero if there is no current rune ([current] is null).
+   */
+  int get currentSize => _nextPosition - _position;
+
+  /**
+   * A string containing the current rune.
+   *
+   * For runes outside the basic multilingual plane, this will be
+   * a String of length 2, containing two code units.
+   *
+   * Returns null if [current] is null.
+   */
+  String get currentAsString {
+    if (_position == _nextPosition) return null;
+    if (_position + 1 == _nextPosition) return string[_position];
+    return string.substring(_position, _nextPosition);
+  }
+
+  bool moveNext() {
+    _position = _nextPosition;
+    if (_position == string.length) {
+      _currentCodePoint = null;
+      return false;
+    }
+    int codeUnit = string.codeUnitAt(_position);
+    int nextPosition = _position + 1;
+    if (_isLeadSurrogate(codeUnit) && nextPosition < string.length) {
+      int nextCodeUnit = string.codeUnitAt(nextPosition);
+      if (_isTrailSurrogate(nextCodeUnit)) {
+        _nextPosition = nextPosition + 1;
+        _currentCodePoint = _combineSurrogatePair(codeUnit, nextCodeUnit);
+        return true;
+      }
+    }
+    _nextPosition = nextPosition;
+    _currentCodePoint = codeUnit;
+    return true;
+  }
+
+  bool movePrevious() {
+    _nextPosition = _position;
+    if (_position == 0) {
+      _currentCodePoint = null;
+      return false;
+    }
+    int position = _position - 1;
+    int codeUnit = string.codeUnitAt(position);
+    if (_isTrailSurrogate(codeUnit) && position > 0) {
+      int prevCodeUnit = string.codeUnitAt(position - 1);
+      if (_isLeadSurrogate(prevCodeUnit)) {
+        _position = position - 1;
+        _currentCodePoint = _combineSurrogatePair(prevCodeUnit, codeUnit);
+        return true;
+      }
+    }
+    _position = position;
+    _currentCodePoint = codeUnit;
+    return true;
+  }
+}
diff --git a/sdk_nnbd/lib/core/string_buffer.dart b/sdk_nnbd/lib/core/string_buffer.dart
new file mode 100644
index 0000000..8fe17f5
--- /dev/null
+++ b/sdk_nnbd/lib/core/string_buffer.dart
@@ -0,0 +1,50 @@
+// Copyright (c) 2011, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.core;
+
+/**
+ * A class for concatenating strings efficiently.
+ *
+ * Allows for the incremental building of a string using write*() methods.
+ * The strings are concatenated to a single string only when [toString] is
+ * called.
+ */
+class StringBuffer implements StringSink {
+  /** Creates the string buffer with an initial content. */
+  external StringBuffer([Object content = ""]);
+
+  /**
+   * Returns the length of the content that has been accumulated so far.
+   * This is a constant-time operation.
+   */
+  external int get length;
+
+  /** Returns whether the buffer is empty. This is a constant-time operation. */
+  bool get isEmpty => length == 0;
+
+  /**
+   * Returns whether the buffer is not empty. This is a constant-time
+   * operation.
+   */
+  bool get isNotEmpty => !isEmpty;
+
+  /// Adds the contents of [obj], converted to a string, to the buffer.
+  external void write(Object obj);
+
+  /// Adds the string representation of [charCode] to the buffer.
+  external void writeCharCode(int charCode);
+
+  external void writeAll(Iterable objects, [String separator = ""]);
+
+  external void writeln([Object obj = ""]);
+
+  /**
+   * Clears the string buffer.
+   */
+  external void clear();
+
+  /// Returns the contents of buffer as a concatenated string.
+  external String toString();
+}
diff --git a/sdk_nnbd/lib/core/string_sink.dart b/sdk_nnbd/lib/core/string_sink.dart
new file mode 100644
index 0000000..e7d950c
--- /dev/null
+++ b/sdk_nnbd/lib/core/string_sink.dart
@@ -0,0 +1,31 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.core;
+
+abstract class StringSink {
+  /**
+   * Converts [obj] to a String by invoking [Object.toString] and 
+   * adds the result to `this`.
+   */
+  void write(Object obj);
+
+  /**
+   * Iterates over the given [objects] and [write]s them in sequence.
+   */
+  void writeAll(Iterable objects, [String separator = ""]);
+
+  /**
+   * Converts [obj] to a String by invoking [Object.toString] and 
+   * adds the result to `this`, followed by a newline.
+   */
+  void writeln([Object obj = ""]);
+
+  /**
+   * Writes the [charCode] to `this`.
+   *
+   * This method is equivalent to `write(new String.fromCharCode(charCode))`.
+   */
+  void writeCharCode(int charCode);
+}
diff --git a/sdk_nnbd/lib/core/symbol.dart b/sdk_nnbd/lib/core/symbol.dart
new file mode 100644
index 0000000..a46ec97
--- /dev/null
+++ b/sdk_nnbd/lib/core/symbol.dart
@@ -0,0 +1,97 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.core;
+
+/// Opaque name used by mirrors, invocations and [Function.apply].
+abstract class Symbol {
+  /** The symbol corresponding to the name of the unary minus operator. */
+  static const Symbol unaryMinus = Symbol("unary-");
+
+  /**
+   * The empty symbol.
+   *
+   * The empty symbol is the name of libraries with no library declaration,
+   * and the base-name of the unnamed constructor.
+   */
+  static const Symbol empty = Symbol("");
+
+  /**
+   * Constructs a new [Symbol] representing the provided name.
+   *
+   * The name must be a valid public Dart member name,
+   * public constructor name, or library name, optionally qualified.
+   *
+   * A qualified name is a valid name preceded by a public identifier name
+   * and a '`.`', e.g., `foo.bar.baz=` is a qualified version of `baz=`.
+   * That means that the content of the [name] String must be either
+   *
+   * * a valid public Dart identifier
+   *   (that is, an identifier not starting with "`_`"),
+   * * such an identifier followed by "=" (a setter name),
+   * * the name of a declarable operator
+   *   (one of "`+`", "`-`", "`*`", "`/`", "`%`", "`~/`", "`&`", "`|`",
+   *   "`^`", "`~`", "`<<`", "`>>`", "`<`", "`<=`", "`>`", "`>=`", "`==`",
+   *   "`[]`", "`[]=`", or "`unary-`"),
+   * * any of the above preceded by any number of qualifiers,
+   *   where a qualifier is a non-private identifier followed by '`.`',
+   * * or the empty string (the default name of a library with no library
+   *   name declaration).
+   *
+   * Symbol instances created from the same [name] are equal,
+   * but not necessarily identical, but symbols created as compile-time
+   * constants are canonicalized, as all other constant object creations.
+   *
+   * ```dart
+   * assert(new Symbol("foo") == new Symbol("foo"));
+   * assert(identical(const Symbol("foo"), const Symbol("foo")));
+   * ```
+   *
+   * If [name] is a single identifier that does not start with an underscore,
+   * or it is a qualified identifier,
+   * or it is an operator name different from `unary-`,
+   * then the result of `const Symbol(name)` is the same instance that
+   * the symbol literal created by prefixing `#` to the content of [name]
+   * would evaluate to.
+   *
+   * ```dart
+   * assert(new Symbol("foo") == #foo);
+   * assert(new Symbol("[]=") == #[]=]);
+   * assert(new Symbol("foo.bar") == #foo.bar);
+   * assert(identical(const Symbol("foo"), #foo));
+   * assert(identical(const Symbol("[]="), #[]=]));
+   * assert(identical(const Symbol("foo.bar"), #foo.bar));
+   * ```
+   *
+   * This constructor cannot create a [Symbol] instance that is equal to
+   * a private symbol literal like `#_foo`.
+   * ```dart
+   * const Symbol("_foo") // Invalid
+   * ```
+   *
+   * The created instance overrides [Object.==].
+   *
+   * The following text is non-normative:
+   *
+   * Creating non-const Symbol instances may result in larger output.  If
+   * possible, use `MirrorsUsed` from "dart:mirrors" to specify which names
+   * might be passed to this constructor.
+   */
+  const factory Symbol(String name) = internal.Symbol;
+
+  /**
+   * Returns a hash code compatible with [operator==].
+   *
+   * Equal symbols have the same hash code.
+   */
+  int get hashCode;
+
+  /**
+   * Symbols are equal to other symbols that correspond to the same member name.
+   *
+   * Qualified member names, like `#foo.bar` are equal only if they have the
+   * same identifiers before the same final member name.
+   */
+  bool operator ==(other);
+}
diff --git a/sdk_nnbd/lib/core/type.dart b/sdk_nnbd/lib/core/type.dart
new file mode 100644
index 0000000..d2e107b
--- /dev/null
+++ b/sdk_nnbd/lib/core/type.dart
@@ -0,0 +1,10 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.core;
+
+/**
+ * Runtime representation of a type.
+ */
+abstract class Type {}
diff --git a/sdk_nnbd/lib/core/uri.dart b/sdk_nnbd/lib/core/uri.dart
new file mode 100644
index 0000000..2ca94a1
--- /dev/null
+++ b/sdk_nnbd/lib/core/uri.dart
@@ -0,0 +1,4784 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.core;
+
+// Frequently used character codes.
+const int _SPACE = 0x20;
+const int _PERCENT = 0x25;
+const int _AMPERSAND = 0x26;
+const int _PLUS = 0x2B;
+const int _DOT = 0x2E;
+const int _SLASH = 0x2F;
+const int _COLON = 0x3A;
+const int _EQUALS = 0x3d;
+const int _UPPER_CASE_A = 0x41;
+const int _UPPER_CASE_Z = 0x5A;
+const int _LEFT_BRACKET = 0x5B;
+const int _BACKSLASH = 0x5C;
+const int _RIGHT_BRACKET = 0x5D;
+const int _LOWER_CASE_A = 0x61;
+const int _LOWER_CASE_F = 0x66;
+const int _LOWER_CASE_Z = 0x7A;
+
+const String _hexDigits = "0123456789ABCDEF";
+
+/**
+ * A parsed URI, such as a URL.
+ *
+ * **See also:**
+ *
+ * * [URIs][uris] in the [library tour][libtour]
+ * * [RFC-3986](http://tools.ietf.org/html/rfc3986)
+ *
+ * [uris]: https://www.dartlang.org/docs/dart-up-and-running/ch03.html#uris
+ * [libtour]: https://www.dartlang.org/docs/dart-up-and-running/contents/ch03.html
+ */
+abstract class Uri {
+  /**
+   * Returns the natural base URI for the current platform.
+   *
+   * When running in a browser this is the current URL of the current page
+   * (from `window.location.href`).
+   *
+   * When not running in a browser this is the file URI referencing
+   * the current working directory.
+   */
+  external static Uri get base;
+
+  /**
+   * Creates a new URI from its components.
+   *
+   * Each component is set through a named argument. Any number of
+   * components can be provided. The [path] and [query] components can be set
+   * using either of two different named arguments.
+   *
+   * The scheme component is set through [scheme]. The scheme is
+   * normalized to all lowercase letters. If the scheme is omitted or empty,
+   * the URI will not have a scheme part.
+   *
+   * The user info part of the authority component is set through
+   * [userInfo]. It defaults to the empty string, which will be omitted
+   * from the string representation of the URI.
+   *
+   * The host part of the authority component is set through
+   * [host]. The host can either be a hostname, an IPv4 address or an
+   * IPv6 address, contained in '[' and ']'. If the host contains a
+   * ':' character, the '[' and ']' are added if not already provided.
+   * The host is normalized to all lowercase letters.
+   *
+   * The port part of the authority component is set through
+   * [port].
+   * If [port] is omitted or `null`, it implies the default port for
+   * the URI's scheme, and is equivalent to passing that port explicitly.
+   * The recognized schemes, and their default ports, are "http" (80) and
+   * "https" (443). All other schemes are considered as having zero as the
+   * default port.
+   *
+   * If any of `userInfo`, `host` or `port` are provided,
+   * the URI has an authority according to [hasAuthority].
+   *
+   * The path component is set through either [path] or
+   * [pathSegments].
+   * When [path] is used, it should be a valid URI path,
+   * but invalid characters, except the general delimiters ':/@[]?#',
+   * will be escaped if necessary.
+   * When [pathSegments] is used, each of the provided segments
+   * is first percent-encoded and then joined using the forward slash
+   * separator.
+   *
+   * The percent-encoding of the path segments encodes all
+   * characters except for the unreserved characters and the following
+   * list of characters: `!$&'()*+,;=:@`. If the other components
+   * necessitate an absolute path, a leading slash `/` is prepended if
+   * not already there.
+   *
+   * The query component is set through either [query] or [queryParameters].
+   * When [query] is used, the provided string should be a valid URI query,
+   * but invalid characters, other than general delimiters,
+   * will be escaped if necessary.
+   * When [queryParameters] is used the query is built from the
+   * provided map. Each key and value in the map is percent-encoded
+   * and joined using equal and ampersand characters.
+   * A value in the map must be either a string, or an [Iterable] of strings,
+   * where the latter corresponds to multiple values for the same key.
+   *
+   * The percent-encoding of the keys and values encodes all characters
+   * except for the unreserved characters, and replaces spaces with `+`.
+   * If `query` is the empty string, it is equivalent to omitting it.
+   * To have an actual empty query part,
+   * use an empty map for `queryParameters`.
+   *
+   * If both `query` and `queryParameters` are omitted or `null`,
+   * the URI has no query part.
+   *
+   * The fragment component is set through [fragment].
+   * It should be a valid URI fragment, but invalid characters other than
+   * general delimiters, are escaped if necessary.
+   * If `fragment` is omitted or `null`, the URI has no fragment part.
+   */
+  factory Uri(
+      {String scheme,
+      String userInfo,
+      String host,
+      int port,
+      String path,
+      Iterable<String> pathSegments,
+      String query,
+      Map<String, dynamic /*String|Iterable<String>*/ > queryParameters,
+      String fragment}) = _Uri;
+
+  /**
+   * Creates a new `http` URI from authority, path and query.
+   *
+   * Examples:
+   *
+   * ```
+   * // http://example.org/path?q=dart.
+   * new Uri.http("example.org", "/path", { "q" : "dart" });
+   *
+   * // http://user:pass@localhost:8080
+   * new Uri.http("user:pass@localhost:8080", "");
+   *
+   * // http://example.org/a%20b
+   * new Uri.http("example.org", "a b");
+   *
+   * // http://example.org/a%252F
+   * new Uri.http("example.org", "/a%2F");
+   * ```
+   *
+   * The `scheme` is always set to `http`.
+   *
+   * The `userInfo`, `host` and `port` components are set from the
+   * [authority] argument. If `authority` is `null` or empty,
+   * the created `Uri` has no authority, and isn't directly usable
+   * as an HTTP URL, which must have a non-empty host.
+   *
+   * The `path` component is set from the [unencodedPath]
+   * argument. The path passed must not be encoded as this constructor
+   * encodes the path.
+   *
+   * The `query` component is set from the optional [queryParameters]
+   * argument.
+   */
+  factory Uri.http(String authority, String unencodedPath,
+      [Map<String, String> queryParameters]) = _Uri.http;
+
+  /**
+   * Creates a new `https` URI from authority, path and query.
+   *
+   * This constructor is the same as [Uri.http] except for the scheme
+   * which is set to `https`.
+   */
+  factory Uri.https(String authority, String unencodedPath,
+      [Map<String, String> queryParameters]) = _Uri.https;
+
+  /**
+   * Creates a new file URI from an absolute or relative file path.
+   *
+   * The file path is passed in [path].
+   *
+   * This path is interpreted using either Windows or non-Windows
+   * semantics.
+   *
+   * With non-Windows semantics the slash (`/`) is used to separate
+   * path segments in the input [path].
+   *
+   * With Windows semantics, backslash (`\`) and forward-slash (`/`)
+   * are used to separate path segments in the input [path],
+   * except if the path starts with `\\?\` in which case
+   * only backslash (`\`) separates path segments in [path].
+   *
+   * If the path starts with a path separator, an absolute URI (with the
+   * `file` scheme and an empty authority) is created.
+   * Otherwise a relative URI reference with no scheme or authority is created.
+   * One exception from this rule is that when Windows semantics is used
+   * and the path starts with a drive letter followed by a colon (":") and a
+   * path separator, then an absolute URI is created.
+   *
+   * The default for whether to use Windows or non-Windows semantics
+   * determined from the platform Dart is running on. When running in
+   * the standalone VM, this is detected by the VM based on the
+   * operating system. When running in a browser non-Windows semantics
+   * is always used.
+   *
+   * To override the automatic detection of which semantics to use pass
+   * a value for [windows]. Passing `true` will use Windows
+   * semantics and passing `false` will use non-Windows semantics.
+   *
+   * Examples using non-Windows semantics:
+   *
+   * ```
+   * // xxx/yyy
+   * new Uri.file("xxx/yyy", windows: false);
+   *
+   * // xxx/yyy/
+   * new Uri.file("xxx/yyy/", windows: false);
+   *
+   * // file:///xxx/yyy
+   * new Uri.file("/xxx/yyy", windows: false);
+   *
+   * // file:///xxx/yyy/
+   * new Uri.file("/xxx/yyy/", windows: false);
+   *
+   * // C%3A
+   * new Uri.file("C:", windows: false);
+   * ```
+   *
+   * Examples using Windows semantics:
+   *
+   * ```
+   * // xxx/yyy
+   * new Uri.file(r"xxx\yyy", windows: true);
+   *
+   * // xxx/yyy/
+   * new Uri.file(r"xxx\yyy\", windows: true);
+   *
+   * file:///xxx/yyy
+   * new Uri.file(r"\xxx\yyy", windows: true);
+   *
+   * file:///xxx/yyy/
+   * new Uri.file(r"\xxx\yyy/", windows: true);
+   *
+   * // file:///C:/xxx/yyy
+   * new Uri.file(r"C:\xxx\yyy", windows: true);
+   *
+   * // This throws an error. A path with a drive letter, but no following
+   * // path, is not allowed.
+   * new Uri.file(r"C:", windows: true);
+   *
+   * // This throws an error. A path with a drive letter is not absolute.
+   * new Uri.file(r"C:xxx\yyy", windows: true);
+   *
+   * // file://server/share/file
+   * new Uri.file(r"\\server\share\file", windows: true);
+   * ```
+   *
+   * If the path passed is not a valid file path, an error is thrown.
+   */
+  factory Uri.file(String path, {bool windows}) = _Uri.file;
+
+  /**
+   * Like [Uri.file] except that a non-empty URI path ends in a slash.
+   *
+   * If [path] is not empty, and it doesn't end in a directory separator,
+   * then a slash is added to the returned URI's path.
+   * In all other cases, the result is the same as returned by `Uri.file`.
+   */
+  factory Uri.directory(String path, {bool windows}) = _Uri.directory;
+
+  /**
+   * Creates a `data:` URI containing the [content] string.
+   *
+   * Converts the content to a bytes using [encoding] or the charset specified
+   * in [parameters] (defaulting to US-ASCII if not specified or unrecognized),
+   * then encodes the bytes into the resulting data URI.
+   *
+   * Defaults to encoding using percent-encoding (any non-ASCII or non-URI-valid
+   * bytes is replaced by a percent encoding). If [base64] is true, the bytes
+   * are instead encoded using [base64].
+   *
+   * If [encoding] is not provided and [parameters] has a `charset` entry,
+   * that name is looked up using [Encoding.getByName],
+   * and if the lookup returns an encoding, that encoding is used to convert
+   * [content] to bytes.
+   * If providing both an [encoding] and a charset in [parameters], they should
+   * agree, otherwise decoding won't be able to use the charset parameter
+   * to determine the encoding.
+   *
+   * If [mimeType] and/or [parameters] are supplied, they are added to the
+   * created URI. If any of these contain characters that are not allowed
+   * in the data URI, the character is percent-escaped. If the character is
+   * non-ASCII, it is first UTF-8 encoded and then the bytes are percent
+   * encoded. An omitted [mimeType] in a data URI means `text/plain`, just
+   * as an omitted `charset` parameter defaults to meaning `US-ASCII`.
+   *
+   * To read the content back, use [UriData.contentAsString].
+   */
+  factory Uri.dataFromString(String content,
+      {String mimeType,
+      Encoding encoding,
+      Map<String, String> parameters,
+      bool base64 = false}) {
+    UriData data = UriData.fromString(content,
+        mimeType: mimeType,
+        encoding: encoding,
+        parameters: parameters,
+        base64: base64);
+    return data.uri;
+  }
+
+  /**
+   * Creates a `data:` URI containing an encoding of [bytes].
+   *
+   * Defaults to Base64 encoding the bytes, but if [percentEncoded]
+   * is `true`, the bytes will instead be percent encoded (any non-ASCII
+   * or non-valid-ASCII-character byte is replaced by a percent encoding).
+   *
+   * To read the bytes back, use [UriData.contentAsBytes].
+   *
+   * It defaults to having the mime-type `application/octet-stream`.
+   * The [mimeType] and [parameters] are added to the created URI.
+   * If any of these contain characters that are not allowed
+   * in the data URI, the character is percent-escaped. If the character is
+   * non-ASCII, it is first UTF-8 encoded and then the bytes are percent
+   * encoded.
+   */
+  factory Uri.dataFromBytes(List<int> bytes,
+      {mimeType = "application/octet-stream",
+      Map<String, String> parameters,
+      percentEncoded = false}) {
+    UriData data = UriData.fromBytes(bytes,
+        mimeType: mimeType,
+        parameters: parameters,
+        percentEncoded: percentEncoded);
+    return data.uri;
+  }
+
+  /**
+   * The scheme component of the URI.
+   *
+   * Returns the empty string if there is no scheme component.
+   *
+   * A URI scheme is case insensitive.
+   * The returned scheme is canonicalized to lowercase letters.
+   */
+  String get scheme;
+
+  /**
+   * Returns the authority component.
+   *
+   * The authority is formatted from the [userInfo], [host] and [port]
+   * parts.
+   *
+   * Returns the empty string if there is no authority component.
+   */
+  String get authority;
+
+  /**
+   * Returns the user info part of the authority component.
+   *
+   * Returns the empty string if there is no user info in the
+   * authority component.
+   */
+  String get userInfo;
+
+  /**
+   * Returns the host part of the authority component.
+   *
+   * Returns the empty string if there is no authority component and
+   * hence no host.
+   *
+   * If the host is an IP version 6 address, the surrounding `[` and `]` is
+   * removed.
+   *
+   * The host string is case-insensitive.
+   * The returned host name is canonicalized to lower-case
+   * with upper-case percent-escapes.
+   */
+  String get host;
+
+  /**
+   * Returns the port part of the authority component.
+   *
+   * Returns the default port if there is no port number in the authority
+   * component. That's 80 for http, 443 for https, and 0 for everything else.
+   */
+  int get port;
+
+  /**
+   * Returns the path component.
+   *
+   * The returned path is encoded. To get direct access to the decoded
+   * path use [pathSegments].
+   *
+   * Returns the empty string if there is no path component.
+   */
+  String get path;
+
+  /**
+   * Returns the query component. The returned query is encoded. To get
+   * direct access to the decoded query use [queryParameters].
+   *
+   * Returns the empty string if there is no query component.
+   */
+  String get query;
+
+  /**
+   * Returns the fragment identifier component.
+   *
+   * Returns the empty string if there is no fragment identifier
+   * component.
+   */
+  String get fragment;
+
+  /**
+   * Returns the URI path split into its segments. Each of the segments in the
+   * returned list have been decoded. If the path is empty the empty list will
+   * be returned. A leading slash `/` does not affect the segments returned.
+   *
+   * The returned list is unmodifiable and will throw [UnsupportedError] on any
+   * calls that would mutate it.
+   */
+  List<String> get pathSegments;
+
+  /**
+   * Returns the URI query split into a map according to the rules
+   * specified for FORM post in the [HTML 4.01 specification section
+   * 17.13.4](http://www.w3.org/TR/REC-html40/interact/forms.html#h-17.13.4 "HTML 4.01 section 17.13.4").
+   * Each key and value in the returned map has been decoded.
+   * If there is no query the empty map is returned.
+   *
+   * Keys in the query string that have no value are mapped to the
+   * empty string.
+   * If a key occurs more than once in the query string, it is mapped to
+   * an arbitrary choice of possible value.
+   * The [queryParametersAll] getter can provide a map
+   * that maps keys to all of their values.
+   *
+   * The returned map is unmodifiable.
+   */
+  Map<String, String> get queryParameters;
+
+  /**
+   * Returns the URI query split into a map according to the rules
+   * specified for FORM post in the [HTML 4.01 specification section
+   * 17.13.4](http://www.w3.org/TR/REC-html40/interact/forms.html#h-17.13.4 "HTML 4.01 section 17.13.4").
+   * Each key and value in the returned map has been decoded. If there is no
+   * query the empty map is returned.
+   *
+   * Keys are mapped to lists of their values. If a key occurs only once,
+   * its value is a singleton list. If a key occurs with no value, the
+   * empty string is used as the value for that occurrence.
+   *
+   * The returned map and the lists it contains are unmodifiable.
+   */
+  Map<String, List<String>> get queryParametersAll;
+
+  /**
+   * Returns whether the URI is absolute.
+   *
+   * A URI is an absolute URI in the sense of RFC 3986 if it has a scheme
+   * and no fragment.
+   */
+  bool get isAbsolute;
+
+  /**
+   * Returns whether the URI has a [scheme] component.
+   */
+  bool get hasScheme => scheme.isNotEmpty;
+
+  /**
+   * Returns whether the URI has an [authority] component.
+   */
+  bool get hasAuthority;
+
+  /**
+   * Returns whether the URI has an explicit port.
+   *
+   * If the port number is the default port number
+   * (zero for unrecognized schemes, with http (80) and https (443) being
+   * recognized),
+   * then the port is made implicit and omitted from the URI.
+   */
+  bool get hasPort;
+
+  /**
+   * Returns whether the URI has a query part.
+   */
+  bool get hasQuery;
+
+  /**
+   * Returns whether the URI has a fragment part.
+   */
+  bool get hasFragment;
+
+  /**
+   * Returns whether the URI has an empty path.
+   */
+  bool get hasEmptyPath;
+
+  /**
+   * Returns whether the URI has an absolute path (starting with '/').
+   */
+  bool get hasAbsolutePath;
+
+  /**
+   * Returns the origin of the URI in the form scheme://host:port for the
+   * schemes http and https.
+   *
+   * It is an error if the scheme is not "http" or "https", or if the host name
+   * is missing or empty.
+   *
+   * See: http://www.w3.org/TR/2011/WD-html5-20110405/origin-0.html#origin
+   */
+  String get origin;
+
+  /// Whether the scheme of this [Uri] is [scheme].
+  ///
+  /// The [scheme] should be the same as the one returned by [Uri.scheme],
+  /// but doesn't have to be case-normalized to lower-case characters.
+  ///
+  /// Example:
+  /// ```dart
+  /// var uri = Uri.parse("http://example.com/");
+  /// print(uri.isScheme("HTTP"));  // Prints true.
+  /// ```
+  ///
+  /// A `null` or empty [scheme] string matches a URI with no scheme
+  /// (one where [hasScheme] returns false).
+  bool isScheme(String scheme);
+
+  /**
+   * Returns the file path from a file URI.
+   *
+   * The returned path has either Windows or non-Windows
+   * semantics.
+   *
+   * For non-Windows semantics the slash ("/") is used to separate
+   * path segments.
+   *
+   * For Windows semantics the backslash ("\\") separator is used to
+   * separate path segments.
+   *
+   * If the URI is absolute the path starts with a path separator
+   * unless Windows semantics is used and the first path segment is a
+   * drive letter. When Windows semantics is used a host component in
+   * the uri in interpreted as a file server and a UNC path is
+   * returned.
+   *
+   * The default for whether to use Windows or non-Windows semantics
+   * determined from the platform Dart is running on. When running in
+   * the standalone VM this is detected by the VM based on the
+   * operating system. When running in a browser non-Windows semantics
+   * is always used.
+   *
+   * To override the automatic detection of which semantics to use pass
+   * a value for [windows]. Passing `true` will use Windows
+   * semantics and passing `false` will use non-Windows semantics.
+   *
+   * If the URI ends with a slash (i.e. the last path component is
+   * empty) the returned file path will also end with a slash.
+   *
+   * With Windows semantics URIs starting with a drive letter cannot
+   * be relative to the current drive on the designated drive. That is
+   * for the URI `file:///c:abc` calling `toFilePath` will throw as a
+   * path segment cannot contain colon on Windows.
+   *
+   * Examples using non-Windows semantics (resulting of calling
+   * toFilePath in comment):
+   *
+   *     Uri.parse("xxx/yyy");  // xxx/yyy
+   *     Uri.parse("xxx/yyy/");  // xxx/yyy/
+   *     Uri.parse("file:///xxx/yyy");  // /xxx/yyy
+   *     Uri.parse("file:///xxx/yyy/");  // /xxx/yyy/
+   *     Uri.parse("file:///C:");  // /C:
+   *     Uri.parse("file:///C:a");  // /C:a
+   *
+   * Examples using Windows semantics (resulting URI in comment):
+   *
+   *     Uri.parse("xxx/yyy");  // xxx\yyy
+   *     Uri.parse("xxx/yyy/");  // xxx\yyy\
+   *     Uri.parse("file:///xxx/yyy");  // \xxx\yyy
+   *     Uri.parse("file:///xxx/yyy/");  // \xxx\yyy\
+   *     Uri.parse("file:///C:/xxx/yyy");  // C:\xxx\yyy
+   *     Uri.parse("file:C:xxx/yyy");  // Throws as a path segment
+   *                                   // cannot contain colon on Windows.
+   *     Uri.parse("file://server/share/file");  // \\server\share\file
+   *
+   * If the URI is not a file URI calling this throws
+   * [UnsupportedError].
+   *
+   * If the URI cannot be converted to a file path calling this throws
+   * [UnsupportedError].
+   */
+  // TODO(lrn): Deprecate and move functionality to File class or similar.
+  // The core libraries should not worry about the platform.
+  String toFilePath({bool windows});
+
+  /**
+   * Access the structure of a `data:` URI.
+   *
+   * Returns a [UriData] object for `data:` URIs and `null` for all other
+   * URIs.
+   * The [UriData] object can be used to access the media type and data
+   * of a `data:` URI.
+   */
+  UriData get data;
+
+  /// Returns a hash code computed as `toString().hashCode`.
+  ///
+  /// This guarantees that URIs with the same normalized
+  int get hashCode;
+
+  /// A URI is equal to another URI with the same normalized representation.
+  bool operator ==(Object other);
+
+  /// Returns the normalized string representation of the URI.
+  String toString();
+
+  /**
+   * Returns a new `Uri` based on this one, but with some parts replaced.
+   *
+   * This method takes the same parameters as the [new Uri] constructor,
+   * and they have the same meaning.
+   *
+   * At most one of [path] and [pathSegments] must be provided.
+   * Likewise, at most one of [query] and [queryParameters] must be provided.
+   *
+   * Each part that is not provided will default to the corresponding
+   * value from this `Uri` instead.
+   *
+   * This method is different from [Uri.resolve] which overrides in a
+   * hierarchical manner,
+   * and can instead replace each part of a `Uri` individually.
+   *
+   * Example:
+   *
+   *     Uri uri1 = Uri.parse("a://b@c:4/d/e?f#g");
+   *     Uri uri2 = uri1.replace(scheme: "A", path: "D/E/E", fragment: "G");
+   *     print(uri2);  // prints "a://b@c:4/D/E/E?f#G"
+   *
+   * This method acts similarly to using the `new Uri` constructor with
+   * some of the arguments taken from this `Uri`. Example:
+   *
+   *     Uri uri3 = new Uri(
+   *         scheme: "A",
+   *         userInfo: uri1.userInfo,
+   *         host: uri1.host,
+   *         port: uri1.port,
+   *         path: "D/E/E",
+   *         query: uri1.query,
+   *         fragment: "G");
+   *     print(uri3);  // prints "a://b@c:4/D/E/E?f#G"
+   *     print(uri2 == uri3);  // prints true.
+   *
+   * Using this method can be seen as a shorthand for the `Uri` constructor
+   * call above, but may also be slightly faster because the parts taken
+   * from this `Uri` need not be checked for validity again.
+   */
+  Uri replace(
+      {String scheme,
+      String userInfo,
+      String host,
+      int port,
+      String path,
+      Iterable<String> pathSegments,
+      String query,
+      Map<String, dynamic /*String|Iterable<String>*/ > queryParameters,
+      String fragment});
+
+  /**
+   * Returns a `Uri` that differs from this only in not having a fragment.
+   *
+   * If this `Uri` does not have a fragment, it is itself returned.
+   */
+  Uri removeFragment();
+
+  /**
+   * Resolve [reference] as an URI relative to `this`.
+   *
+   * First turn [reference] into a URI using [Uri.parse]. Then resolve the
+   * resulting URI relative to `this`.
+   *
+   * Returns the resolved URI.
+   *
+   * See [resolveUri] for details.
+   */
+  Uri resolve(String reference);
+
+  /**
+   * Resolve [reference] as an URI relative to `this`.
+   *
+   * Returns the resolved URI.
+   *
+   * The algorithm "Transform Reference" for resolving a reference is described
+   * in [RFC-3986 Section 5](http://tools.ietf.org/html/rfc3986#section-5 "RFC-1123").
+   *
+   * Updated to handle the case where the base URI is just a relative path -
+   * that is: when it has no scheme and no authority and the path does not start
+   * with a slash.
+   * In that case, the paths are combined without removing leading "..", and
+   * an empty path is not converted to "/".
+   */
+  Uri resolveUri(Uri reference);
+
+  /**
+   * Returns a URI where the path has been normalized.
+   *
+   * A normalized path does not contain `.` segments or non-leading `..`
+   * segments.
+   * Only a relative path with no scheme or authority may contain
+   * leading `..` segments,
+   * a path that starts with `/` will also drop any leading `..` segments.
+   *
+   * This uses the same normalization strategy as `new Uri().resolve(this)`.
+   *
+   * Does not change any part of the URI except the path.
+   *
+   * The default implementation of `Uri` always normalizes paths, so calling
+   * this function has no effect.
+   */
+  Uri normalizePath();
+
+  /**
+   * Creates a new `Uri` object by parsing a URI string.
+   *
+   * If [start] and [end] are provided, they must specify a valid substring
+   * of [uri], and only the substring from `start` to `end` is parsed as a URI.
+   *
+   * The [uri] must not be `null`.
+   * If the [uri] string is not valid as a URI or URI reference,
+   * a [FormatException] is thrown.
+   */
+  static Uri parse(String uri, [int start = 0, int end]) {
+    // This parsing will not validate percent-encoding, IPv6, etc.
+    // When done splitting into parts, it will call, e.g., [_makeFragment]
+    // to do the final parsing.
+    //
+    // Important parts of the RFC 3986 used here:
+    // URI           = scheme ":" hier-part [ "?" query ] [ "#" fragment ]
+    //
+    // hier-part     = "//" authority path-abempty
+    //               / path-absolute
+    //               / path-rootless
+    //               / path-empty
+    //
+    // URI-reference = URI / relative-ref
+    //
+    // absolute-URI  = scheme ":" hier-part [ "?" query ]
+    //
+    // relative-ref  = relative-part [ "?" query ] [ "#" fragment ]
+    //
+    // relative-part = "//" authority path-abempty
+    //               / path-absolute
+    //               / path-noscheme
+    //               / path-empty
+    //
+    // scheme        = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
+    //
+    // authority     = [ userinfo "@" ] host [ ":" port ]
+    // userinfo      = *( unreserved / pct-encoded / sub-delims / ":" )
+    // host          = IP-literal / IPv4address / reg-name
+    // IP-literal    = "[" ( IPv6address / IPv6addrz / IPvFuture ) "]"
+    // IPv6addrz     = IPv6address "%25" ZoneID
+    // ZoneID        = 1*( unreserved / pct-encoded )
+    // port          = *DIGIT
+    // reg-name      = *( unreserved / pct-encoded / sub-delims )
+    //
+    // path          = path-abempty    ; begins with "/" or is empty
+    //               / path-absolute   ; begins with "/" but not "//"
+    //               / path-noscheme   ; begins with a non-colon segment
+    //               / path-rootless   ; begins with a segment
+    //               / path-empty      ; zero characters
+    //
+    // path-abempty  = *( "/" segment )
+    // path-absolute = "/" [ segment-nz *( "/" segment ) ]
+    // path-noscheme = segment-nz-nc *( "/" segment )
+    // path-rootless = segment-nz *( "/" segment )
+    // path-empty    = 0<pchar>
+    //
+    // segment       = *pchar
+    // segment-nz    = 1*pchar
+    // segment-nz-nc = 1*( unreserved / pct-encoded / sub-delims / "@" )
+    //               ; non-zero-length segment without any colon ":"
+    //
+    // pchar         = unreserved / pct-encoded / sub-delims / ":" / "@"
+    //
+    // query         = *( pchar / "/" / "?" )
+    //
+    // fragment      = *( pchar / "/" / "?" )
+    end ??= uri.length;
+
+    // Special case data:URIs. Ignore case when testing.
+    if (end >= start + 5) {
+      int dataDelta = _startsWithData(uri, start);
+      if (dataDelta == 0) {
+        // The case is right.
+        if (start > 0 || end < uri.length) uri = uri.substring(start, end);
+        return UriData._parse(uri, 5, null).uri;
+      } else if (dataDelta == 0x20) {
+        return UriData._parse(uri.substring(start + 5, end), 0, null).uri;
+      }
+      // Otherwise the URI doesn't start with "data:" or any case variant of it.
+    }
+
+    // The following index-normalization belongs with the scanning, but is
+    // easier to do here because we already have extracted variables from the
+    // indices list.
+    var indices = List<int>(8);
+
+    // Set default values for each position.
+    // The value will either be correct in some cases where it isn't set
+    // by the scanner, or it is clearly recognizable as an unset value.
+    indices
+      ..[0] = 0
+      ..[_schemeEndIndex] = start - 1
+      ..[_hostStartIndex] = start - 1
+      ..[_notSimpleIndex] = start - 1
+      ..[_portStartIndex] = start
+      ..[_pathStartIndex] = start
+      ..[_queryStartIndex] = end
+      ..[_fragmentStartIndex] = end;
+    var state = _scan(uri, start, end, _uriStart, indices);
+    // Some states that should be non-simple, but the URI ended early.
+    // Paths that end at a ".." must be normalized to end in "../".
+    if (state >= _nonSimpleEndStates) {
+      indices[_notSimpleIndex] = end;
+    }
+    int schemeEnd = indices[_schemeEndIndex];
+    if (schemeEnd >= start) {
+      // Rescan the scheme part now that we know it's not a path.
+      state = _scan(uri, start, schemeEnd, _schemeStart, indices);
+      if (state == _schemeStart) {
+        // Empty scheme.
+        indices[_notSimpleIndex] = schemeEnd;
+      }
+    }
+    // The returned positions are limited by the scanners ability to write only
+    // one position per character, and only the current position.
+    // Scanning from left to right, we only know whether something is a scheme
+    // or a path when we see a `:` or `/`, and likewise we only know if the first
+    // `/` is part of the path or is leading an authority component when we see
+    // the next character.
+
+    int hostStart = indices[_hostStartIndex] + 1;
+    int portStart = indices[_portStartIndex];
+    int pathStart = indices[_pathStartIndex];
+    int queryStart = indices[_queryStartIndex];
+    int fragmentStart = indices[_fragmentStartIndex];
+
+    // We may discover scheme while handling special cases.
+    String scheme;
+
+    // Derive some positions that weren't set to normalize the indices.
+    if (fragmentStart < queryStart) queryStart = fragmentStart;
+    // If pathStart isn't set (it's before scheme end or host start), then
+    // the path is empty, or there is no authority part and the path
+    // starts with a non-simple character.
+    if (pathStart < hostStart) {
+      // There is an authority, but no path. The path would start with `/`
+      // if it was there.
+      pathStart = queryStart;
+    } else if (pathStart <= schemeEnd) {
+      // There is a scheme, but no authority.
+      pathStart = schemeEnd + 1;
+    }
+    // If there is an authority with no port, set the port position
+    // to be at the end of the authority (equal to pathStart).
+    // This also handles a ":" in a user-info component incorrectly setting
+    // the port start position.
+    if (portStart < hostStart) portStart = pathStart;
+
+    assert(hostStart == start || schemeEnd <= hostStart);
+    assert(hostStart <= portStart);
+    assert(schemeEnd <= pathStart);
+    assert(portStart <= pathStart);
+    assert(pathStart <= queryStart);
+    assert(queryStart <= fragmentStart);
+
+    bool isSimple = indices[_notSimpleIndex] < start;
+
+    if (isSimple) {
+      // Check/do normalizations that weren't detected by the scanner.
+      // This includes removal of empty port or userInfo,
+      // or scheme specific port and path normalizations.
+      if (hostStart > schemeEnd + 3) {
+        // Always be non-simple if URI contains user-info.
+        // The scanner doesn't set the not-simple position in this case because
+        // it's setting the host-start position instead.
+        isSimple = false;
+      } else if (portStart > start && portStart + 1 == pathStart) {
+        // If the port is empty, it should be omitted.
+        // Pathological case, don't bother correcting it.
+        isSimple = false;
+      } else if (queryStart < end &&
+              (queryStart == pathStart + 2 &&
+                  uri.startsWith("..", pathStart)) ||
+          (queryStart > pathStart + 2 &&
+              uri.startsWith("/..", queryStart - 3))) {
+        // The path ends in a ".." segment. This should be normalized to "../".
+        // We didn't detect this while scanning because a query or fragment was
+        // detected at the same time (which is why we only need to check this
+        // if there is something after the path).
+        isSimple = false;
+      } else {
+        // There are a few scheme-based normalizations that
+        // the scanner couldn't check.
+        // That means that the input is very close to simple, so just do
+        // the normalizations.
+        if (schemeEnd == start + 4) {
+          // Do scheme based normalizations for file, http.
+          if (uri.startsWith("file", start)) {
+            scheme = "file";
+            if (hostStart <= start) {
+              // File URIs should have an authority.
+              // Paths after an authority should be absolute.
+              String schemeAuth = "file://";
+              int delta = 2;
+              if (!uri.startsWith("/", pathStart)) {
+                schemeAuth = "file:///";
+                delta = 3;
+              }
+              uri = schemeAuth + uri.substring(pathStart, end);
+              schemeEnd -= start;
+              hostStart = 7;
+              portStart = 7;
+              pathStart = 7;
+              queryStart += delta - start;
+              fragmentStart += delta - start;
+              start = 0;
+              end = uri.length;
+            } else if (pathStart == queryStart) {
+              // Uri has authority and empty path. Add "/" as path.
+              if (start == 0 && end == uri.length) {
+                uri = uri.replaceRange(pathStart, queryStart, "/");
+                queryStart += 1;
+                fragmentStart += 1;
+                end += 1;
+              } else {
+                uri = "${uri.substring(start, pathStart)}/"
+                    "${uri.substring(queryStart, end)}";
+                schemeEnd -= start;
+                hostStart -= start;
+                portStart -= start;
+                pathStart -= start;
+                queryStart += 1 - start;
+                fragmentStart += 1 - start;
+                start = 0;
+                end = uri.length;
+              }
+            }
+          } else if (uri.startsWith("http", start)) {
+            scheme = "http";
+            // HTTP URIs should not have an explicit port of 80.
+            if (portStart > start &&
+                portStart + 3 == pathStart &&
+                uri.startsWith("80", portStart + 1)) {
+              if (start == 0 && end == uri.length) {
+                uri = uri.replaceRange(portStart, pathStart, "");
+                pathStart -= 3;
+                queryStart -= 3;
+                fragmentStart -= 3;
+                end -= 3;
+              } else {
+                uri = uri.substring(start, portStart) +
+                    uri.substring(pathStart, end);
+                schemeEnd -= start;
+                hostStart -= start;
+                portStart -= start;
+                pathStart -= 3 + start;
+                queryStart -= 3 + start;
+                fragmentStart -= 3 + start;
+                start = 0;
+                end = uri.length;
+              }
+            }
+          }
+        } else if (schemeEnd == start + 5 && uri.startsWith("https", start)) {
+          scheme = "https";
+          // HTTPS URIs should not have an explicit port of 443.
+          if (portStart > start &&
+              portStart + 4 == pathStart &&
+              uri.startsWith("443", portStart + 1)) {
+            if (start == 0 && end == uri.length) {
+              uri = uri.replaceRange(portStart, pathStart, "");
+              pathStart -= 4;
+              queryStart -= 4;
+              fragmentStart -= 4;
+              end -= 3;
+            } else {
+              uri = uri.substring(start, portStart) +
+                  uri.substring(pathStart, end);
+              schemeEnd -= start;
+              hostStart -= start;
+              portStart -= start;
+              pathStart -= 4 + start;
+              queryStart -= 4 + start;
+              fragmentStart -= 4 + start;
+              start = 0;
+              end = uri.length;
+            }
+          }
+        }
+      }
+    }
+
+    if (isSimple) {
+      if (start > 0 || end < uri.length) {
+        uri = uri.substring(start, end);
+        schemeEnd -= start;
+        hostStart -= start;
+        portStart -= start;
+        pathStart -= start;
+        queryStart -= start;
+        fragmentStart -= start;
+      }
+      return _SimpleUri(uri, schemeEnd, hostStart, portStart, pathStart,
+          queryStart, fragmentStart, scheme);
+    }
+
+    return _Uri.notSimple(uri, start, end, schemeEnd, hostStart, portStart,
+        pathStart, queryStart, fragmentStart, scheme);
+  }
+
+  /**
+   * Creates a new `Uri` object by parsing a URI string.
+   *
+   * If [start] and [end] are provided, they must specify a valid substring
+   * of [uri], and only the substring from `start` to `end` is parsed as a URI.
+   * The [uri] must not be `null`.
+   *
+   * Returns `null` if the [uri] string is not valid as a URI or URI reference.
+   */
+  static Uri tryParse(String uri, [int start = 0, int end]) {
+    // TODO: Optimize to avoid throwing-and-recatching.
+    try {
+      return parse(uri, start, end);
+    } on FormatException {
+      return null;
+    }
+  }
+
+  /**
+   * Encode the string [component] using percent-encoding to make it
+   * safe for literal use as a URI component.
+   *
+   * All characters except uppercase and lowercase letters, digits and
+   * the characters `-_.!~*'()` are percent-encoded. This is the
+   * set of characters specified in RFC 2396 and the which is
+   * specified for the encodeUriComponent in ECMA-262 version 5.1.
+   *
+   * When manually encoding path segments or query components remember
+   * to encode each part separately before building the path or query
+   * string.
+   *
+   * For encoding the query part consider using
+   * [encodeQueryComponent].
+   *
+   * To avoid the need for explicitly encoding use the [pathSegments]
+   * and [queryParameters] optional named arguments when constructing
+   * a [Uri].
+   */
+  static String encodeComponent(String component) {
+    return _Uri._uriEncode(_Uri._unreserved2396Table, component, utf8, false);
+  }
+
+  /**
+   * Encode the string [component] according to the HTML 4.01 rules
+   * for encoding the posting of a HTML form as a query string
+   * component.
+   *
+   * Encode the string [component] according to the HTML 4.01 rules
+   * for encoding the posting of a HTML form as a query string
+   * component.
+
+   * The component is first encoded to bytes using [encoding].
+   * The default is to use [utf8] encoding, which preserves all
+   * the characters that don't need encoding.
+
+   * Then the resulting bytes are "percent-encoded". This transforms
+   * spaces (U+0020) to a plus sign ('+') and all bytes that are not
+   * the ASCII decimal digits, letters or one of '-._~' are written as
+   * a percent sign '%' followed by the two-digit hexadecimal
+   * representation of the byte.
+
+   * Note that the set of characters which are percent-encoded is a
+   * superset of what HTML 4.01 requires, since it refers to RFC 1738
+   * for reserved characters.
+   *
+   * When manually encoding query components remember to encode each
+   * part separately before building the query string.
+   *
+   * To avoid the need for explicitly encoding the query use the
+   * [queryParameters] optional named arguments when constructing a
+   * [Uri].
+   *
+   * See http://www.w3.org/TR/html401/interact/forms.html#h-17.13.4.2 for more
+   * details.
+   */
+  static String encodeQueryComponent(String component,
+      {Encoding encoding = utf8}) {
+    return _Uri._uriEncode(_Uri._unreservedTable, component, encoding, true);
+  }
+
+  /**
+   * Decodes the percent-encoding in [encodedComponent].
+   *
+   * Note that decoding a URI component might change its meaning as
+   * some of the decoded characters could be characters with are
+   * delimiters for a given URI component type. Always split a URI
+   * component using the delimiters for the component before decoding
+   * the individual parts.
+   *
+   * For handling the [path] and [query] components consider using
+   * [pathSegments] and [queryParameters] to get the separated and
+   * decoded component.
+   */
+  static String decodeComponent(String encodedComponent) {
+    return _Uri._uriDecode(
+        encodedComponent, 0, encodedComponent.length, utf8, false);
+  }
+
+  /**
+   * Decodes the percent-encoding in [encodedComponent], converting
+   * pluses to spaces.
+   *
+   * It will create a byte-list of the decoded characters, and then use
+   * [encoding] to decode the byte-list to a String. The default encoding is
+   * UTF-8.
+   */
+  static String decodeQueryComponent(String encodedComponent,
+      {Encoding encoding = utf8}) {
+    return _Uri._uriDecode(
+        encodedComponent, 0, encodedComponent.length, encoding, true);
+  }
+
+  /**
+   * Encode the string [uri] using percent-encoding to make it
+   * safe for literal use as a full URI.
+   *
+   * All characters except uppercase and lowercase letters, digits and
+   * the characters `!#$&'()*+,-./:;=?@_~` are percent-encoded. This
+   * is the set of characters specified in in ECMA-262 version 5.1 for
+   * the encodeURI function .
+   */
+  static String encodeFull(String uri) {
+    return _Uri._uriEncode(_Uri._encodeFullTable, uri, utf8, false);
+  }
+
+  /**
+   * Decodes the percent-encoding in [uri].
+   *
+   * Note that decoding a full URI might change its meaning as some of
+   * the decoded characters could be reserved characters. In most
+   * cases an encoded URI should be parsed into components using
+   * [Uri.parse] before decoding the separate components.
+   */
+  static String decodeFull(String uri) {
+    return _Uri._uriDecode(uri, 0, uri.length, utf8, false);
+  }
+
+  /**
+   * Returns the [query] split into a map according to the rules
+   * specified for FORM post in the [HTML 4.01 specification section
+   * 17.13.4](http://www.w3.org/TR/REC-html40/interact/forms.html#h-17.13.4 "HTML 4.01 section 17.13.4").
+   * Each key and value in the returned map has been decoded. If the [query]
+   * is the empty string an empty map is returned.
+   *
+   * Keys in the query string that have no value are mapped to the
+   * empty string.
+   *
+   * Each query component will be decoded using [encoding]. The default encoding
+   * is UTF-8.
+   */
+  static Map<String, String> splitQueryString(String query,
+      {Encoding encoding = utf8}) {
+    return query.split("&").fold({}, (map, element) {
+      int index = element.indexOf("=");
+      if (index == -1) {
+        if (element != "") {
+          map[decodeQueryComponent(element, encoding: encoding)] = "";
+        }
+      } else if (index != 0) {
+        var key = element.substring(0, index);
+        var value = element.substring(index + 1);
+        map[decodeQueryComponent(key, encoding: encoding)] =
+            decodeQueryComponent(value, encoding: encoding);
+      }
+      return map;
+    });
+  }
+
+  /**
+   * Parse the [host] as an IP version 4 (IPv4) address, returning the address
+   * as a list of 4 bytes in network byte order (big endian).
+   *
+   * Throws a [FormatException] if [host] is not a valid IPv4 address
+   * representation.
+   */
+  static List<int> parseIPv4Address(String host) =>
+      _parseIPv4Address(host, 0, host.length);
+
+  /// Implementation of [parseIPv4Address] that can work on a substring.
+  static List<int> _parseIPv4Address(String host, int start, int end) {
+    void error(String msg, int position) {
+      throw FormatException('Illegal IPv4 address, $msg', host, position);
+    }
+
+    var result = Uint8List(4);
+    int partIndex = 0;
+    int partStart = start;
+    for (int i = start; i < end; i++) {
+      int char = host.codeUnitAt(i);
+      if (char != _DOT) {
+        if (char ^ 0x30 > 9) {
+          // Fail on a non-digit character.
+          error("invalid character", i);
+        }
+      } else {
+        if (partIndex == 3) {
+          error('IPv4 address should contain exactly 4 parts', i);
+        }
+        int part = int.parse(host.substring(partStart, i));
+        if (part > 255) {
+          error("each part must be in the range 0..255", partStart);
+        }
+        result[partIndex++] = part;
+        partStart = i + 1;
+      }
+    }
+
+    if (partIndex != 3) {
+      error('IPv4 address should contain exactly 4 parts', end);
+    }
+
+    int part = int.parse(host.substring(partStart, end));
+    if (part > 255) {
+      error("each part must be in the range 0..255", partStart);
+    }
+    result[partIndex] = part;
+
+    return result;
+  }
+
+  /**
+   * Parse the [host] as an IP version 6 (IPv6) address, returning the address
+   * as a list of 16 bytes in network byte order (big endian).
+   *
+   * Throws a [FormatException] if [host] is not a valid IPv6 address
+   * representation.
+   *
+   * Acts on the substring from [start] to [end]. If [end] is omitted, it
+   * defaults ot the end of the string.
+   *
+   * Some examples of IPv6 addresses:
+   *  * `::1`
+   *  * `FEDC:BA98:7654:3210:FEDC:BA98:7654:3210`
+   *  * `3ffe:2a00:100:7031::1`
+   *  * `::FFFF:129.144.52.38`
+   *  * `2010:836B:4179::836B:4179`
+   */
+  static List<int> parseIPv6Address(String host, [int start = 0, int end]) {
+    end ??= host.length;
+    // An IPv6 address consists of exactly 8 parts of 1-4 hex digits, separated
+    // by `:`'s, with the following exceptions:
+    //
+    //  - One (and only one) wildcard (`::`) may be present, representing a fill
+    //    of 0's. The IPv6 `::` is thus 16 bytes of `0`.
+    //  - The last two parts may be replaced by an IPv4 "dotted-quad" address.
+
+    // Helper function for reporting a badly formatted IPv6 address.
+    void error(String msg, [position]) {
+      throw FormatException('Illegal IPv6 address, $msg', host, position);
+    }
+
+    // Parse a hex block.
+    int parseHex(int start, int end) {
+      if (end - start > 4) {
+        error('an IPv6 part can only contain a maximum of 4 hex digits', start);
+      }
+      int value = int.parse(host.substring(start, end), radix: 16);
+      if (value < 0 || value > 0xFFFF) {
+        error('each part must be in the range of `0x0..0xFFFF`', start);
+      }
+      return value;
+    }
+
+    if (host.length < 2) error('address is too short');
+    List<int> parts = [];
+    bool wildcardSeen = false;
+    // Set if seeing a ".", suggesting that there is an IPv4 address.
+    bool seenDot = false;
+    int partStart = start;
+    // Parse all parts, except a potential last one.
+    for (int i = start; i < end; i++) {
+      int char = host.codeUnitAt(i);
+      if (char == _COLON) {
+        if (i == start) {
+          // If we see a `:` in the beginning, expect wildcard.
+          i++;
+          if (host.codeUnitAt(i) != _COLON) {
+            error('invalid start colon.', i);
+          }
+          partStart = i;
+        }
+        if (i == partStart) {
+          // Wildcard. We only allow one.
+          if (wildcardSeen) {
+            error('only one wildcard `::` is allowed', i);
+          }
+          wildcardSeen = true;
+          parts.add(-1);
+        } else {
+          // Found a single colon. Parse [partStart..i] as a hex entry.
+          parts.add(parseHex(partStart, i));
+        }
+        partStart = i + 1;
+      } else if (char == _DOT) {
+        seenDot = true;
+      }
+    }
+    if (parts.length == 0) error('too few parts');
+    bool atEnd = (partStart == end);
+    bool isLastWildcard = (parts.last == -1);
+    if (atEnd && !isLastWildcard) {
+      error('expected a part after last `:`', end);
+    }
+    if (!atEnd) {
+      if (!seenDot) {
+        parts.add(parseHex(partStart, end));
+      } else {
+        List<int> last = _parseIPv4Address(host, partStart, end);
+        parts.add(last[0] << 8 | last[1]);
+        parts.add(last[2] << 8 | last[3]);
+      }
+    }
+    if (wildcardSeen) {
+      if (parts.length > 7) {
+        error('an address with a wildcard must have less than 7 parts');
+      }
+    } else if (parts.length != 8) {
+      error('an address without a wildcard must contain exactly 8 parts');
+    }
+    List<int> bytes = Uint8List(16);
+    for (int i = 0, index = 0; i < parts.length; i++) {
+      int value = parts[i];
+      if (value == -1) {
+        int wildCardLength = 9 - parts.length;
+        for (int j = 0; j < wildCardLength; j++) {
+          bytes[index] = 0;
+          bytes[index + 1] = 0;
+          index += 2;
+        }
+      } else {
+        bytes[index] = value >> 8;
+        bytes[index + 1] = value & 0xff;
+        index += 2;
+      }
+    }
+    return bytes;
+  }
+}
+
+class _Uri implements Uri {
+  // We represent the missing scheme as an empty string.
+  // A valid scheme cannot be empty.
+  final String scheme;
+
+  /**
+   * The user-info part of the authority.
+   *
+   * Does not distinguish between an empty user-info and an absent one.
+   * The value is always non-null.
+   * Is considered absent if [_host] is `null`.
+   */
+  final String _userInfo;
+
+  /**
+   * The host name of the URI.
+   *
+   * Set to `null` if there is no authority in the URI.
+   * The host name is the only mandatory part of an authority, so we use
+   * it to mark whether an authority part was present or not.
+   */
+  final String _host;
+
+  /**
+   * The port number part of the authority.
+   *
+   * The port. Set to null if there is no port. Normalized to null if
+   * the port is the default port for the scheme.
+   */
+  int _port;
+
+  /**
+   * The path of the URI.
+   *
+   * Always non-null.
+   */
+  final String path;
+
+  // The query content, or null if there is no query.
+  final String _query;
+
+  // The fragment content, or null if there is no fragment.
+  final String _fragment;
+
+  /**
+   * Cache the computed return value of [pathSegments].
+   */
+  List<String> _pathSegments;
+
+  /**
+   * Cache of the full normalized text representation of the URI.
+   */
+  String _text;
+
+  /**
+   * Cache of the hashCode of [_text].
+   *
+   * Is null until computed.
+   */
+  int _hashCodeCache;
+
+  /**
+   * Cache the computed return value of [queryParameters].
+   */
+  Map<String, String> _queryParameters;
+  Map<String, List<String>> _queryParameterLists;
+
+  /// Internal non-verifying constructor. Only call with validated arguments.
+  ///
+  /// The components must be properly normalized.
+  ///
+  /// Use `null` for [_host] if there is no authority. In that case, always
+  /// pass `null` for [_port] and [_userInfo] as well.
+  ///
+  /// Use `null` for [_port], [_userInfo], [_query] and [_fragment] if there is
+  /// component of that type.
+  ///
+  /// The [path] and [scheme] are never empty.
+  _Uri._internal(this.scheme, this._userInfo, this._host, this._port, this.path,
+      this._query, this._fragment);
+
+  /// Create a [_Uri] from parts of [uri].
+  ///
+  /// The parameters specify the start/end of particular components of the URI.
+  /// The [scheme] may contain a string representing a normalized scheme
+  /// component if one has already been discovered.
+  factory _Uri.notSimple(
+      String uri,
+      int start,
+      int end,
+      int schemeEnd,
+      int hostStart,
+      int portStart,
+      int pathStart,
+      int queryStart,
+      int fragmentStart,
+      String scheme) {
+    if (scheme == null) {
+      scheme = "";
+      if (schemeEnd > start) {
+        scheme = _makeScheme(uri, start, schemeEnd);
+      } else if (schemeEnd == start) {
+        _fail(uri, start, "Invalid empty scheme");
+      }
+    }
+    String userInfo = "";
+    String host;
+    int port;
+    if (hostStart > start) {
+      int userInfoStart = schemeEnd + 3;
+      if (userInfoStart < hostStart) {
+        userInfo = _makeUserInfo(uri, userInfoStart, hostStart - 1);
+      }
+      host = _makeHost(uri, hostStart, portStart, false);
+      if (portStart + 1 < pathStart) {
+        // Should throw because invalid.
+        port = int.parse(uri.substring(portStart + 1, pathStart), onError: (_) {
+          throw FormatException("Invalid port", uri, portStart + 1);
+        });
+        port = _makePort(port, scheme);
+      }
+    }
+    String path =
+        _makePath(uri, pathStart, queryStart, null, scheme, host != null);
+    String query;
+    if (queryStart < fragmentStart) {
+      query = _makeQuery(uri, queryStart + 1, fragmentStart, null);
+    }
+    String fragment;
+    if (fragmentStart < end) {
+      fragment = _makeFragment(uri, fragmentStart + 1, end);
+    }
+    return _Uri._internal(scheme, userInfo, host, port, path, query, fragment);
+  }
+
+  /// Implementation of [Uri.Uri].
+  factory _Uri(
+      {String scheme,
+      String userInfo,
+      String host,
+      int port,
+      String path,
+      Iterable<String> pathSegments,
+      String query,
+      Map<String, dynamic /*String|Iterable<String>*/ > queryParameters,
+      String fragment}) {
+    scheme = _makeScheme(scheme, 0, _stringOrNullLength(scheme));
+    userInfo = _makeUserInfo(userInfo, 0, _stringOrNullLength(userInfo));
+    host = _makeHost(host, 0, _stringOrNullLength(host), false);
+    // Special case this constructor for backwards compatibility.
+    if (query == "") query = null;
+    query = _makeQuery(query, 0, _stringOrNullLength(query), queryParameters);
+    fragment = _makeFragment(fragment, 0, _stringOrNullLength(fragment));
+    port = _makePort(port, scheme);
+    bool isFile = (scheme == "file");
+    if (host == null && (userInfo.isNotEmpty || port != null || isFile)) {
+      host = "";
+    }
+    bool hasAuthority = (host != null);
+    path = _makePath(
+        path, 0, _stringOrNullLength(path), pathSegments, scheme, hasAuthority);
+    if (scheme.isEmpty && host == null && !path.startsWith('/')) {
+      bool allowScheme = scheme.isNotEmpty || host != null;
+      path = _normalizeRelativePath(path, allowScheme);
+    } else {
+      path = _removeDotSegments(path);
+    }
+    if (host == null && path.startsWith("//")) {
+      host = "";
+    }
+    return _Uri._internal(scheme, userInfo, host, port, path, query, fragment);
+  }
+
+  /// Implementation of [Uri.http].
+  factory _Uri.http(String authority, String unencodedPath,
+      [Map<String, String> queryParameters]) {
+    return _makeHttpUri("http", authority, unencodedPath, queryParameters);
+  }
+
+  /// Implementation of [Uri.https].
+  factory _Uri.https(String authority, String unencodedPath,
+      [Map<String, String> queryParameters]) {
+    return _makeHttpUri("https", authority, unencodedPath, queryParameters);
+  }
+
+  String get authority {
+    if (!hasAuthority) return "";
+    var sb = StringBuffer();
+    _writeAuthority(sb);
+    return sb.toString();
+  }
+
+  String get userInfo => _userInfo;
+
+  String get host {
+    if (_host == null) return "";
+    if (_host.startsWith('[')) {
+      return _host.substring(1, _host.length - 1);
+    }
+    return _host;
+  }
+
+  int get port {
+    if (_port == null) return _defaultPort(scheme);
+    return _port;
+  }
+
+  // The default port for the scheme of this Uri.
+  static int _defaultPort(String scheme) {
+    if (scheme == "http") return 80;
+    if (scheme == "https") return 443;
+    return 0;
+  }
+
+  String get query => _query ?? "";
+
+  String get fragment => _fragment ?? "";
+
+  bool isScheme(String scheme) {
+    String thisScheme = this.scheme;
+    if (scheme == null) return thisScheme.isEmpty;
+    if (scheme.length != thisScheme.length) return false;
+    return _compareScheme(scheme, thisScheme);
+  }
+
+  /// Compares scheme characters in [scheme] and at the start of [uri].
+  ///
+  /// Returns `true` if [scheme] represents the same scheme as the start of
+  /// [uri]. That means having the same characters, but possibly different case
+  /// for letters.
+  ///
+  /// This function doesn't check that the characters are valid URI scheme
+  /// characters. The [uri] is assumed to be valid, so if [scheme] matches
+  /// it, it has to be valid too.
+  ///
+  /// The length should be tested before calling this function,
+  /// so the scheme part of [uri] is known to have the same length as [scheme].
+  static bool _compareScheme(String scheme, String uri) {
+    for (int i = 0; i < scheme.length; i++) {
+      int schemeChar = scheme.codeUnitAt(i);
+      int uriChar = uri.codeUnitAt(i);
+      int delta = schemeChar ^ uriChar;
+      if (delta != 0) {
+        if (delta == 0x20) {
+          // Might be a case difference.
+          int lowerChar = uriChar | delta;
+          if (0x61 /*a*/ <= lowerChar && lowerChar <= 0x7a /*z*/) {
+            continue;
+          }
+        }
+        return false;
+      }
+    }
+    return true;
+  }
+
+  // Report a parse failure.
+  static void _fail(String uri, int index, String message) {
+    throw FormatException(message, uri, index);
+  }
+
+  static Uri _makeHttpUri(String scheme, String authority, String unencodedPath,
+      Map<String, String> queryParameters) {
+    var userInfo = "";
+    String host;
+    int port;
+
+    if (authority != null && authority.isNotEmpty) {
+      var hostStart = 0;
+      // Split off the user info.
+      bool hasUserInfo = false;
+      for (int i = 0; i < authority.length; i++) {
+        const int atSign = 0x40;
+        if (authority.codeUnitAt(i) == atSign) {
+          hasUserInfo = true;
+          userInfo = authority.substring(0, i);
+          hostStart = i + 1;
+          break;
+        }
+      }
+      var hostEnd = hostStart;
+      if (hostStart < authority.length &&
+          authority.codeUnitAt(hostStart) == _LEFT_BRACKET) {
+        // IPv6 host.
+        int escapeForZoneID = -1;
+        for (; hostEnd < authority.length; hostEnd++) {
+          int char = authority.codeUnitAt(hostEnd);
+          if (char == _PERCENT && escapeForZoneID < 0) {
+            escapeForZoneID = hostEnd;
+            if (authority.startsWith("25", hostEnd + 1)) {
+              hostEnd += 2; // Might as well skip the already checked escape.
+            }
+          } else if (char == _RIGHT_BRACKET) {
+            break;
+          }
+        }
+        if (hostEnd == authority.length) {
+          throw FormatException(
+              "Invalid IPv6 host entry.", authority, hostStart);
+        }
+        Uri.parseIPv6Address(authority, hostStart + 1,
+            (escapeForZoneID < 0) ? hostEnd : escapeForZoneID);
+        hostEnd++; // Skip the closing bracket.
+        if (hostEnd != authority.length &&
+            authority.codeUnitAt(hostEnd) != _COLON) {
+          throw FormatException("Invalid end of authority", authority, hostEnd);
+        }
+      }
+      // Split host and port.
+      bool hasPort = false;
+      for (; hostEnd < authority.length; hostEnd++) {
+        if (authority.codeUnitAt(hostEnd) == _COLON) {
+          var portString = authority.substring(hostEnd + 1);
+          // We allow the empty port - falling back to initial value.
+          if (portString.isNotEmpty) port = int.parse(portString);
+          break;
+        }
+      }
+      host = authority.substring(hostStart, hostEnd);
+    }
+    return Uri(
+        scheme: scheme,
+        userInfo: userInfo,
+        host: host,
+        port: port,
+        pathSegments: unencodedPath.split("/"),
+        queryParameters: queryParameters);
+  }
+
+  /// Implementation of [Uri.file].
+  factory _Uri.file(String path, {bool windows}) {
+    windows = (windows == null) ? _Uri._isWindows : windows;
+    return windows
+        ? _makeWindowsFileUrl(path, false)
+        : _makeFileUri(path, false);
+  }
+
+  /// Implementation of [Uri.directory].
+  factory _Uri.directory(String path, {bool windows}) {
+    windows = (windows == null) ? _Uri._isWindows : windows;
+    return windows ? _makeWindowsFileUrl(path, true) : _makeFileUri(path, true);
+  }
+
+  /// Used internally in path-related constructors.
+  external static bool get _isWindows;
+
+  static _checkNonWindowsPathReservedCharacters(
+      List<String> segments, bool argumentError) {
+    segments.forEach((segment) {
+      if (segment.contains("/")) {
+        if (argumentError) {
+          throw ArgumentError("Illegal path character $segment");
+        } else {
+          throw UnsupportedError("Illegal path character $segment");
+        }
+      }
+    });
+  }
+
+  static _checkWindowsPathReservedCharacters(
+      List<String> segments, bool argumentError,
+      [int firstSegment = 0]) {
+    for (var segment in segments.skip(firstSegment)) {
+      if (segment.contains(RegExp(r'["*/:<>?\\|]'))) {
+        if (argumentError) {
+          throw ArgumentError("Illegal character in path");
+        } else {
+          throw UnsupportedError("Illegal character in path: $segment");
+        }
+      }
+    }
+  }
+
+  static _checkWindowsDriveLetter(int charCode, bool argumentError) {
+    if ((_UPPER_CASE_A <= charCode && charCode <= _UPPER_CASE_Z) ||
+        (_LOWER_CASE_A <= charCode && charCode <= _LOWER_CASE_Z)) {
+      return;
+    }
+    if (argumentError) {
+      throw ArgumentError(
+          "Illegal drive letter " + String.fromCharCode(charCode));
+    } else {
+      throw UnsupportedError(
+          "Illegal drive letter " + String.fromCharCode(charCode));
+    }
+  }
+
+  static _makeFileUri(String path, bool slashTerminated) {
+    const String sep = "/";
+    var segments = path.split(sep);
+    if (slashTerminated && segments.isNotEmpty && segments.last.isNotEmpty) {
+      segments.add(""); // Extra separator at end.
+    }
+    if (path.startsWith(sep)) {
+      // Absolute file:// URI.
+      return Uri(scheme: "file", pathSegments: segments);
+    } else {
+      // Relative URI.
+      return Uri(pathSegments: segments);
+    }
+  }
+
+  static _makeWindowsFileUrl(String path, bool slashTerminated) {
+    if (path.startsWith(r"\\?\")) {
+      if (path.startsWith(r"UNC\", 4)) {
+        path = path.replaceRange(0, 7, r'\');
+      } else {
+        path = path.substring(4);
+        if (path.length < 3 ||
+            path.codeUnitAt(1) != _COLON ||
+            path.codeUnitAt(2) != _BACKSLASH) {
+          throw ArgumentError(
+              r"Windows paths with \\?\ prefix must be absolute");
+        }
+      }
+    } else {
+      path = path.replaceAll("/", r'\');
+    }
+    const String sep = r'\';
+    if (path.length > 1 && path.codeUnitAt(1) == _COLON) {
+      _checkWindowsDriveLetter(path.codeUnitAt(0), true);
+      if (path.length == 2 || path.codeUnitAt(2) != _BACKSLASH) {
+        throw ArgumentError("Windows paths with drive letter must be absolute");
+      }
+      // Absolute file://C:/ URI.
+      var pathSegments = path.split(sep);
+      if (slashTerminated && pathSegments.last.isNotEmpty) {
+        pathSegments.add(""); // Extra separator at end.
+      }
+      _checkWindowsPathReservedCharacters(pathSegments, true, 1);
+      return Uri(scheme: "file", pathSegments: pathSegments);
+    }
+
+    if (path.startsWith(sep)) {
+      if (path.startsWith(sep, 1)) {
+        // Absolute file:// URI with host.
+        int pathStart = path.indexOf(r'\', 2);
+        String hostPart =
+            (pathStart < 0) ? path.substring(2) : path.substring(2, pathStart);
+        String pathPart = (pathStart < 0) ? "" : path.substring(pathStart + 1);
+        var pathSegments = pathPart.split(sep);
+        _checkWindowsPathReservedCharacters(pathSegments, true);
+        if (slashTerminated && pathSegments.last.isNotEmpty) {
+          pathSegments.add(""); // Extra separator at end.
+        }
+        return Uri(scheme: "file", host: hostPart, pathSegments: pathSegments);
+      } else {
+        // Absolute file:// URI.
+        var pathSegments = path.split(sep);
+        if (slashTerminated && pathSegments.last.isNotEmpty) {
+          pathSegments.add(""); // Extra separator at end.
+        }
+        _checkWindowsPathReservedCharacters(pathSegments, true);
+        return Uri(scheme: "file", pathSegments: pathSegments);
+      }
+    } else {
+      // Relative URI.
+      var pathSegments = path.split(sep);
+      _checkWindowsPathReservedCharacters(pathSegments, true);
+      if (slashTerminated &&
+          pathSegments.isNotEmpty &&
+          pathSegments.last.isNotEmpty) {
+        pathSegments.add(""); // Extra separator at end.
+      }
+      return Uri(pathSegments: pathSegments);
+    }
+  }
+
+  Uri replace(
+      {String scheme,
+      String userInfo,
+      String host,
+      int port,
+      String path,
+      Iterable<String> pathSegments,
+      String query,
+      Map<String, dynamic /*String|Iterable<String>*/ > queryParameters,
+      String fragment}) {
+    // Set to true if the scheme has (potentially) changed.
+    // In that case, the default port may also have changed and we need
+    // to check even the existing port.
+    bool schemeChanged = false;
+    if (scheme != null) {
+      scheme = _makeScheme(scheme, 0, scheme.length);
+      schemeChanged = (scheme != this.scheme);
+    } else {
+      scheme = this.scheme;
+    }
+    bool isFile = (scheme == "file");
+    if (userInfo != null) {
+      userInfo = _makeUserInfo(userInfo, 0, userInfo.length);
+    } else {
+      userInfo = this._userInfo;
+    }
+    if (port != null) {
+      port = _makePort(port, scheme);
+    } else {
+      port = this._port;
+      if (schemeChanged) {
+        // The default port might have changed.
+        port = _makePort(port, scheme);
+      }
+    }
+    if (host != null) {
+      host = _makeHost(host, 0, host.length, false);
+    } else if (this.hasAuthority) {
+      host = this._host;
+    } else if (userInfo.isNotEmpty || port != null || isFile) {
+      host = "";
+    }
+
+    bool hasAuthority = host != null;
+    if (path != null || pathSegments != null) {
+      path = _makePath(path, 0, _stringOrNullLength(path), pathSegments, scheme,
+          hasAuthority);
+    } else {
+      path = this.path;
+      if ((isFile || (hasAuthority && !path.isEmpty)) &&
+          !path.startsWith('/')) {
+        path = "/" + path;
+      }
+    }
+
+    if (query != null || queryParameters != null) {
+      query = _makeQuery(query, 0, _stringOrNullLength(query), queryParameters);
+    } else {
+      query = this._query;
+    }
+
+    if (fragment != null) {
+      fragment = _makeFragment(fragment, 0, fragment.length);
+    } else {
+      fragment = this._fragment;
+    }
+
+    return _Uri._internal(scheme, userInfo, host, port, path, query, fragment);
+  }
+
+  Uri removeFragment() {
+    if (!this.hasFragment) return this;
+    return _Uri._internal(scheme, _userInfo, _host, _port, path, _query, null);
+  }
+
+  List<String> get pathSegments {
+    var result = _pathSegments;
+    if (result != null) return result;
+
+    var pathToSplit = path;
+    if (pathToSplit.isNotEmpty && pathToSplit.codeUnitAt(0) == _SLASH) {
+      pathToSplit = pathToSplit.substring(1);
+    }
+    result = (pathToSplit == "")
+        ? const <String>[]
+        : List<String>.unmodifiable(
+            pathToSplit.split("/").map(Uri.decodeComponent));
+    _pathSegments = result;
+    return result;
+  }
+
+  Map<String, String> get queryParameters {
+    _queryParameters ??=
+        UnmodifiableMapView<String, String>(Uri.splitQueryString(query));
+    return _queryParameters;
+  }
+
+  Map<String, List<String>> get queryParametersAll {
+    if (_queryParameterLists == null) {
+      Map queryParameterLists = _splitQueryStringAll(query);
+      for (var key in queryParameterLists.keys) {
+        queryParameterLists[key] =
+            List<String>.unmodifiable(queryParameterLists[key]);
+      }
+      _queryParameterLists =
+          Map<String, List<String>>.unmodifiable(queryParameterLists);
+    }
+    return _queryParameterLists;
+  }
+
+  Uri normalizePath() {
+    String path = _normalizePath(this.path, scheme, hasAuthority);
+    if (identical(path, this.path)) return this;
+    return this.replace(path: path);
+  }
+
+  static int _makePort(int port, String scheme) {
+    // Perform scheme specific normalization.
+    if (port != null && port == _defaultPort(scheme)) return null;
+    return port;
+  }
+
+  /**
+   * Check and normalize a host name.
+   *
+   * If the host name starts and ends with '[' and ']', it is considered an
+   * IPv6 address. If [strictIPv6] is false, the address is also considered
+   * an IPv6 address if it contains any ':' character.
+   *
+   * If it is not an IPv6 address, it is case- and escape-normalized.
+   * This escapes all characters not valid in a reg-name,
+   * and converts all non-escape upper-case letters to lower-case.
+   */
+  static String _makeHost(String host, int start, int end, bool strictIPv6) {
+    // TODO(lrn): Should we normalize IPv6 addresses according to RFC 5952?
+    if (host == null) return null;
+    if (start == end) return "";
+    // Host is an IPv6 address if it starts with '[' or contains a colon.
+    if (host.codeUnitAt(start) == _LEFT_BRACKET) {
+      if (host.codeUnitAt(end - 1) != _RIGHT_BRACKET) {
+        _fail(host, start, 'Missing end `]` to match `[` in host');
+      }
+      String zoneID = "";
+      int index = _checkZoneID(host, start + 1, end - 1);
+      if (index < end - 1) {
+        int zoneIDstart =
+            (host.startsWith("25", index + 1)) ? index + 3 : index + 1;
+        zoneID = _normalizeZoneID(host, zoneIDstart, end - 1, "%25");
+      }
+      Uri.parseIPv6Address(host, start + 1, index);
+      // RFC 5952 requires hex digits to be lower case.
+      return host.substring(start, index).toLowerCase() + zoneID + ']';
+    }
+    if (!strictIPv6) {
+      // TODO(lrn): skip if too short to be a valid IPv6 address?
+      for (int i = start; i < end; i++) {
+        if (host.codeUnitAt(i) == _COLON) {
+          String zoneID = "";
+          int index = _checkZoneID(host, start, end);
+          if (index < end) {
+            int zoneIDstart =
+                (host.startsWith("25", index + 1)) ? index + 3 : index + 1;
+            zoneID = _normalizeZoneID(host, zoneIDstart, end, "%25");
+          }
+          Uri.parseIPv6Address(host, start, index);
+          return '[${host.substring(start, index)}' + zoneID + ']';
+        }
+      }
+    }
+    return _normalizeRegName(host, start, end);
+  }
+
+  // RFC 6874 check for ZoneID
+  // Return the index of first appeared `%`.
+  static int _checkZoneID(String host, int start, int end) {
+    int index = host.indexOf('%', start);
+    index = (index >= start && index < end) ? index : end;
+    return index;
+  }
+
+  static bool _isZoneIDChar(int char) {
+    return char < 127 && (_zoneIDTable[char >> 4] & (1 << (char & 0xf))) != 0;
+  }
+
+  /**
+   * Validates and does case- and percent-encoding normalization.
+   *
+   * The same as [_normalizeOrSubstring]
+   * except this function does not convert characters to lower case.
+   * The [host] must be an RFC6874 "ZoneID".
+   * ZoneID = 1*(unreserved / pct-encoded)
+   */
+  static String _normalizeZoneID(String host, int start, int end,
+      [String prefix = '']) {
+    StringBuffer buffer;
+    if (prefix != '') {
+      buffer = StringBuffer(prefix);
+    }
+    int sectionStart = start;
+    int index = start;
+    // Whether all characters between sectionStart and index are normalized,
+    bool isNormalized = true;
+
+    while (index < end) {
+      int char = host.codeUnitAt(index);
+      if (char == _PERCENT) {
+        String replacement = _normalizeEscape(host, index, true);
+        if (replacement == null && isNormalized) {
+          index += 3;
+          continue;
+        }
+        buffer ??= StringBuffer();
+        String slice = host.substring(sectionStart, index);
+        buffer.write(slice);
+        int sourceLength = 3;
+        if (replacement == null) {
+          replacement = host.substring(index, index + 3);
+        } else if (replacement == "%") {
+          _fail(host, index, "ZoneID should not contain % anymore");
+        }
+        buffer.write(replacement);
+        index += sourceLength;
+        sectionStart = index;
+        isNormalized = true;
+      } else if (_isZoneIDChar(char)) {
+        if (isNormalized && _UPPER_CASE_A <= char && _UPPER_CASE_Z >= char) {
+          // Put initial slice in buffer and continue in non-normalized mode
+          buffer ??= StringBuffer();
+          if (sectionStart < index) {
+            buffer.write(host.substring(sectionStart, index));
+            sectionStart = index;
+          }
+          isNormalized = false;
+        }
+        index++;
+      } else {
+        int sourceLength = 1;
+        if ((char & 0xFC00) == 0xD800 && (index + 1) < end) {
+          int tail = host.codeUnitAt(index + 1);
+          if ((tail & 0xFC00) == 0xDC00) {
+            char = 0x10000 | ((char & 0x3ff) << 10) | (tail & 0x3ff);
+            sourceLength = 2;
+          }
+        }
+        buffer ??= StringBuffer();
+        String slice = host.substring(sectionStart, index);
+        buffer.write(slice);
+        buffer.write(_escapeChar(char));
+        index += sourceLength;
+        sectionStart = index;
+      }
+    }
+    if (buffer == null) return host.substring(start, end);
+    if (sectionStart < end) {
+      String slice = host.substring(sectionStart, end);
+      buffer.write(slice);
+    }
+    return buffer.toString();
+  }
+
+  static bool _isRegNameChar(int char) {
+    return char < 127 && (_regNameTable[char >> 4] & (1 << (char & 0xf))) != 0;
+  }
+
+  /**
+   * Validates and does case- and percent-encoding normalization.
+   *
+   * The [host] must be an RFC3986 "reg-name". It is converted
+   * to lower case, and percent escapes are converted to either
+   * lower case unreserved characters or upper case escapes.
+   */
+  static String _normalizeRegName(String host, int start, int end) {
+    StringBuffer buffer;
+    int sectionStart = start;
+    int index = start;
+    // Whether all characters between sectionStart and index are normalized,
+    bool isNormalized = true;
+
+    while (index < end) {
+      int char = host.codeUnitAt(index);
+      if (char == _PERCENT) {
+        // The _regNameTable contains "%", so we check that first.
+        String replacement = _normalizeEscape(host, index, true);
+        if (replacement == null && isNormalized) {
+          index += 3;
+          continue;
+        }
+        buffer ??= StringBuffer();
+        String slice = host.substring(sectionStart, index);
+        if (!isNormalized) slice = slice.toLowerCase();
+        buffer.write(slice);
+        int sourceLength = 3;
+        if (replacement == null) {
+          replacement = host.substring(index, index + 3);
+        } else if (replacement == "%") {
+          replacement = "%25";
+          sourceLength = 1;
+        }
+        buffer.write(replacement);
+        index += sourceLength;
+        sectionStart = index;
+        isNormalized = true;
+      } else if (_isRegNameChar(char)) {
+        if (isNormalized && _UPPER_CASE_A <= char && _UPPER_CASE_Z >= char) {
+          // Put initial slice in buffer and continue in non-normalized mode
+          buffer ??= StringBuffer();
+          if (sectionStart < index) {
+            buffer.write(host.substring(sectionStart, index));
+            sectionStart = index;
+          }
+          isNormalized = false;
+        }
+        index++;
+      } else if (_isGeneralDelimiter(char)) {
+        _fail(host, index, "Invalid character");
+      } else {
+        int sourceLength = 1;
+        if ((char & 0xFC00) == 0xD800 && (index + 1) < end) {
+          int tail = host.codeUnitAt(index + 1);
+          if ((tail & 0xFC00) == 0xDC00) {
+            char = 0x10000 | ((char & 0x3ff) << 10) | (tail & 0x3ff);
+            sourceLength = 2;
+          }
+        }
+        buffer ??= StringBuffer();
+        String slice = host.substring(sectionStart, index);
+        if (!isNormalized) slice = slice.toLowerCase();
+        buffer.write(slice);
+        buffer.write(_escapeChar(char));
+        index += sourceLength;
+        sectionStart = index;
+      }
+    }
+    if (buffer == null) return host.substring(start, end);
+    if (sectionStart < end) {
+      String slice = host.substring(sectionStart, end);
+      if (!isNormalized) slice = slice.toLowerCase();
+      buffer.write(slice);
+    }
+    return buffer.toString();
+  }
+
+  /**
+   * Validates scheme characters and does case-normalization.
+   *
+   * Schemes are converted to lower case. They cannot contain escapes.
+   */
+  static String _makeScheme(String scheme, int start, int end) {
+    if (start == end) return "";
+    final int firstCodeUnit = scheme.codeUnitAt(start);
+    if (!_isAlphabeticCharacter(firstCodeUnit)) {
+      _fail(scheme, start, "Scheme not starting with alphabetic character");
+    }
+    bool containsUpperCase = false;
+    for (int i = start; i < end; i++) {
+      final int codeUnit = scheme.codeUnitAt(i);
+      if (!_isSchemeCharacter(codeUnit)) {
+        _fail(scheme, i, "Illegal scheme character");
+      }
+      if (_UPPER_CASE_A <= codeUnit && codeUnit <= _UPPER_CASE_Z) {
+        containsUpperCase = true;
+      }
+    }
+    scheme = scheme.substring(start, end);
+    if (containsUpperCase) scheme = scheme.toLowerCase();
+    return _canonicalizeScheme(scheme);
+  }
+
+  // Canonicalize a few often-used scheme strings.
+  //
+  // This improves memory usage and makes comparison faster.
+  static String _canonicalizeScheme(String scheme) {
+    if (scheme == "http") return "http";
+    if (scheme == "file") return "file";
+    if (scheme == "https") return "https";
+    if (scheme == "package") return "package";
+    return scheme;
+  }
+
+  static String _makeUserInfo(String userInfo, int start, int end) {
+    if (userInfo == null) return "";
+    return _normalizeOrSubstring(userInfo, start, end, _userinfoTable);
+  }
+
+  static String _makePath(String path, int start, int end,
+      Iterable<String> pathSegments, String scheme, bool hasAuthority) {
+    bool isFile = (scheme == "file");
+    bool ensureLeadingSlash = isFile || hasAuthority;
+    if (path == null && pathSegments == null) return isFile ? "/" : "";
+    if (path != null && pathSegments != null) {
+      throw ArgumentError('Both path and pathSegments specified');
+    }
+    String result;
+    if (path != null) {
+      result = _normalizeOrSubstring(path, start, end, _pathCharOrSlashTable,
+          escapeDelimiters: true);
+    } else {
+      result = pathSegments
+          .map((s) => _uriEncode(_pathCharTable, s, utf8, false))
+          .join("/");
+    }
+    if (result.isEmpty) {
+      if (isFile) return "/";
+    } else if (ensureLeadingSlash && !result.startsWith('/')) {
+      result = "/" + result;
+    }
+    result = _normalizePath(result, scheme, hasAuthority);
+    return result;
+  }
+
+  /// Performs path normalization (remove dot segments) on a path.
+  ///
+  /// If the URI has neither scheme nor authority, it's considered a
+  /// "pure path" and normalization won't remove leading ".." segments.
+  /// Otherwise it follows the RFC 3986 "remove dot segments" algorithm.
+  static String _normalizePath(String path, String scheme, bool hasAuthority) {
+    if (scheme.isEmpty && !hasAuthority && !path.startsWith('/')) {
+      return _normalizeRelativePath(path, scheme.isNotEmpty || hasAuthority);
+    }
+    return _removeDotSegments(path);
+  }
+
+  static String _makeQuery(String query, int start, int end,
+      Map<String, dynamic /*String|Iterable<String>*/ > queryParameters) {
+    if (query != null) {
+      if (queryParameters != null) {
+        throw ArgumentError('Both query and queryParameters specified');
+      }
+      return _normalizeOrSubstring(query, start, end, _queryCharTable,
+          escapeDelimiters: true);
+    }
+    if (queryParameters == null) return null;
+
+    var result = StringBuffer();
+    var separator = "";
+
+    void writeParameter(String key, String value) {
+      result.write(separator);
+      separator = "&";
+      result.write(Uri.encodeQueryComponent(key));
+      if (value != null && value.isNotEmpty) {
+        result.write("=");
+        result.write(Uri.encodeQueryComponent(value));
+      }
+    }
+
+    queryParameters.forEach((key, value) {
+      if (value == null || value is String) {
+        writeParameter(key, value);
+      } else {
+        Iterable values = value;
+        for (String value in values) {
+          writeParameter(key, value);
+        }
+      }
+    });
+    return result.toString();
+  }
+
+  static String _makeFragment(String fragment, int start, int end) {
+    if (fragment == null) return null;
+    return _normalizeOrSubstring(fragment, start, end, _queryCharTable,
+        escapeDelimiters: true);
+  }
+
+  /**
+   * Performs RFC 3986 Percent-Encoding Normalization.
+   *
+   * Returns a replacement string that should be replace the original escape.
+   * Returns null if no replacement is necessary because the escape is
+   * not for an unreserved character and is already non-lower-case.
+   *
+   * Returns "%" if the escape is invalid (not two valid hex digits following
+   * the percent sign). The calling code should replace the percent
+   * sign with "%25", but leave the following two characters unmodified.
+   *
+   * If [lowerCase] is true, a single character returned is always lower case,
+   */
+  static String _normalizeEscape(String source, int index, bool lowerCase) {
+    assert(source.codeUnitAt(index) == _PERCENT);
+    if (index + 2 >= source.length) {
+      return "%"; // Marks the escape as invalid.
+    }
+    int firstDigit = source.codeUnitAt(index + 1);
+    int secondDigit = source.codeUnitAt(index + 2);
+    int firstDigitValue = hexDigitValue(firstDigit);
+    int secondDigitValue = hexDigitValue(secondDigit);
+    if (firstDigitValue < 0 || secondDigitValue < 0) {
+      return "%"; // Marks the escape as invalid.
+    }
+    int value = firstDigitValue * 16 + secondDigitValue;
+    if (_isUnreservedChar(value)) {
+      if (lowerCase && _UPPER_CASE_A <= value && _UPPER_CASE_Z >= value) {
+        value |= 0x20;
+      }
+      return String.fromCharCode(value);
+    }
+    if (firstDigit >= _LOWER_CASE_A || secondDigit >= _LOWER_CASE_A) {
+      // Either digit is lower case.
+      return source.substring(index, index + 3).toUpperCase();
+    }
+    // Escape is retained, and is already non-lower case, so return null to
+    // represent "no replacement necessary".
+    return null;
+  }
+
+  static String _escapeChar(int char) {
+    assert(char <= 0x10ffff); // It's a valid unicode code point.
+    List<int> codeUnits;
+    if (char < 0x80) {
+      // ASCII, a single percent encoded sequence.
+      codeUnits = List(3);
+      codeUnits[0] = _PERCENT;
+      codeUnits[1] = _hexDigits.codeUnitAt(char >> 4);
+      codeUnits[2] = _hexDigits.codeUnitAt(char & 0xf);
+    } else {
+      // Do UTF-8 encoding of character, then percent encode bytes.
+      int flag = 0xc0; // The high-bit markers on the first byte of UTF-8.
+      int encodedBytes = 2;
+      if (char > 0x7ff) {
+        flag = 0xe0;
+        encodedBytes = 3;
+        if (char > 0xffff) {
+          encodedBytes = 4;
+          flag = 0xf0;
+        }
+      }
+      codeUnits = List(3 * encodedBytes);
+      int index = 0;
+      while (--encodedBytes >= 0) {
+        int byte = ((char >> (6 * encodedBytes)) & 0x3f) | flag;
+        codeUnits[index] = _PERCENT;
+        codeUnits[index + 1] = _hexDigits.codeUnitAt(byte >> 4);
+        codeUnits[index + 2] = _hexDigits.codeUnitAt(byte & 0xf);
+        index += 3;
+        flag = 0x80; // Following bytes have only high bit set.
+      }
+    }
+    return String.fromCharCodes(codeUnits);
+  }
+
+  /**
+   * Normalizes using [_normalize] or returns substring of original.
+   *
+   * If [_normalize] returns `null` (original content is already normalized),
+   * this methods returns the substring if [component] from [start] to [end].
+   */
+  static String _normalizeOrSubstring(
+      String component, int start, int end, List<int> charTable,
+      {bool escapeDelimiters = false}) {
+    return _normalize(component, start, end, charTable,
+            escapeDelimiters: escapeDelimiters) ??
+        component.substring(start, end);
+  }
+
+  /**
+   * Runs through component checking that each character is valid and
+   * normalize percent escapes.
+   *
+   * Uses [charTable] to check if a non-`%` character is allowed.
+   * Each `%` character must be followed by two hex digits.
+   * If the hex-digits are lower case letters, they are converted to
+   * upper case.
+   *
+   * Returns `null` if the original content was already normalized.
+   */
+  static String _normalize(
+      String component, int start, int end, List<int> charTable,
+      {bool escapeDelimiters = false}) {
+    StringBuffer buffer;
+    int sectionStart = start;
+    int index = start;
+    // Loop while characters are valid and escapes correct and upper-case.
+    while (index < end) {
+      int char = component.codeUnitAt(index);
+      if (char < 127 && (charTable[char >> 4] & (1 << (char & 0x0f))) != 0) {
+        index++;
+      } else {
+        String replacement;
+        int sourceLength;
+        if (char == _PERCENT) {
+          replacement = _normalizeEscape(component, index, false);
+          // Returns null if we should keep the existing escape.
+          if (replacement == null) {
+            index += 3;
+            continue;
+          }
+          // Returns "%" if we should escape the existing percent.
+          if ("%" == replacement) {
+            replacement = "%25";
+            sourceLength = 1;
+          } else {
+            sourceLength = 3;
+          }
+        } else if (!escapeDelimiters && _isGeneralDelimiter(char)) {
+          _fail(component, index, "Invalid character");
+        } else {
+          sourceLength = 1;
+          if ((char & 0xFC00) == 0xD800) {
+            // Possible lead surrogate.
+            if (index + 1 < end) {
+              int tail = component.codeUnitAt(index + 1);
+              if ((tail & 0xFC00) == 0xDC00) {
+                // Tail surrogate.
+                sourceLength = 2;
+                char = 0x10000 | ((char & 0x3ff) << 10) | (tail & 0x3ff);
+              }
+            }
+          }
+          replacement = _escapeChar(char);
+        }
+        buffer ??= StringBuffer();
+        buffer.write(component.substring(sectionStart, index));
+        buffer.write(replacement);
+        index += sourceLength;
+        sectionStart = index;
+      }
+    }
+    if (buffer == null) {
+      return null;
+    }
+    if (sectionStart < end) {
+      buffer.write(component.substring(sectionStart, end));
+    }
+    return buffer.toString();
+  }
+
+  static bool _isSchemeCharacter(int ch) {
+    return ch < 128 && ((_schemeTable[ch >> 4] & (1 << (ch & 0x0f))) != 0);
+  }
+
+  static bool _isGeneralDelimiter(int ch) {
+    return ch <= _RIGHT_BRACKET &&
+        ((_genDelimitersTable[ch >> 4] & (1 << (ch & 0x0f))) != 0);
+  }
+
+  /**
+   * Returns whether the URI is absolute.
+   */
+  bool get isAbsolute => scheme != "" && fragment == "";
+
+  String _mergePaths(String base, String reference) {
+    // Optimize for the case: absolute base, reference beginning with "../".
+    int backCount = 0;
+    int refStart = 0;
+    // Count number of "../" at beginning of reference.
+    while (reference.startsWith("../", refStart)) {
+      refStart += 3;
+      backCount++;
+    }
+
+    // Drop last segment - everything after last '/' of base.
+    int baseEnd = base.lastIndexOf('/');
+    // Drop extra segments for each leading "../" of reference.
+    while (baseEnd > 0 && backCount > 0) {
+      int newEnd = base.lastIndexOf('/', baseEnd - 1);
+      if (newEnd < 0) {
+        break;
+      }
+      int delta = baseEnd - newEnd;
+      // If we see a "." or ".." segment in base, stop here and let
+      // _removeDotSegments handle it.
+      if ((delta == 2 || delta == 3) &&
+          base.codeUnitAt(newEnd + 1) == _DOT &&
+          (delta == 2 || base.codeUnitAt(newEnd + 2) == _DOT)) {
+        break;
+      }
+      baseEnd = newEnd;
+      backCount--;
+    }
+    return base.replaceRange(
+        baseEnd + 1, null, reference.substring(refStart - 3 * backCount));
+  }
+
+  /// Make a guess at whether a path contains a `..` or `.` segment.
+  ///
+  /// This is a primitive test that can cause false positives.
+  /// It's only used to avoid a more expensive operation in the case where
+  /// it's not necessary.
+  static bool _mayContainDotSegments(String path) {
+    if (path.startsWith('.')) return true;
+    int index = path.indexOf("/.");
+    return index != -1;
+  }
+
+  /// Removes '.' and '..' segments from a path.
+  ///
+  /// Follows the RFC 2986 "remove dot segments" algorithm.
+  /// This algorithm is only used on paths of URIs with a scheme,
+  /// and it treats the path as if it is absolute (leading '..' are removed).
+  static String _removeDotSegments(String path) {
+    if (!_mayContainDotSegments(path)) return path;
+    assert(path.isNotEmpty); // An empty path would not have dot segments.
+    List<String> output = [];
+    bool appendSlash = false;
+    for (String segment in path.split("/")) {
+      appendSlash = false;
+      if (segment == "..") {
+        if (output.isNotEmpty) {
+          output.removeLast();
+          if (output.isEmpty) {
+            output.add("");
+          }
+        }
+        appendSlash = true;
+      } else if ("." == segment) {
+        appendSlash = true;
+      } else {
+        output.add(segment);
+      }
+    }
+    if (appendSlash) output.add("");
+    return output.join("/");
+  }
+
+  /// Removes all `.` segments and any non-leading `..` segments.
+  ///
+  /// If the path starts with something that looks like a scheme,
+  /// and [allowScheme] is false, the colon is escaped.
+  ///
+  /// Removing the ".." from a "bar/foo/.." sequence results in "bar/"
+  /// (trailing "/"). If the entire path is removed (because it contains as
+  /// many ".." segments as real segments), the result is "./".
+  /// This is different from an empty string, which represents "no path",
+  /// when you resolve it against a base URI with a path with a non-empty
+  /// final segment.
+  static String _normalizeRelativePath(String path, bool allowScheme) {
+    assert(!path.startsWith('/')); // Only get called for relative paths.
+    if (!_mayContainDotSegments(path)) {
+      if (!allowScheme) path = _escapeScheme(path);
+      return path;
+    }
+    assert(path.isNotEmpty); // An empty path would not have dot segments.
+    List<String> output = [];
+    bool appendSlash = false;
+    for (String segment in path.split("/")) {
+      appendSlash = false;
+      if (".." == segment) {
+        if (!output.isEmpty && output.last != "..") {
+          output.removeLast();
+          appendSlash = true;
+        } else {
+          output.add("..");
+        }
+      } else if ("." == segment) {
+        appendSlash = true;
+      } else {
+        output.add(segment);
+      }
+    }
+    if (output.isEmpty || (output.length == 1 && output[0].isEmpty)) {
+      return "./";
+    }
+    if (appendSlash || output.last == '..') output.add("");
+    if (!allowScheme) output[0] = _escapeScheme(output[0]);
+    return output.join("/");
+  }
+
+  /// If [path] starts with a valid scheme, escape the percent.
+  static String _escapeScheme(String path) {
+    if (path.length >= 2 && _isAlphabeticCharacter(path.codeUnitAt(0))) {
+      for (int i = 1; i < path.length; i++) {
+        int char = path.codeUnitAt(i);
+        if (char == _COLON) {
+          return "${path.substring(0, i)}%3A${path.substring(i + 1)}";
+        }
+        if (char > 127 ||
+            ((_schemeTable[char >> 4] & (1 << (char & 0x0f))) == 0)) {
+          break;
+        }
+      }
+    }
+    return path;
+  }
+
+  Uri resolve(String reference) {
+    return resolveUri(Uri.parse(reference));
+  }
+
+  Uri resolveUri(Uri reference) {
+    // From RFC 3986.
+    String targetScheme;
+    String targetUserInfo = "";
+    String targetHost;
+    int targetPort;
+    String targetPath;
+    String targetQuery;
+    if (reference.scheme.isNotEmpty) {
+      targetScheme = reference.scheme;
+      if (reference.hasAuthority) {
+        targetUserInfo = reference.userInfo;
+        targetHost = reference.host;
+        targetPort = reference.hasPort ? reference.port : null;
+      }
+      targetPath = _removeDotSegments(reference.path);
+      if (reference.hasQuery) {
+        targetQuery = reference.query;
+      }
+    } else {
+      targetScheme = this.scheme;
+      if (reference.hasAuthority) {
+        targetUserInfo = reference.userInfo;
+        targetHost = reference.host;
+        targetPort =
+            _makePort(reference.hasPort ? reference.port : null, targetScheme);
+        targetPath = _removeDotSegments(reference.path);
+        if (reference.hasQuery) targetQuery = reference.query;
+      } else {
+        targetUserInfo = this._userInfo;
+        targetHost = this._host;
+        targetPort = this._port;
+        if (reference.path == "") {
+          targetPath = this.path;
+          if (reference.hasQuery) {
+            targetQuery = reference.query;
+          } else {
+            targetQuery = this._query;
+          }
+        } else {
+          if (reference.hasAbsolutePath) {
+            targetPath = _removeDotSegments(reference.path);
+          } else {
+            // This is the RFC 3986 behavior for merging.
+            if (this.hasEmptyPath) {
+              if (!this.hasAuthority) {
+                if (!this.hasScheme) {
+                  // Keep the path relative if no scheme or authority.
+                  targetPath = reference.path;
+                } else {
+                  // Remove leading dot-segments if the path is put
+                  // beneath a scheme.
+                  targetPath = _removeDotSegments(reference.path);
+                }
+              } else {
+                // RFC algorithm for base with authority and empty path.
+                targetPath = _removeDotSegments("/" + reference.path);
+              }
+            } else {
+              var mergedPath = _mergePaths(this.path, reference.path);
+              if (this.hasScheme || this.hasAuthority || this.hasAbsolutePath) {
+                targetPath = _removeDotSegments(mergedPath);
+              } else {
+                // Non-RFC 3986 behavior.
+                // If both base and reference are relative paths,
+                // allow the merged path to start with "..".
+                // The RFC only specifies the case where the base has a scheme.
+                targetPath = _normalizeRelativePath(
+                    mergedPath, this.hasScheme || this.hasAuthority);
+              }
+            }
+          }
+          if (reference.hasQuery) targetQuery = reference.query;
+        }
+      }
+    }
+    String fragment = reference.hasFragment ? reference.fragment : null;
+    return _Uri._internal(targetScheme, targetUserInfo, targetHost, targetPort,
+        targetPath, targetQuery, fragment);
+  }
+
+  bool get hasScheme => scheme.isNotEmpty;
+
+  bool get hasAuthority => _host != null;
+
+  bool get hasPort => _port != null;
+
+  bool get hasQuery => _query != null;
+
+  bool get hasFragment => _fragment != null;
+
+  bool get hasEmptyPath => path.isEmpty;
+
+  bool get hasAbsolutePath => path.startsWith('/');
+
+  String get origin {
+    if (scheme == "") {
+      throw StateError("Cannot use origin without a scheme: $this");
+    }
+    if (scheme != "http" && scheme != "https") {
+      throw StateError(
+          "Origin is only applicable schemes http and https: $this");
+    }
+    if (_host == null || _host == "") {
+      throw StateError(
+          "A $scheme: URI should have a non-empty host name: $this");
+    }
+    if (_port == null) return "$scheme://$_host";
+    return "$scheme://$_host:$_port";
+  }
+
+  String toFilePath({bool windows}) {
+    if (scheme != "" && scheme != "file") {
+      throw UnsupportedError("Cannot extract a file path from a $scheme URI");
+    }
+    if (query != "") {
+      throw UnsupportedError(
+          "Cannot extract a file path from a URI with a query component");
+    }
+    if (fragment != "") {
+      throw UnsupportedError(
+          "Cannot extract a file path from a URI with a fragment component");
+    }
+    windows ??= _isWindows;
+    return windows ? _toWindowsFilePath(this) : _toFilePath();
+  }
+
+  String _toFilePath() {
+    if (hasAuthority && host != "") {
+      throw UnsupportedError(
+          "Cannot extract a non-Windows file path from a file URI "
+          "with an authority");
+    }
+    // Use path segments to have any escapes unescaped.
+    var pathSegments = this.pathSegments;
+    _checkNonWindowsPathReservedCharacters(pathSegments, false);
+    var result = StringBuffer();
+    if (hasAbsolutePath) result.write("/");
+    result.writeAll(pathSegments, "/");
+    return result.toString();
+  }
+
+  static String _toWindowsFilePath(Uri uri) {
+    bool hasDriveLetter = false;
+    var segments = uri.pathSegments;
+    if (segments.length > 0 &&
+        segments[0].length == 2 &&
+        segments[0].codeUnitAt(1) == _COLON) {
+      _checkWindowsDriveLetter(segments[0].codeUnitAt(0), false);
+      _checkWindowsPathReservedCharacters(segments, false, 1);
+      hasDriveLetter = true;
+    } else {
+      _checkWindowsPathReservedCharacters(segments, false, 0);
+    }
+    var result = StringBuffer();
+    if (uri.hasAbsolutePath && !hasDriveLetter) result.write(r"\");
+    if (uri.hasAuthority) {
+      var host = uri.host;
+      if (host.isNotEmpty) {
+        result.write(r"\");
+        result.write(host);
+        result.write(r"\");
+      }
+    }
+    result.writeAll(segments, r"\");
+    if (hasDriveLetter && segments.length == 1) result.write(r"\");
+    return result.toString();
+  }
+
+  bool get _isPathAbsolute {
+    return path != null && path.startsWith('/');
+  }
+
+  void _writeAuthority(StringSink ss) {
+    if (_userInfo.isNotEmpty) {
+      ss.write(_userInfo);
+      ss.write("@");
+    }
+    if (_host != null) ss.write(_host);
+    if (_port != null) {
+      ss.write(":");
+      ss.write(_port);
+    }
+  }
+
+  /**
+   * Access the structure of a `data:` URI.
+   *
+   * Returns a [UriData] object for `data:` URIs and `null` for all other
+   * URIs.
+   * The [UriData] object can be used to access the media type and data
+   * of a `data:` URI.
+   */
+  UriData get data => (scheme == "data") ? UriData.fromUri(this) : null;
+
+  String toString() {
+    return _text ??= _initializeText();
+  }
+
+  String _initializeText() {
+    assert(_text == null);
+    StringBuffer sb = StringBuffer();
+    if (scheme.isNotEmpty) sb..write(scheme)..write(":");
+    if (hasAuthority || (scheme == "file")) {
+      // File URIS always have the authority, even if it is empty.
+      // The empty URI means "localhost".
+      sb.write("//");
+      _writeAuthority(sb);
+    }
+    sb.write(path);
+    if (_query != null) sb..write("?")..write(_query);
+    if (_fragment != null) sb..write("#")..write(_fragment);
+    return sb.toString();
+  }
+
+  bool operator ==(Object other) {
+    if (identical(this, other)) return true;
+    return other is Uri &&
+        scheme == other.scheme &&
+        hasAuthority == other.hasAuthority &&
+        userInfo == other.userInfo &&
+        host == other.host &&
+        port == other.port &&
+        path == other.path &&
+        hasQuery == other.hasQuery &&
+        query == other.query &&
+        hasFragment == other.hasFragment &&
+        fragment == other.fragment;
+  }
+
+  int get hashCode {
+    return _hashCodeCache ??= toString().hashCode;
+  }
+
+  static List<String> _createList() => <String>[];
+
+  static Map<String, List<String>> _splitQueryStringAll(String query,
+      {Encoding encoding = utf8}) {
+    var result = <String, List<String>>{};
+    int i = 0;
+    int start = 0;
+    int equalsIndex = -1;
+
+    void parsePair(int start, int equalsIndex, int end) {
+      String key;
+      String value;
+      if (start == end) return;
+      if (equalsIndex < 0) {
+        key = _uriDecode(query, start, end, encoding, true);
+        value = "";
+      } else {
+        key = _uriDecode(query, start, equalsIndex, encoding, true);
+        value = _uriDecode(query, equalsIndex + 1, end, encoding, true);
+      }
+      result.putIfAbsent(key, _createList).add(value);
+    }
+
+    while (i < query.length) {
+      int char = query.codeUnitAt(i);
+      if (char == _EQUALS) {
+        if (equalsIndex < 0) equalsIndex = i;
+      } else if (char == _AMPERSAND) {
+        parsePair(start, equalsIndex, i);
+        start = i + 1;
+        equalsIndex = -1;
+      }
+      i++;
+    }
+    parsePair(start, equalsIndex, i);
+    return result;
+  }
+
+  external static String _uriEncode(List<int> canonicalTable, String text,
+      Encoding encoding, bool spaceToPlus);
+
+  /**
+   * Convert a byte (2 character hex sequence) in string [s] starting
+   * at position [pos] to its ordinal value
+   */
+  static int _hexCharPairToByte(String s, int pos) {
+    int byte = 0;
+    for (int i = 0; i < 2; i++) {
+      var charCode = s.codeUnitAt(pos + i);
+      if (0x30 <= charCode && charCode <= 0x39) {
+        byte = byte * 16 + charCode - 0x30;
+      } else {
+        // Check ranges A-F (0x41-0x46) and a-f (0x61-0x66).
+        charCode |= 0x20;
+        if (0x61 <= charCode && charCode <= 0x66) {
+          byte = byte * 16 + charCode - 0x57;
+        } else {
+          throw ArgumentError("Invalid URL encoding");
+        }
+      }
+    }
+    return byte;
+  }
+
+  /**
+   * Uri-decode a percent-encoded string.
+   *
+   * It unescapes the string [text] and returns the unescaped string.
+   *
+   * This function is similar to the JavaScript-function `decodeURI`.
+   *
+   * If [plusToSpace] is `true`, plus characters will be converted to spaces.
+   *
+   * The decoder will create a byte-list of the percent-encoded parts, and then
+   * decode the byte-list using [encoding]. The default encodings UTF-8.
+   */
+  static String _uriDecode(
+      String text, int start, int end, Encoding encoding, bool plusToSpace) {
+    assert(0 <= start);
+    assert(start <= end);
+    assert(end <= text.length);
+    assert(encoding != null);
+    // First check whether there is any characters which need special handling.
+    bool simple = true;
+    for (int i = start; i < end; i++) {
+      var codeUnit = text.codeUnitAt(i);
+      if (codeUnit > 127 ||
+          codeUnit == _PERCENT ||
+          (plusToSpace && codeUnit == _PLUS)) {
+        simple = false;
+        break;
+      }
+    }
+    List<int> bytes;
+    if (simple) {
+      if (utf8 == encoding || latin1 == encoding || ascii == encoding) {
+        return text.substring(start, end);
+      } else {
+        bytes = text.substring(start, end).codeUnits;
+      }
+    } else {
+      bytes = List();
+      for (int i = start; i < end; i++) {
+        var codeUnit = text.codeUnitAt(i);
+        if (codeUnit > 127) {
+          throw ArgumentError("Illegal percent encoding in URI");
+        }
+        if (codeUnit == _PERCENT) {
+          if (i + 3 > text.length) {
+            throw ArgumentError('Truncated URI');
+          }
+          bytes.add(_hexCharPairToByte(text, i + 1));
+          i += 2;
+        } else if (plusToSpace && codeUnit == _PLUS) {
+          bytes.add(_SPACE);
+        } else {
+          bytes.add(codeUnit);
+        }
+      }
+    }
+    return encoding.decode(bytes);
+  }
+
+  static bool _isAlphabeticCharacter(int codeUnit) {
+    var lowerCase = codeUnit | 0x20;
+    return (_LOWER_CASE_A <= lowerCase && lowerCase <= _LOWER_CASE_Z);
+  }
+
+  static bool _isUnreservedChar(int char) {
+    return char < 127 &&
+        ((_unreservedTable[char >> 4] & (1 << (char & 0x0f))) != 0);
+  }
+
+  // Tables of char-codes organized as a bit vector of 128 bits where
+  // each bit indicate whether a character code on the 0-127 needs to
+  // be escaped or not.
+
+  // The unreserved characters of RFC 3986.
+  static const _unreservedTable = <int>[
+    //                     LSB            MSB
+    //                      |              |
+    0x0000, // 0x00 - 0x0f  0000000000000000
+    0x0000, // 0x10 - 0x1f  0000000000000000
+    //                                   -.
+    0x6000, // 0x20 - 0x2f  0000000000000110
+    //                      0123456789
+    0x03ff, // 0x30 - 0x3f  1111111111000000
+    //                       ABCDEFGHIJKLMNO
+    0xfffe, // 0x40 - 0x4f  0111111111111111
+    //                      PQRSTUVWXYZ    _
+    0x87ff, // 0x50 - 0x5f  1111111111100001
+    //                       abcdefghijklmno
+    0xfffe, // 0x60 - 0x6f  0111111111111111
+    //                      pqrstuvwxyz   ~
+    0x47ff, // 0x70 - 0x7f  1111111111100010
+  ];
+
+  // The unreserved characters of RFC 2396.
+  static const _unreserved2396Table = <int>[
+    //                     LSB            MSB
+    //                      |              |
+    0x0000, // 0x00 - 0x0f  0000000000000000
+    0x0000, // 0x10 - 0x1f  0000000000000000
+    //                       !     '()*  -.
+    0x6782, // 0x20 - 0x2f  0100000111100110
+    //                      0123456789
+    0x03ff, // 0x30 - 0x3f  1111111111000000
+    //                       ABCDEFGHIJKLMNO
+    0xfffe, // 0x40 - 0x4f  0111111111111111
+    //                      PQRSTUVWXYZ    _
+    0x87ff, // 0x50 - 0x5f  1111111111100001
+    //                       abcdefghijklmno
+    0xfffe, // 0x60 - 0x6f  0111111111111111
+    //                      pqrstuvwxyz   ~
+    0x47ff, // 0x70 - 0x7f  1111111111100010
+  ];
+
+  // Table of reserved characters specified by ECMAScript 5.
+  static const _encodeFullTable = <int>[
+    //                     LSB            MSB
+    //                      |              |
+    0x0000, // 0x00 - 0x0f  0000000000000000
+    0x0000, // 0x10 - 0x1f  0000000000000000
+    //                       ! #$ &'()*+,-./
+    0xffda, // 0x20 - 0x2f  0101101111111111
+    //                      0123456789:; = ?
+    0xafff, // 0x30 - 0x3f  1111111111110101
+    //                      @ABCDEFGHIJKLMNO
+    0xffff, // 0x40 - 0x4f  1111111111111111
+    //                      PQRSTUVWXYZ    _
+    0x87ff, // 0x50 - 0x5f  1111111111100001
+    //                       abcdefghijklmno
+    0xfffe, // 0x60 - 0x6f  0111111111111111
+    //                      pqrstuvwxyz   ~
+    0x47ff, // 0x70 - 0x7f  1111111111100010
+  ];
+
+  // Characters allowed in the scheme.
+  static const _schemeTable = <int>[
+    //                     LSB            MSB
+    //                      |              |
+    0x0000, // 0x00 - 0x0f  0000000000000000
+    0x0000, // 0x10 - 0x1f  0000000000000000
+    //                                 + -.
+    0x6800, // 0x20 - 0x2f  0000000000010110
+    //                      0123456789
+    0x03ff, // 0x30 - 0x3f  1111111111000000
+    //                       ABCDEFGHIJKLMNO
+    0xfffe, // 0x40 - 0x4f  0111111111111111
+    //                      PQRSTUVWXYZ
+    0x07ff, // 0x50 - 0x5f  1111111111100001
+    //                       abcdefghijklmno
+    0xfffe, // 0x60 - 0x6f  0111111111111111
+    //                      pqrstuvwxyz
+    0x07ff, // 0x70 - 0x7f  1111111111100010
+  ];
+
+  // Characters allowed in scheme except for upper case letters.
+  static const _schemeLowerTable = <int>[
+    //                     LSB            MSB
+    //                      |              |
+    0x0000, // 0x00 - 0x0f  0000000000000000
+    0x0000, // 0x10 - 0x1f  0000000000000000
+    //                                 + -.
+    0x6800, // 0x20 - 0x2f  0000000000010110
+    //                      0123456789
+    0x03ff, // 0x30 - 0x3f  1111111111000000
+    //
+    0x0000, // 0x40 - 0x4f  0111111111111111
+    //
+    0x0000, // 0x50 - 0x5f  1111111111100001
+    //                       abcdefghijklmno
+    0xfffe, // 0x60 - 0x6f  0111111111111111
+    //                      pqrstuvwxyz
+    0x07ff, // 0x70 - 0x7f  1111111111100010
+  ];
+
+  // Sub delimiter characters combined with unreserved as of 3986.
+  // sub-delims  = "!" / "$" / "&" / "'" / "(" / ")"
+  //         / "*" / "+" / "," / ";" / "="
+  // RFC 3986 section 2.3.
+  // unreserved  = ALPHA / DIGIT / "-" / "." / "_" / "~"
+  static const _subDelimitersTable = <int>[
+    //                     LSB            MSB
+    //                      |              |
+    0x0000, // 0x00 - 0x0f  0000000000000000
+    0x0000, // 0x10 - 0x1f  0000000000000000
+    //                       !  $ &'()*+,-.
+    0x7fd2, // 0x20 - 0x2f  0100101111111110
+    //                      0123456789 ; =
+    0x2bff, // 0x30 - 0x3f  1111111111010100
+    //                       ABCDEFGHIJKLMNO
+    0xfffe, // 0x40 - 0x4f  0111111111111111
+    //                      PQRSTUVWXYZ    _
+    0x87ff, // 0x50 - 0x5f  1111111111100001
+    //                       abcdefghijklmno
+    0xfffe, // 0x60 - 0x6f  0111111111111111
+    //                      pqrstuvwxyz   ~
+    0x47ff, // 0x70 - 0x7f  1111111111100010
+  ];
+
+  // General delimiter characters, RFC 3986 section 2.2.
+  // gen-delims  = ":" / "/" / "?" / "#" / "[" / "]" / "@"
+  //
+  static const _genDelimitersTable = <int>[
+    //                     LSB            MSB
+    //                      |              |
+    0x0000, // 0x00 - 0x0f  0000000000000000
+    0x0000, // 0x10 - 0x1f  0000000000000000
+    //                         #           /
+    0x8008, // 0x20 - 0x2f  0001000000000001
+    //                                :    ?
+    0x8400, // 0x30 - 0x3f  0000000000100001
+    //                      @
+    0x0001, // 0x40 - 0x4f  1000000000000000
+    //                                 [ ]
+    0x2800, // 0x50 - 0x5f  0000000000010100
+    //
+    0x0000, // 0x60 - 0x6f  0000000000000000
+    //
+    0x0000, // 0x70 - 0x7f  0000000000000000
+  ];
+
+  // Characters allowed in the userinfo as of RFC 3986.
+  // RFC 3986 Appendix A
+  // userinfo = *( unreserved / pct-encoded / sub-delims / ':')
+  static const _userinfoTable = <int>[
+    //                     LSB            MSB
+    //                      |              |
+    0x0000, // 0x00 - 0x0f  0000000000000000
+    0x0000, // 0x10 - 0x1f  0000000000000000
+    //                       !  $ &'()*+,-.
+    0x7fd2, // 0x20 - 0x2f  0100101111111110
+    //                      0123456789:; =
+    0x2fff, // 0x30 - 0x3f  1111111111110100
+    //                       ABCDEFGHIJKLMNO
+    0xfffe, // 0x40 - 0x4f  0111111111111111
+    //                      PQRSTUVWXYZ    _
+    0x87ff, // 0x50 - 0x5f  1111111111100001
+    //                       abcdefghijklmno
+    0xfffe, // 0x60 - 0x6f  0111111111111111
+    //                      pqrstuvwxyz   ~
+    0x47ff, // 0x70 - 0x7f  1111111111100010
+  ];
+
+  // Characters allowed in the reg-name as of RFC 3986.
+  // RFC 3986 Appendix A
+  // reg-name = *( unreserved / pct-encoded / sub-delims )
+  static const _regNameTable = <int>[
+    //                     LSB            MSB
+    //                      |              |
+    0x0000, // 0x00 - 0x0f  0000000000000000
+    0x0000, // 0x10 - 0x1f  0000000000000000
+    //                       !  $%&'()*+,-.
+    0x7ff2, // 0x20 - 0x2f  0100111111111110
+    //                      0123456789 ; =
+    0x2bff, // 0x30 - 0x3f  1111111111010100
+    //                       ABCDEFGHIJKLMNO
+    0xfffe, // 0x40 - 0x4f  0111111111111111
+    //                      PQRSTUVWXYZ    _
+    0x87ff, // 0x50 - 0x5f  1111111111100001
+    //                       abcdefghijklmno
+    0xfffe, // 0x60 - 0x6f  0111111111111111
+    //                      pqrstuvwxyz   ~
+    0x47ff, // 0x70 - 0x7f  1111111111100010
+  ];
+
+  // Characters allowed in the path as of RFC 3986.
+  // RFC 3986 section 3.3.
+  // pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
+  static const _pathCharTable = <int>[
+    //                     LSB            MSB
+    //                      |              |
+    0x0000, // 0x00 - 0x0f  0000000000000000
+    0x0000, // 0x10 - 0x1f  0000000000000000
+    //                       !  $ &'()*+,-.
+    0x7fd2, // 0x20 - 0x2f  0100101111111110
+    //                      0123456789:; =
+    0x2fff, // 0x30 - 0x3f  1111111111110100
+    //                      @ABCDEFGHIJKLMNO
+    0xffff, // 0x40 - 0x4f  1111111111111111
+    //                      PQRSTUVWXYZ    _
+    0x87ff, // 0x50 - 0x5f  1111111111100001
+    //                       abcdefghijklmno
+    0xfffe, // 0x60 - 0x6f  0111111111111111
+    //                      pqrstuvwxyz   ~
+    0x47ff, // 0x70 - 0x7f  1111111111100010
+  ];
+
+  // Characters allowed in the path as of RFC 3986.
+  // RFC 3986 section 3.3 *and* slash.
+  static const _pathCharOrSlashTable = [
+    //                     LSB            MSB
+    //                      |              |
+    0x0000, // 0x00 - 0x0f  0000000000000000
+    0x0000, // 0x10 - 0x1f  0000000000000000
+    //                       !  $ &'()*+,-./
+    0xffd2, // 0x20 - 0x2f  0100101111111111
+    //                      0123456789:; =
+    0x2fff, // 0x30 - 0x3f  1111111111110100
+    //                      @ABCDEFGHIJKLMNO
+    0xffff, // 0x40 - 0x4f  1111111111111111
+
+    //                      PQRSTUVWXYZ    _
+    0x87ff, // 0x50 - 0x5f  1111111111100001
+    //                       abcdefghijklmno
+    0xfffe, // 0x60 - 0x6f  0111111111111111
+    //                      pqrstuvwxyz   ~
+    0x47ff, // 0x70 - 0x7f  1111111111100010
+  ];
+
+  // Characters allowed in the query as of RFC 3986.
+  // RFC 3986 section 3.4.
+  // query = *( pchar / "/" / "?" )
+  static const _queryCharTable = [
+    //                     LSB            MSB
+    //                      |              |
+    0x0000, // 0x00 - 0x0f  0000000000000000
+    0x0000, // 0x10 - 0x1f  0000000000000000
+    //                       !  $ &'()*+,-./
+    0xffd2, // 0x20 - 0x2f  0100101111111111
+    //                      0123456789:; = ?
+    0xafff, // 0x30 - 0x3f  1111111111110101
+    //                      @ABCDEFGHIJKLMNO
+    0xffff, // 0x40 - 0x4f  1111111111111111
+    //                      PQRSTUVWXYZ    _
+    0x87ff, // 0x50 - 0x5f  1111111111100001
+    //                       abcdefghijklmno
+    0xfffe, // 0x60 - 0x6f  0111111111111111
+    //                      pqrstuvwxyz   ~
+    0x47ff, // 0x70 - 0x7f  1111111111100010
+  ];
+
+  // Characters allowed in the ZoneID as of RFC 6874.
+  // ZoneID = 1*( unreserved / pct-encoded )
+  static const _zoneIDTable = <int>[
+    //                     LSB            MSB
+    //                      |              |
+    0x0000, // 0x00 - 0x0f  0000000000000000
+    0x0000, // 0x10 - 0x1f  0000000000000000
+    //                       !  $%&'()*+,-.
+    0x6000, // 0x20 - 0x2f  0000000000000110
+    //                      0123456789 ; =
+    0x03ff, // 0x30 - 0x3f  1111111111000000
+    //                       ABCDEFGHIJKLMNO
+    0xfffe, // 0x40 - 0x4f  0111111111111111
+    //                      PQRSTUVWXYZ    _
+    0x87ff, // 0x50 - 0x5f  1111111111100001
+    //                       abcdefghijklmno
+    0xfffe, // 0x60 - 0x6f  0111111111111111
+    //                      pqrstuvwxyz   ~
+    0x47ff, // 0x70 - 0x7f  1111111111100010
+  ];
+}
+
+// --------------------------------------------------------------------
+// Data URI
+// --------------------------------------------------------------------
+
+/**
+ * A way to access the structure of a `data:` URI.
+ *
+ * Data URIs are non-hierarchical URIs that can contain any binary data.
+ * They are defined by [RFC 2397](https://tools.ietf.org/html/rfc2397).
+ *
+ * This class allows parsing the URI text and extracting individual parts of the
+ * URI, as well as building the URI text from structured parts.
+ */
+class UriData {
+  static const int _noScheme = -1;
+  /**
+   * Contains the text content of a `data:` URI, with or without a
+   * leading `data:`.
+   *
+   * If [_separatorIndices] starts with `4` (the index of the `:`), then
+   * there is a leading `data:`, otherwise [_separatorIndices] starts with
+   * `-1`.
+   */
+  final String _text;
+
+  /**
+   * List of the separators (';', '=' and ',') in the text.
+   *
+   * Starts with the index of the `:` in `data:` of the mimeType.
+   * That is always either -1 or 4, depending on whether `_text` includes the
+   * `data:` scheme or not.
+   *
+   * The first speparator ends the mime type. We don't bother with finding
+   * the '/' inside the mime type.
+   *
+   * Each two separators after that marks a parameter key and value.
+   *
+   * If there is a single separator left, it ends the "base64" marker.
+   *
+   * So the following separators are found for a text:
+   * ```
+   * data:text/plain;foo=bar;base64,ARGLEBARGLE=
+   *     ^          ^   ^   ^      ^
+   * ```
+   */
+  final List<int> _separatorIndices;
+
+  /**
+   * Cache of the result returned by [uri].
+   */
+  Uri _uriCache;
+
+  UriData._(this._text, this._separatorIndices, this._uriCache);
+
+  // Avoid shadowing by argument.
+  static const Base64Codec _base64 = base64;
+
+  /**
+   * Creates a `data:` URI containing the [content] string.
+   *
+   * Equivalent to `new Uri.dataFromString(...).data`, but may
+   * be more efficient if the [uri] itself isn't used.
+   */
+  factory UriData.fromString(String content,
+      {String mimeType,
+      Encoding encoding,
+      Map<String, String> parameters,
+      bool base64 = false}) {
+    StringBuffer buffer = StringBuffer();
+    List<int> indices = [_noScheme];
+    String charsetName;
+    String encodingName;
+    if (parameters != null) charsetName = parameters["charset"];
+    if (encoding == null) {
+      if (charsetName != null) {
+        encoding = Encoding.getByName(charsetName);
+      }
+    } else if (charsetName == null) {
+      // Non-null only if parameters does not contain "charset".
+      encodingName = encoding.name;
+    }
+    encoding ??= ascii;
+    _writeUri(mimeType, encodingName, parameters, buffer, indices);
+    indices.add(buffer.length);
+    if (base64) {
+      buffer.write(';base64,');
+      indices.add(buffer.length - 1);
+      buffer.write(encoding.fuse(_base64).encode(content));
+    } else {
+      buffer.write(',');
+      _uriEncodeBytes(_uricTable, encoding.encode(content), buffer);
+    }
+    return UriData._(buffer.toString(), indices, null);
+  }
+
+  /**
+   * Creates a `data:` URI containing an encoding of [bytes].
+   *
+   * Equivalent to `new Uri.dataFromBytes(...).data`, but may
+   * be more efficient if the [uri] itself isn't used.
+   */
+  factory UriData.fromBytes(List<int> bytes,
+      {mimeType = "application/octet-stream",
+      Map<String, String> parameters,
+      percentEncoded = false}) {
+    StringBuffer buffer = StringBuffer();
+    List<int> indices = [_noScheme];
+    _writeUri(mimeType, null, parameters, buffer, indices);
+    indices.add(buffer.length);
+    if (percentEncoded) {
+      buffer.write(',');
+      _uriEncodeBytes(_uricTable, bytes, buffer);
+    } else {
+      buffer.write(';base64,');
+      indices.add(buffer.length - 1);
+      _base64.encoder
+          .startChunkedConversion(StringConversionSink.fromStringSink(buffer))
+          .addSlice(bytes, 0, bytes.length, true);
+    }
+
+    return UriData._(buffer.toString(), indices, null);
+  }
+
+  /**
+   * Creates a `DataUri` from a [Uri] which must have `data` as [Uri.scheme].
+   *
+   * The [uri] must have scheme `data` and no authority or fragment,
+   * and the path (concatenated with the query, if there is one) must be valid
+   * as data URI content with the same rules as [parse].
+   */
+  factory UriData.fromUri(Uri uri) {
+    if (uri.scheme != "data") {
+      throw ArgumentError.value(uri, "uri", "Scheme must be 'data'");
+    }
+    if (uri.hasAuthority) {
+      throw ArgumentError.value(uri, "uri", "Data uri must not have authority");
+    }
+    if (uri.hasFragment) {
+      throw ArgumentError.value(
+          uri, "uri", "Data uri must not have a fragment part");
+    }
+    if (!uri.hasQuery) {
+      return _parse(uri.path, 0, uri);
+    }
+    // Includes path and query (and leading "data:").
+    return _parse("$uri", 5, uri);
+  }
+
+  /**
+   * Writes the initial part of a `data:` uri, from after the "data:"
+   * until just before the ',' before the data, or before a `;base64,`
+   * marker.
+   *
+   * Of an [indices] list is passed, separator indices are stored in that
+   * list.
+   */
+  static void _writeUri(String mimeType, String charsetName,
+      Map<String, String> parameters, StringBuffer buffer, List indices) {
+    if (mimeType == null || mimeType == "text/plain") {
+      mimeType = "";
+    }
+    if (mimeType.isEmpty || identical(mimeType, "application/octet-stream")) {
+      buffer.write(mimeType); // Common cases need no escaping.
+    } else {
+      int slashIndex = _validateMimeType(mimeType);
+      if (slashIndex < 0) {
+        throw ArgumentError.value(mimeType, "mimeType", "Invalid MIME type");
+      }
+      buffer.write(_Uri._uriEncode(
+          _tokenCharTable, mimeType.substring(0, slashIndex), utf8, false));
+      buffer.write("/");
+      buffer.write(_Uri._uriEncode(
+          _tokenCharTable, mimeType.substring(slashIndex + 1), utf8, false));
+    }
+    if (charsetName != null) {
+      if (indices != null) {
+        indices..add(buffer.length)..add(buffer.length + 8);
+      }
+      buffer.write(";charset=");
+      buffer.write(_Uri._uriEncode(_tokenCharTable, charsetName, utf8, false));
+    }
+    parameters?.forEach((key, value) {
+      if (key.isEmpty) {
+        throw ArgumentError.value("", "Parameter names must not be empty");
+      }
+      if (value.isEmpty) {
+        throw ArgumentError.value(
+            "", "Parameter values must not be empty", 'parameters["$key"]');
+      }
+      if (indices != null) indices.add(buffer.length);
+      buffer.write(';');
+      // Encode any non-RFC2045-token character and both '%' and '#'.
+      buffer.write(_Uri._uriEncode(_tokenCharTable, key, utf8, false));
+      if (indices != null) indices.add(buffer.length);
+      buffer.write('=');
+      buffer.write(_Uri._uriEncode(_tokenCharTable, value, utf8, false));
+    });
+  }
+
+  /**
+   * Checks mimeType is valid-ish (`token '/' token`).
+   *
+   * Returns the index of the slash, or -1 if the mime type is not
+   * considered valid.
+   *
+   * Currently only looks for slashes, all other characters will be
+   * percent-encoded as UTF-8 if necessary.
+   */
+  static int _validateMimeType(String mimeType) {
+    int slashIndex = -1;
+    for (int i = 0; i < mimeType.length; i++) {
+      var char = mimeType.codeUnitAt(i);
+      if (char != _SLASH) continue;
+      if (slashIndex < 0) {
+        slashIndex = i;
+        continue;
+      }
+      return -1;
+    }
+    return slashIndex;
+  }
+
+  /**
+   * Parses a string as a `data` URI.
+   *
+   * The string must have the format:
+   *
+   * ```
+   * 'data:' (type '/' subtype)? (';' attribute '=' value)* (';base64')? ',' data
+   * ````
+   *
+   * where `type`, `subtype`, `attribute` and `value` are specified in RFC-2045,
+   * and `data` is a sequence of URI-characters (RFC-2396 `uric`).
+   *
+   * This means that all the characters must be ASCII, but the URI may contain
+   * percent-escapes for non-ASCII byte values that need an interpretation
+   * to be converted to the corresponding string.
+   *
+   * Parsing checks that Base64 encoded data is valid, and it normalizes it
+   * to use the default Base64 alphabet and to use padding.
+   * Non-Base64 data is escaped using percent-escapes as necessary to make
+   * it valid, and existing escapes are case normalized.
+   *
+   * Accessing the individual parts may fail later if they turn out to have
+   * content that can't be decoded successfully as a string, for example if
+   * existing percent escapes represent bytes that cannot be decoded
+   * by the chosen [Encoding] (see [contentAsString]).
+   *
+   * A [FormatException] is thrown if [uri] is not a valid data URI.
+   */
+  static UriData parse(String uri) {
+    if (uri.length >= 5) {
+      int dataDelta = _startsWithData(uri, 0);
+      if (dataDelta == 0) {
+        // Exact match on "data:".
+        return _parse(uri, 5, null);
+      }
+      if (dataDelta == 0x20) {
+        // Starts with a non-normalized "data" scheme containing upper-case
+        // letters. Parse anyway, but throw away the scheme.
+        return _parse(uri.substring(5), 0, null);
+      }
+    }
+    throw FormatException("Does not start with 'data:'", uri, 0);
+  }
+
+  /**
+   * The [Uri] that this `UriData` is giving access to.
+   *
+   * Returns a `Uri` with scheme `data` and the remainder of the data URI
+   * as path.
+   */
+  Uri get uri {
+    if (_uriCache != null) return _uriCache;
+    String path = _text;
+    String query;
+    int colonIndex = _separatorIndices[0];
+    int queryIndex = _text.indexOf('?', colonIndex + 1);
+    int end = _text.length;
+    if (queryIndex >= 0) {
+      query = _Uri._normalizeOrSubstring(
+          _text, queryIndex + 1, end, _Uri._queryCharTable);
+      end = queryIndex;
+    }
+    path = _Uri._normalizeOrSubstring(
+        _text, colonIndex + 1, end, _Uri._pathCharOrSlashTable);
+    _uriCache = _DataUri(this, path, query);
+    return _uriCache;
+  }
+
+  /**
+   * The MIME type of the data URI.
+   *
+   * A data URI consists of a "media type" followed by data.
+   * The media type starts with a MIME type and can be followed by
+   * extra parameters.
+   * If the MIME type representation in the URI text contains URI escapes,
+   * they are unescaped in the returned string.
+   * If the value contain non-ASCII percent escapes, they are decoded as UTF-8.
+   *
+   * Example:
+   *
+   *     data:text/plain;charset=utf-8,Hello%20World!
+   *
+   * This data URI has the media type `text/plain;charset=utf-8`, which is the
+   * MIME type `text/plain` with the parameter `charset` with value `utf-8`.
+   * See [RFC 2045](https://tools.ietf.org/html/rfc2045) for more detail.
+   *
+   * If the first part of the data URI is empty, it defaults to `text/plain`.
+   */
+  String get mimeType {
+    int start = _separatorIndices[0] + 1;
+    int end = _separatorIndices[1];
+    if (start == end) return "text/plain";
+    return _Uri._uriDecode(_text, start, end, utf8, false);
+  }
+
+  /**
+   * The charset parameter of the media type.
+   *
+   * If the parameters of the media type contains a `charset` parameter
+   * then this returns its value, otherwise it returns `US-ASCII`,
+   * which is the default charset for data URIs.
+   * If the value contain non-ASCII percent escapes, they are decoded as UTF-8.
+   *
+   * If the MIME type representation in the URI text contains URI escapes,
+   * they are unescaped in the returned string.
+   */
+  String get charset {
+    int parameterStart = 1;
+    int parameterEnd = _separatorIndices.length - 1; // The ',' before data.
+    if (isBase64) {
+      // There is a ";base64" separator, so subtract one for that as well.
+      parameterEnd -= 1;
+    }
+    for (int i = parameterStart; i < parameterEnd; i += 2) {
+      var keyStart = _separatorIndices[i] + 1;
+      var keyEnd = _separatorIndices[i + 1];
+      if (keyEnd == keyStart + 7 && _text.startsWith("charset", keyStart)) {
+        return _Uri._uriDecode(
+            _text, keyEnd + 1, _separatorIndices[i + 2], utf8, false);
+      }
+    }
+    return "US-ASCII";
+  }
+
+  /**
+   * Whether the data is Base64 encoded or not.
+   */
+  bool get isBase64 => _separatorIndices.length.isOdd;
+
+  /**
+   * The content part of the data URI, as its actual representation.
+   *
+   * This string may contain percent escapes.
+   */
+  String get contentText => _text.substring(_separatorIndices.last + 1);
+
+  /**
+   * The content part of the data URI as bytes.
+   *
+   * If the data is Base64 encoded, it will be decoded to bytes.
+   *
+   * If the data is not Base64 encoded, it will be decoded by unescaping
+   * percent-escaped characters and returning byte values of each unescaped
+   * character. The bytes will not be, e.g., UTF-8 decoded.
+   */
+  Uint8List contentAsBytes() {
+    String text = _text;
+    int start = _separatorIndices.last + 1;
+    if (isBase64) {
+      return base64.decoder.convert(text, start);
+    }
+
+    // Not base64, do percent-decoding and return the remaining bytes.
+    // Compute result size.
+    const int percent = 0x25;
+    int length = text.length - start;
+    for (int i = start; i < text.length; i++) {
+      var codeUnit = text.codeUnitAt(i);
+      if (codeUnit == percent) {
+        i += 2;
+        length -= 2;
+      }
+    }
+    // Fill result array.
+    Uint8List result = Uint8List(length);
+    if (length == text.length) {
+      result.setRange(0, length, text.codeUnits, start);
+      return result;
+    }
+    int index = 0;
+    for (int i = start; i < text.length; i++) {
+      var codeUnit = text.codeUnitAt(i);
+      if (codeUnit != percent) {
+        result[index++] = codeUnit;
+      } else {
+        if (i + 2 < text.length) {
+          int byte = parseHexByte(text, i + 1);
+          if (byte >= 0) {
+            result[index++] = byte;
+            i += 2;
+            continue;
+          }
+        }
+        throw FormatException("Invalid percent escape", text, i);
+      }
+    }
+    assert(index == result.length);
+    return result;
+  }
+
+  /**
+   * Returns a string created from the content of the data URI.
+   *
+   * If the content is Base64 encoded, it will be decoded to bytes and then
+   * decoded to a string using [encoding].
+   * If encoding is omitted, the value of a `charset` parameter is used
+   * if it is recognized by [Encoding.getByName], otherwise it defaults to
+   * the [ascii] encoding, which is the default encoding for data URIs
+   * that do not specify an encoding.
+   *
+   * If the content is not Base64 encoded, it will first have percent-escapes
+   * converted to bytes and then the character codes and byte values are
+   * decoded using [encoding].
+   */
+  String contentAsString({Encoding encoding}) {
+    if (encoding == null) {
+      var charset = this.charset; // Returns "US-ASCII" if not present.
+      encoding = Encoding.getByName(charset);
+      if (encoding == null) {
+        throw UnsupportedError("Unknown charset: $charset");
+      }
+    }
+    String text = _text;
+    int start = _separatorIndices.last + 1;
+    if (isBase64) {
+      var converter = base64.decoder.fuse(encoding.decoder);
+      return converter.convert(text.substring(start));
+    }
+    return _Uri._uriDecode(text, start, text.length, encoding, false);
+  }
+
+  /**
+   * A map representing the parameters of the media type.
+   *
+   * A data URI may contain parameters between the MIME type and the
+   * data. This converts these parameters to a map from parameter name
+   * to parameter value.
+   * The map only contains parameters that actually occur in the URI.
+   * The `charset` parameter has a default value even if it doesn't occur
+   * in the URI, which is reflected by the [charset] getter. This means that
+   * [charset] may return a value even if `parameters["charset"]` is `null`.
+   *
+   * If the values contain non-ASCII values or percent escapes,
+   * they are decoded as UTF-8.
+   */
+  Map<String, String> get parameters {
+    var result = <String, String>{};
+    for (int i = 3; i < _separatorIndices.length; i += 2) {
+      var start = _separatorIndices[i - 2] + 1;
+      var equals = _separatorIndices[i - 1];
+      var end = _separatorIndices[i];
+      String key = _Uri._uriDecode(_text, start, equals, utf8, false);
+      String value = _Uri._uriDecode(_text, equals + 1, end, utf8, false);
+      result[key] = value;
+    }
+    return result;
+  }
+
+  static UriData _parse(String text, int start, Uri sourceUri) {
+    assert(start == 0 || start == 5);
+    assert((start == 5) == text.startsWith("data:"));
+
+    /// Character codes.
+    const int comma = 0x2c;
+    const int slash = 0x2f;
+    const int semicolon = 0x3b;
+    const int equals = 0x3d;
+    List<int> indices = [start - 1];
+    int slashIndex = -1;
+    var char;
+    int i = start;
+    for (; i < text.length; i++) {
+      char = text.codeUnitAt(i);
+      if (char == comma || char == semicolon) break;
+      if (char == slash) {
+        if (slashIndex < 0) {
+          slashIndex = i;
+          continue;
+        }
+        throw FormatException("Invalid MIME type", text, i);
+      }
+    }
+    if (slashIndex < 0 && i > start) {
+      // An empty MIME type is allowed, but if non-empty it must contain
+      // exactly one slash.
+      throw FormatException("Invalid MIME type", text, i);
+    }
+    while (char != comma) {
+      // Parse parameters and/or "base64".
+      indices.add(i);
+      i++;
+      int equalsIndex = -1;
+      for (; i < text.length; i++) {
+        char = text.codeUnitAt(i);
+        if (char == equals) {
+          if (equalsIndex < 0) equalsIndex = i;
+        } else if (char == semicolon || char == comma) {
+          break;
+        }
+      }
+      if (equalsIndex >= 0) {
+        indices.add(equalsIndex);
+      } else {
+        // Have to be final "base64".
+        var lastSeparator = indices.last;
+        if (char != comma ||
+            i != lastSeparator + 7 /* "base64,".length */ ||
+            !text.startsWith("base64", lastSeparator + 1)) {
+          throw FormatException("Expecting '='", text, i);
+        }
+        break;
+      }
+    }
+    indices.add(i);
+    bool isBase64 = indices.length.isOdd;
+    if (isBase64) {
+      text = base64.normalize(text, i + 1, text.length);
+    } else {
+      // Validate "data" part, must only contain RFC 2396 'uric' characters
+      // (reserved, unreserved, or escape sequences).
+      // Normalize to this (throws on a fragment separator).
+      var data = _Uri._normalize(text, i + 1, text.length, _uricTable,
+          escapeDelimiters: true);
+      if (data != null) {
+        text = text.replaceRange(i + 1, text.length, data);
+      }
+    }
+    return UriData._(text, indices, sourceUri);
+  }
+
+  /**
+   * Like [Uri._uriEncode] but takes the input as bytes, not a string.
+   *
+   * Encodes into [buffer] instead of creating its own buffer.
+   */
+  static void _uriEncodeBytes(
+      List<int> canonicalTable, List<int> bytes, StringSink buffer) {
+    // Encode the string into bytes then generate an ASCII only string
+    // by percent encoding selected bytes.
+    int byteOr = 0;
+    for (int i = 0; i < bytes.length; i++) {
+      int byte = bytes[i];
+      byteOr |= byte;
+      if (byte < 128 &&
+          ((canonicalTable[byte >> 4] & (1 << (byte & 0x0f))) != 0)) {
+        buffer.writeCharCode(byte);
+      } else {
+        buffer.writeCharCode(_PERCENT);
+        buffer.writeCharCode(_hexDigits.codeUnitAt(byte >> 4));
+        buffer.writeCharCode(_hexDigits.codeUnitAt(byte & 0x0f));
+      }
+    }
+    if ((byteOr & ~0xFF) != 0) {
+      for (int i = 0; i < bytes.length; i++) {
+        var byte = bytes[i];
+        if (byte < 0 || byte > 255) {
+          throw ArgumentError.value(byte, "non-byte value");
+        }
+      }
+    }
+  }
+
+  String toString() =>
+      (_separatorIndices[0] == _noScheme) ? "data:$_text" : _text;
+
+  // Table of the `token` characters of RFC 2045 in a URI.
+  //
+  // A token is any US-ASCII character except SPACE, control characters and
+  // `tspecial` characters. The `tspecial` category is:
+  // '(', ')', '<', '>', '@', ',', ';', ':', '\', '"', '/', '[, ']', '?', '='.
+  //
+  // In a data URI, we also need to escape '%' and '#' characters.
+  static const _tokenCharTable = [
+    //                     LSB             MSB
+    //                      |               |
+    0x0000, // 0x00 - 0x0f  00000000 00000000
+    0x0000, // 0x10 - 0x1f  00000000 00000000
+    //                       !  $ &'   *+ -.
+    0x6cd2, // 0x20 - 0x2f  01001011 00110110
+    //                      01234567 89
+    0x03ff, // 0x30 - 0x3f  11111111 11000000
+    //                       ABCDEFG HIJKLMNO
+    0xfffe, // 0x40 - 0x4f  01111111 11111111
+    //                      PQRSTUVW XYZ   ^_
+    0xc7ff, // 0x50 - 0x5f  11111111 11100011
+    //                      `abcdefg hijklmno
+    0xffff, // 0x60 - 0x6f  11111111 11111111
+    //                      pqrstuvw xyz{|}~
+    0x7fff, // 0x70 - 0x7f  11111111 11111110
+  ];
+
+  // All non-escape RFC-2396 uric characters.
+  //
+  //  uric        =  reserved | unreserved | escaped
+  //  reserved    =  ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ","
+  //  unreserved  =  alphanum | mark
+  //  mark        =  "-" | "_" | "." | "!" | "~" | "*" | "'" | "(" | ")"
+  //
+  // This is the same characters as in a URI query (which is URI pchar plus '?')
+  static const _uricTable = _Uri._queryCharTable;
+
+  // Characters allowed in base-64 encoding (alphanumeric, '/', '+' and '=').
+  static const _base64Table = [
+    //                     LSB             MSB
+    //                      |               |
+    0x0000, // 0x00 - 0x0f  00000000 00000000
+    0x0000, // 0x10 - 0x1f  00000000 00000000
+    //                                  +   /
+    0x8800, // 0x20 - 0x2f  00000000 00010001
+    //                      01234567 89
+    0x03ff, // 0x30 - 0x3f  11111111 11000000
+    //                       ABCDEFG HIJKLMNO
+    0xfffe, // 0x40 - 0x4f  01111111 11111111
+    //                      PQRSTUVW XYZ
+    0x07ff, // 0x50 - 0x5f  11111111 11100000
+    //                       abcdefg hijklmno
+    0xfffe, // 0x60 - 0x6f  01111111 11111111
+    //                      pqrstuvw xyz
+    0x07ff, // 0x70 - 0x7f  11111111 11100000
+  ];
+}
+
+// --------------------------------------------------------------------
+// Constants used to read the scanner result.
+// The indices points into the table filled by [_scan] which contains
+// recognized positions in the scanned URI.
+// The `0` index is only used internally.
+
+/// Index of the position of that `:` after a scheme.
+const int _schemeEndIndex = 1;
+
+/// Index of the position of the character just before the host name.
+const int _hostStartIndex = 2;
+
+/// Index of the position of the `:` before a port value.
+const int _portStartIndex = 3;
+
+/// Index of the position of the first character of a path.
+const int _pathStartIndex = 4;
+
+/// Index of the position of the `?` before a query.
+const int _queryStartIndex = 5;
+
+/// Index of the position of the `#` before a fragment.
+const int _fragmentStartIndex = 6;
+
+/// Index of a position where the URI was determined to be "non-simple".
+const int _notSimpleIndex = 7;
+
+// Initial state for scanner.
+const int _uriStart = 00;
+
+// If scanning of a URI terminates in this state or above,
+// consider the URI non-simple
+const int _nonSimpleEndStates = 14;
+
+// Initial state for scheme validation.
+const int _schemeStart = 20;
+
+/// Transition tables used to scan a URI to determine its structure.
+///
+/// The tables represent a state machine with output.
+///
+/// To scan the URI, start in the [_uriStart] state, then read each character
+/// of the URI in order, from start to end, and for each character perform a
+/// transition to a new state while writing the current position into the output
+/// buffer at a designated index.
+///
+/// Each state, represented by an integer which is an index into
+/// [_scannerTables], has a set of transitions, one for each character.
+/// The transitions are encoded as a 5-bit integer representing the next state
+/// and a 3-bit index into the output table.
+///
+/// For URI scanning, only characters in the range U+0020 through U+007E are
+/// interesting, all characters outside that range are treated the same.
+/// The tables only contain 96 entries, representing that characters in the
+/// interesting range, plus one more to represent all values outside the range.
+/// The character entries are stored in one `Uint8List` per state, with the
+/// transition for a character at position `character ^ 0x60`,
+/// which maps the range U+0020 .. U+007F into positions 0 .. 95.
+/// All remaining characters are mapped to position 31 (`0x7f ^ 0x60`) which
+/// represents the transition for all remaining characters.
+final List<Uint8List> _scannerTables = _createTables();
+
+// ----------------------------------------------------------------------
+// Code to create the URI scanner table.
+
+/// Creates the tables for [_scannerTables] used by [Uri.parse].
+///
+/// See [_scannerTables] for the generated format.
+///
+/// The concrete tables are chosen as a trade-off between the number of states
+/// needed and the precision of the result.
+/// This allows definitely recognizing the general structure of the URI
+/// (presence and location of scheme, user-info, host, port, path, query and
+/// fragment) while at the same time detecting that some components are not
+/// in canonical form (anything containing a `%`, a host-name containing a
+/// capital letter). Since the scanner doesn't know whether something is a
+/// scheme or a path until it sees `:`, or user-info or host until it sees
+/// a `@`, a second pass is needed to validate the scheme and any user-info
+/// is considered non-canonical by default.
+///
+/// The states (starting from [_uriStart]) write positions while scanning
+/// a string from `start` to `end` as follows:
+///
+/// - [_schemeEndIndex]: Should be initialized to `start-1`.
+///   If the URI has a scheme, it is set to the position of the `:` after
+///   the scheme.
+/// - [_hostStartIndex]: Should be initialized to `start - 1`.
+///   If the URI has an authority, it is set to the character before the
+///   host name - either the second `/` in the `//` leading the authority,
+///   or the `@` after a user-info. Comparing this value to the scheme end
+///   position can be used to detect that there is a user-info component.
+/// - [_portStartIndex]: Should be initialized to `start`.
+///   Set to the position of the last `:` in an authority, and unchanged
+///   if there is no authority or no `:` in an authority.
+///   If this position is after the host start, there is a port, otherwise it
+///   is just marking a colon in the user-info component.
+/// - [_pathStartIndex]: Should be initialized to `start`.
+///   Is set to the first path character unless the path is empty.
+///   If the path is empty, the position is either unchanged (`start`) or
+///   the first slash of an authority. So, if the path start is before a
+///   host start or scheme end, the path is empty.
+/// - [_queryStartIndex]: Should be initialized to `end`.
+///   The position of the `?` leading a query if the URI contains a query.
+/// - [_fragmentStartIndex]: Should be initialized to `end`.
+///   The position of the `#` leading a fragment if the URI contains a fragment.
+/// - [_notSimpleIndex]: Should be initialized to `start - 1`.
+///   Set to another value if the URI is considered "not simple".
+///   This is elaborated below.
+///
+/// # Simple URIs
+/// A URI is considered "simple" if it is in a normalized form containing no
+/// escapes. This allows us to skip normalization and checking whether escapes
+/// are valid, and to extract components without worrying about unescaping.
+///
+/// The scanner computes a conservative approximation of being "simple".
+/// It rejects any URI with an escape, with a user-info component (mainly
+/// because they are rare and would increase the number of states in the
+/// scanner significantly), with an IPV6 host or with a capital letter in
+/// the scheme or host name (the scheme is handled in a second scan using
+/// a separate two-state table).
+/// Further, paths containing `..` or `.` path segments are considered
+/// non-simple except for pure relative paths (no scheme or authority) starting
+/// with a sequence of "../" segments.
+///
+/// The transition tables cannot detect a trailing ".." in the path,
+/// followed by a query or fragment, because the segment is not known to be
+/// complete until we are past it, and we then need to store the query/fragment
+/// start instead. This cast is checked manually post-scanning (such a path
+/// needs to be normalized to end in "../", so the URI shouldn't be considered
+/// simple).
+List<Uint8List> _createTables() {
+  // TODO(lrn): Use a precomputed table.
+
+  // Total number of states for the scanner.
+  const int stateCount = 22;
+
+  // States used to scan a URI from scratch.
+  const int schemeOrPath = 01;
+  const int authOrPath = 02;
+  const int authOrPathSlash = 03;
+  const int uinfoOrHost0 = 04;
+  const int uinfoOrHost = 05;
+  const int uinfoOrPort0 = 06;
+  const int uinfoOrPort = 07;
+  const int ipv6Host = 08;
+  const int relPathSeg = 09;
+  const int pathSeg = 10;
+  const int path = 11;
+  const int query = 12;
+  const int fragment = 13;
+  const int schemeOrPathDot = 14;
+  const int schemeOrPathDot2 = 15;
+  const int relPathSegDot = 16;
+  const int relPathSegDot2 = 17;
+  const int pathSegDot = 18;
+  const int pathSegDot2 = 19;
+
+  // States used to validate a scheme after its end position has been found.
+  const int scheme0 = _schemeStart;
+  const int scheme = 21;
+
+  // Constants encoding the write-index for the state transition into the top 5
+  // bits of a byte.
+  const int schemeEnd = _schemeEndIndex << 5;
+  const int hostStart = _hostStartIndex << 5;
+  const int portStart = _portStartIndex << 5;
+  const int pathStart = _pathStartIndex << 5;
+  const int queryStart = _queryStartIndex << 5;
+  const int fragmentStart = _fragmentStartIndex << 5;
+  const int notSimple = _notSimpleIndex << 5;
+
+  /// The `unreserved` characters of RFC 3986.
+  const unreserved =
+      "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-._~";
+
+  /// The `sub-delim` characters of RFC 3986.
+  const subDelims = r"!$&'()*+,;=";
+  // The `pchar` characters of RFC 3986: characters that may occur in a path,
+  // excluding escapes.
+  const pchar = "$unreserved$subDelims";
+
+  var tables = List<Uint8List>.generate(stateCount, (_) => Uint8List(96));
+
+  // Helper function which initialize the table for [state] with a default
+  // transition and returns the table.
+  Uint8List build(state, defaultTransition) =>
+      tables[state]..fillRange(0, 96, defaultTransition);
+
+  // Helper function which sets the transition for each character in [chars]
+  // to [transition] in the [target] table.
+  // The [chars] string must contain only characters in the U+0020 .. U+007E
+  // range.
+  void setChars(Uint8List target, String chars, int transition) {
+    for (int i = 0; i < chars.length; i++) {
+      var char = chars.codeUnitAt(i);
+      target[char ^ 0x60] = transition;
+    }
+  }
+
+  /// Helper function which sets the transition for all characters in the
+  /// range from `range[0]` to `range[1]` to [transition] in the [target] table.
+  ///
+  /// The [range] must be a two-character string where both characters are in
+  /// the U+0020 .. U+007E range and the former character must have a lower
+  /// code point than the latter.
+  void setRange(Uint8List target, String range, int transition) {
+    for (int i = range.codeUnitAt(0), n = range.codeUnitAt(1); i <= n; i++) {
+      target[i ^ 0x60] = transition;
+    }
+  }
+
+  // Create the transitions for each state.
+  var b;
+
+  // Validate as path, if it is a scheme, we handle it later.
+  b = build(_uriStart, schemeOrPath | notSimple);
+  setChars(b, pchar, schemeOrPath);
+  setChars(b, ".", schemeOrPathDot);
+  setChars(b, ":", authOrPath | schemeEnd); // Handle later.
+  setChars(b, "/", authOrPathSlash);
+  setChars(b, "?", query | queryStart);
+  setChars(b, "#", fragment | fragmentStart);
+
+  b = build(schemeOrPathDot, schemeOrPath | notSimple);
+  setChars(b, pchar, schemeOrPath);
+  setChars(b, ".", schemeOrPathDot2);
+  setChars(b, ':', authOrPath | schemeEnd);
+  setChars(b, "/", pathSeg | notSimple);
+  setChars(b, "?", query | queryStart);
+  setChars(b, "#", fragment | fragmentStart);
+
+  b = build(schemeOrPathDot2, schemeOrPath | notSimple);
+  setChars(b, pchar, schemeOrPath);
+  setChars(b, "%", schemeOrPath | notSimple);
+  setChars(b, ':', authOrPath | schemeEnd);
+  setChars(b, "/", relPathSeg);
+  setChars(b, "?", query | queryStart);
+  setChars(b, "#", fragment | fragmentStart);
+
+  b = build(schemeOrPath, schemeOrPath | notSimple);
+  setChars(b, pchar, schemeOrPath);
+  setChars(b, ':', authOrPath | schemeEnd);
+  setChars(b, "/", pathSeg);
+  setChars(b, "?", query | queryStart);
+  setChars(b, "#", fragment | fragmentStart);
+
+  b = build(authOrPath, path | notSimple);
+  setChars(b, pchar, path | pathStart);
+  setChars(b, "/", authOrPathSlash | pathStart);
+  setChars(b, ".", pathSegDot | pathStart);
+  setChars(b, "?", query | queryStart);
+  setChars(b, "#", fragment | fragmentStart);
+
+  b = build(authOrPathSlash, path | notSimple);
+  setChars(b, pchar, path);
+  setChars(b, "/", uinfoOrHost0 | hostStart);
+  setChars(b, ".", pathSegDot);
+  setChars(b, "?", query | queryStart);
+  setChars(b, "#", fragment | fragmentStart);
+
+  b = build(uinfoOrHost0, uinfoOrHost | notSimple);
+  setChars(b, pchar, uinfoOrHost);
+  setRange(b, "AZ", uinfoOrHost | notSimple);
+  setChars(b, ":", uinfoOrPort0 | portStart);
+  setChars(b, "@", uinfoOrHost0 | hostStart);
+  setChars(b, "[", ipv6Host | notSimple);
+  setChars(b, "/", pathSeg | pathStart);
+  setChars(b, "?", query | queryStart);
+  setChars(b, "#", fragment | fragmentStart);
+
+  b = build(uinfoOrHost, uinfoOrHost | notSimple);
+  setChars(b, pchar, uinfoOrHost);
+  setRange(b, "AZ", uinfoOrHost | notSimple);
+  setChars(b, ":", uinfoOrPort0 | portStart);
+  setChars(b, "@", uinfoOrHost0 | hostStart);
+  setChars(b, "/", pathSeg | pathStart);
+  setChars(b, "?", query | queryStart);
+  setChars(b, "#", fragment | fragmentStart);
+
+  b = build(uinfoOrPort0, uinfoOrPort | notSimple);
+  setRange(b, "19", uinfoOrPort);
+  setChars(b, "@", uinfoOrHost0 | hostStart);
+  setChars(b, "/", pathSeg | pathStart);
+  setChars(b, "?", query | queryStart);
+  setChars(b, "#", fragment | fragmentStart);
+
+  b = build(uinfoOrPort, uinfoOrPort | notSimple);
+  setRange(b, "09", uinfoOrPort);
+  setChars(b, "@", uinfoOrHost0 | hostStart);
+  setChars(b, "/", pathSeg | pathStart);
+  setChars(b, "?", query | queryStart);
+  setChars(b, "#", fragment | fragmentStart);
+
+  b = build(ipv6Host, ipv6Host);
+  setChars(b, "]", uinfoOrHost);
+
+  b = build(relPathSeg, path | notSimple);
+  setChars(b, pchar, path);
+  setChars(b, ".", relPathSegDot);
+  setChars(b, "/", pathSeg | notSimple);
+  setChars(b, "?", query | queryStart);
+  setChars(b, "#", fragment | fragmentStart);
+
+  b = build(relPathSegDot, path | notSimple);
+  setChars(b, pchar, path);
+  setChars(b, ".", relPathSegDot2);
+  setChars(b, "/", pathSeg | notSimple);
+  setChars(b, "?", query | queryStart);
+  setChars(b, "#", fragment | fragmentStart);
+
+  b = build(relPathSegDot2, path | notSimple);
+  setChars(b, pchar, path);
+  setChars(b, "/", relPathSeg);
+  setChars(b, "?", query | queryStart); // This should be non-simple.
+  setChars(b, "#", fragment | fragmentStart); // This should be non-simple.
+
+  b = build(pathSeg, path | notSimple);
+  setChars(b, pchar, path);
+  setChars(b, ".", pathSegDot);
+  setChars(b, "/", pathSeg | notSimple);
+  setChars(b, "?", query | queryStart);
+  setChars(b, "#", fragment | fragmentStart);
+
+  b = build(pathSegDot, path | notSimple);
+  setChars(b, pchar, path);
+  setChars(b, ".", pathSegDot2);
+  setChars(b, "/", pathSeg | notSimple);
+  setChars(b, "?", query | queryStart);
+  setChars(b, "#", fragment | fragmentStart);
+
+  b = build(pathSegDot2, path | notSimple);
+  setChars(b, pchar, path);
+  setChars(b, "/", pathSeg | notSimple);
+  setChars(b, "?", query | queryStart);
+  setChars(b, "#", fragment | fragmentStart);
+
+  b = build(path, path | notSimple);
+  setChars(b, pchar, path);
+  setChars(b, "/", pathSeg);
+  setChars(b, "?", query | queryStart);
+  setChars(b, "#", fragment | fragmentStart);
+
+  b = build(query, query | notSimple);
+  setChars(b, pchar, query);
+  setChars(b, "?", query);
+  setChars(b, "#", fragment | fragmentStart);
+
+  b = build(fragment, fragment | notSimple);
+  setChars(b, pchar, fragment);
+  setChars(b, "?", fragment);
+
+  // A separate two-state validator for lower-case scheme names.
+  // Any non-scheme character or upper-case letter is marked as non-simple.
+  b = build(scheme0, scheme | notSimple);
+  setRange(b, "az", scheme);
+
+  b = build(scheme, scheme | notSimple);
+  setRange(b, "az", scheme);
+  setRange(b, "09", scheme);
+  setChars(b, "+-.", scheme);
+
+  return tables;
+}
+
+// --------------------------------------------------------------------
+// Code that uses the URI scanner table.
+
+/// Scan a string using the [_scannerTables] state machine.
+///
+/// Scans [uri] from [start] to [end], starting in state [state] and
+/// writing output into [indices].
+///
+/// Returns the final state.
+int _scan(String uri, int start, int end, int state, List<int> indices) {
+  var tables = _scannerTables;
+  assert(end <= uri.length);
+  for (int i = start; i < end; i++) {
+    var table = tables[state];
+    // Xor with 0x60 to move range 0x20-0x7f into 0x00-0x5f
+    int char = uri.codeUnitAt(i) ^ 0x60;
+    // Use 0x1f (nee 0x7f) to represent all unhandled characters.
+    if (char > 0x5f) char = 0x1f;
+    int transition = table[char];
+    state = transition & 0x1f;
+    indices[transition >> 5] = i;
+  }
+  return state;
+}
+
+class _SimpleUri implements Uri {
+  final String _uri;
+  final int _schemeEnd;
+  final int _hostStart;
+  final int _portStart;
+  final int _pathStart;
+  final int _queryStart;
+  final int _fragmentStart;
+
+  /// The scheme is often used to distinguish URIs.
+  /// To make comparisons more efficient, we cache the value, and
+  /// canonicalize a few known types.
+  String _schemeCache;
+  int _hashCodeCache;
+
+  _SimpleUri(
+      this._uri,
+      this._schemeEnd,
+      this._hostStart,
+      this._portStart,
+      this._pathStart,
+      this._queryStart,
+      this._fragmentStart,
+      this._schemeCache);
+
+  bool get hasScheme => _schemeEnd > 0;
+  bool get hasAuthority => _hostStart > 0;
+  bool get hasUserInfo => _hostStart > _schemeEnd + 4;
+  bool get hasPort => _hostStart > 0 && _portStart + 1 < _pathStart;
+  bool get hasQuery => _queryStart < _fragmentStart;
+  bool get hasFragment => _fragmentStart < _uri.length;
+
+  bool get _isFile => _schemeEnd == 4 && _uri.startsWith("file");
+  bool get _isHttp => _schemeEnd == 4 && _uri.startsWith("http");
+  bool get _isHttps => _schemeEnd == 5 && _uri.startsWith("https");
+  bool get _isPackage => _schemeEnd == 7 && _uri.startsWith("package");
+
+  /// Like [isScheme] but expects argument to be case normalized.
+  bool _isScheme(String scheme) =>
+      _schemeEnd == scheme.length && _uri.startsWith(scheme);
+
+  bool get hasAbsolutePath => _uri.startsWith("/", _pathStart);
+  bool get hasEmptyPath => _pathStart == _queryStart;
+
+  bool get isAbsolute => hasScheme && !hasFragment;
+
+  bool isScheme(String scheme) {
+    if (scheme == null || scheme.isEmpty) return _schemeEnd < 0;
+    if (scheme.length != _schemeEnd) return false;
+    return _Uri._compareScheme(scheme, _uri);
+  }
+
+  String get scheme {
+    if (_schemeEnd <= 0) return "";
+    if (_schemeCache != null) return _schemeCache;
+    if (_isHttp) {
+      _schemeCache = "http";
+    } else if (_isHttps) {
+      _schemeCache = "https";
+    } else if (_isFile) {
+      _schemeCache = "file";
+    } else if (_isPackage) {
+      _schemeCache = "package";
+    } else {
+      _schemeCache = _uri.substring(0, _schemeEnd);
+    }
+    return _schemeCache;
+  }
+
+  String get authority =>
+      _hostStart > 0 ? _uri.substring(_schemeEnd + 3, _pathStart) : "";
+  String get userInfo => (_hostStart > _schemeEnd + 3)
+      ? _uri.substring(_schemeEnd + 3, _hostStart - 1)
+      : "";
+  String get host =>
+      _hostStart > 0 ? _uri.substring(_hostStart, _portStart) : "";
+  int get port {
+    if (hasPort) return int.parse(_uri.substring(_portStart + 1, _pathStart));
+    if (_isHttp) return 80;
+    if (_isHttps) return 443;
+    return 0;
+  }
+
+  String get path => _uri.substring(_pathStart, _queryStart);
+  String get query => (_queryStart < _fragmentStart)
+      ? _uri.substring(_queryStart + 1, _fragmentStart)
+      : "";
+  String get fragment =>
+      (_fragmentStart < _uri.length) ? _uri.substring(_fragmentStart + 1) : "";
+
+  String get origin {
+    // Check original behavior - W3C spec is wonky!
+    bool isHttp = _isHttp;
+    if (_schemeEnd < 0) {
+      throw StateError("Cannot use origin without a scheme: $this");
+    }
+    if (!isHttp && !_isHttps) {
+      throw StateError(
+          "Origin is only applicable to schemes http and https: $this");
+    }
+    if (_hostStart == _portStart) {
+      throw StateError(
+          "A $scheme: URI should have a non-empty host name: $this");
+    }
+    if (_hostStart == _schemeEnd + 3) {
+      return _uri.substring(0, _pathStart);
+    }
+    // Need to drop anon-empty userInfo.
+    return _uri.substring(0, _schemeEnd + 3) +
+        _uri.substring(_hostStart, _pathStart);
+  }
+
+  List<String> get pathSegments {
+    int start = _pathStart;
+    int end = _queryStart;
+    if (_uri.startsWith("/", start)) start++;
+    if (start == end) return const <String>[];
+    List<String> parts = [];
+    for (int i = start; i < end; i++) {
+      var char = _uri.codeUnitAt(i);
+      if (char == _SLASH) {
+        parts.add(_uri.substring(start, i));
+        start = i + 1;
+      }
+    }
+    parts.add(_uri.substring(start, end));
+    return List<String>.unmodifiable(parts);
+  }
+
+  Map<String, String> get queryParameters {
+    if (!hasQuery) return const <String, String>{};
+    return UnmodifiableMapView<String, String>(Uri.splitQueryString(query));
+  }
+
+  Map<String, List<String>> get queryParametersAll {
+    if (!hasQuery) return const <String, List<String>>{};
+    Map queryParameterLists = _Uri._splitQueryStringAll(query);
+    for (var key in queryParameterLists.keys) {
+      queryParameterLists[key] =
+          List<String>.unmodifiable(queryParameterLists[key]);
+    }
+    return Map<String, List<String>>.unmodifiable(queryParameterLists);
+  }
+
+  bool _isPort(String port) {
+    int portDigitStart = _portStart + 1;
+    return portDigitStart + port.length == _pathStart &&
+        _uri.startsWith(port, portDigitStart);
+  }
+
+  Uri normalizePath() => this;
+
+  Uri removeFragment() {
+    if (!hasFragment) return this;
+    return _SimpleUri(_uri.substring(0, _fragmentStart), _schemeEnd, _hostStart,
+        _portStart, _pathStart, _queryStart, _fragmentStart, _schemeCache);
+  }
+
+  Uri replace(
+      {String scheme,
+      String userInfo,
+      String host,
+      int port,
+      String path,
+      Iterable<String> pathSegments,
+      String query,
+      Map<String, dynamic /*String|Iterable<String>*/ > queryParameters,
+      String fragment}) {
+    bool schemeChanged = false;
+    if (scheme != null) {
+      scheme = _Uri._makeScheme(scheme, 0, scheme.length);
+      schemeChanged = !_isScheme(scheme);
+    } else {
+      scheme = this.scheme;
+    }
+    bool isFile = (scheme == "file");
+    if (userInfo != null) {
+      userInfo = _Uri._makeUserInfo(userInfo, 0, userInfo.length);
+    } else if (_hostStart > 0) {
+      userInfo = _uri.substring(_schemeEnd + 3, _hostStart);
+    } else {
+      userInfo = "";
+    }
+    if (port != null) {
+      port = _Uri._makePort(port, scheme);
+    } else {
+      port = this.hasPort ? this.port : null;
+      if (schemeChanged) {
+        // The default port might have changed.
+        port = _Uri._makePort(port, scheme);
+      }
+    }
+    if (host != null) {
+      host = _Uri._makeHost(host, 0, host.length, false);
+    } else if (_hostStart > 0) {
+      host = _uri.substring(_hostStart, _portStart);
+    } else if (userInfo.isNotEmpty || port != null || isFile) {
+      host = "";
+    }
+
+    bool hasAuthority = host != null;
+    if (path != null || pathSegments != null) {
+      path = _Uri._makePath(path, 0, _stringOrNullLength(path), pathSegments,
+          scheme, hasAuthority);
+    } else {
+      path = _uri.substring(_pathStart, _queryStart);
+      if ((isFile || (hasAuthority && !path.isEmpty)) &&
+          !path.startsWith('/')) {
+        path = "/" + path;
+      }
+    }
+
+    if (query != null || queryParameters != null) {
+      query = _Uri._makeQuery(
+          query, 0, _stringOrNullLength(query), queryParameters);
+    } else if (_queryStart < _fragmentStart) {
+      query = _uri.substring(_queryStart + 1, _fragmentStart);
+    }
+
+    if (fragment != null) {
+      fragment = _Uri._makeFragment(fragment, 0, fragment.length);
+    } else if (_fragmentStart < _uri.length) {
+      fragment = _uri.substring(_fragmentStart + 1);
+    }
+
+    return _Uri._internal(scheme, userInfo, host, port, path, query, fragment);
+  }
+
+  Uri resolve(String reference) {
+    return resolveUri(Uri.parse(reference));
+  }
+
+  Uri resolveUri(Uri reference) {
+    if (reference is _SimpleUri) {
+      return _simpleMerge(this, reference);
+    }
+    return _toNonSimple().resolveUri(reference);
+  }
+
+  // Merge two simple URIs. This should always result in a prefix of
+  // one concatenated with a suffix of the other, possibly with a `/` in
+  // the middle of two merged paths, which is again simple.
+  // In a few cases, there might be a need for extra normalization, when
+  // resolving on top of a known scheme.
+  Uri _simpleMerge(_SimpleUri base, _SimpleUri ref) {
+    if (ref.hasScheme) return ref;
+    if (ref.hasAuthority) {
+      if (!base.hasScheme) return ref;
+      bool isSimple = true;
+      if (base._isFile) {
+        isSimple = !ref.hasEmptyPath;
+      } else if (base._isHttp) {
+        isSimple = !ref._isPort("80");
+      } else if (base._isHttps) {
+        isSimple = !ref._isPort("443");
+      }
+      if (isSimple) {
+        var delta = base._schemeEnd + 1;
+        var newUri = base._uri.substring(0, base._schemeEnd + 1) +
+            ref._uri.substring(ref._schemeEnd + 1);
+        return _SimpleUri(
+            newUri,
+            base._schemeEnd,
+            ref._hostStart + delta,
+            ref._portStart + delta,
+            ref._pathStart + delta,
+            ref._queryStart + delta,
+            ref._fragmentStart + delta,
+            base._schemeCache);
+      } else {
+        // This will require normalization, so use the _Uri implementation.
+        return _toNonSimple().resolveUri(ref);
+      }
+    }
+    if (ref.hasEmptyPath) {
+      if (ref.hasQuery) {
+        int delta = base._queryStart - ref._queryStart;
+        var newUri = base._uri.substring(0, base._queryStart) +
+            ref._uri.substring(ref._queryStart);
+        return _SimpleUri(
+            newUri,
+            base._schemeEnd,
+            base._hostStart,
+            base._portStart,
+            base._pathStart,
+            ref._queryStart + delta,
+            ref._fragmentStart + delta,
+            base._schemeCache);
+      }
+      if (ref.hasFragment) {
+        int delta = base._fragmentStart - ref._fragmentStart;
+        var newUri = base._uri.substring(0, base._fragmentStart) +
+            ref._uri.substring(ref._fragmentStart);
+        return _SimpleUri(
+            newUri,
+            base._schemeEnd,
+            base._hostStart,
+            base._portStart,
+            base._pathStart,
+            base._queryStart,
+            ref._fragmentStart + delta,
+            base._schemeCache);
+      }
+      return base.removeFragment();
+    }
+    if (ref.hasAbsolutePath) {
+      var delta = base._pathStart - ref._pathStart;
+      var newUri = base._uri.substring(0, base._pathStart) +
+          ref._uri.substring(ref._pathStart);
+      return _SimpleUri(
+          newUri,
+          base._schemeEnd,
+          base._hostStart,
+          base._portStart,
+          base._pathStart,
+          ref._queryStart + delta,
+          ref._fragmentStart + delta,
+          base._schemeCache);
+    }
+    if (base.hasEmptyPath && base.hasAuthority) {
+      // ref has relative non-empty path.
+      // Add a "/" in front, then leading "/../" segments are folded to "/".
+      int refStart = ref._pathStart;
+      while (ref._uri.startsWith("../", refStart)) {
+        refStart += 3;
+      }
+      var delta = base._pathStart - refStart + 1;
+      var newUri = "${base._uri.substring(0, base._pathStart)}/"
+          "${ref._uri.substring(refStart)}";
+      return _SimpleUri(
+          newUri,
+          base._schemeEnd,
+          base._hostStart,
+          base._portStart,
+          base._pathStart,
+          ref._queryStart + delta,
+          ref._fragmentStart + delta,
+          base._schemeCache);
+    }
+    // Merge paths.
+
+    // The RFC 3986 algorithm merges the base path without its final segment
+    // (anything after the final "/", or everything if the base path doesn't
+    // contain any "/"), and the reference path.
+    // Then it removes "." and ".." segments using the remove-dot-segment
+    // algorithm.
+    // This code combines the two steps. It is simplified by knowing that
+    // the base path contains no "." or ".." segments, and the reference
+    // path can only contain leading ".." segments.
+
+    String baseUri = base._uri;
+    String refUri = ref._uri;
+    int baseStart = base._pathStart;
+    int baseEnd = base._queryStart;
+    while (baseUri.startsWith("../", baseStart)) baseStart += 3;
+    int refStart = ref._pathStart;
+    int refEnd = ref._queryStart;
+
+    /// Count of leading ".." segments in reference path.
+    /// The count is decremented when the segment is matched with a
+    /// segment of the base path, and both are then omitted from the result.
+    int backCount = 0;
+
+    /// Count "../" segments and advance `refStart` to after the segments.
+    while (refStart + 3 <= refEnd && refUri.startsWith("../", refStart)) {
+      refStart += 3;
+      backCount += 1;
+    }
+
+    // Extra slash inserted between base and reference path parts if
+    // the base path contains any slashes, or empty string if none.
+    // (We could use a slash from the base path in most cases, but not if
+    // we remove the entire base path).
+    String insert = "";
+
+    /// Remove segments from the base path.
+    /// Start with the segment trailing the last slash,
+    /// then remove segments for each leading "../" segment
+    /// from the reference path, or as many of them as are available.
+    while (baseEnd > baseStart) {
+      baseEnd--;
+      int char = baseUri.codeUnitAt(baseEnd);
+      if (char == _SLASH) {
+        insert = "/";
+        if (backCount == 0) break;
+        backCount--;
+      }
+    }
+
+    if (baseEnd == baseStart && !base.hasScheme && !base.hasAbsolutePath) {
+      // If the base is *just* a relative path (no scheme or authority),
+      // then merging with another relative path doesn't follow the
+      // RFC-3986 behavior.
+      // Don't need to check `base.hasAuthority` since the base path is
+      // non-empty - if there is an authority, a non-empty path is absolute.
+
+      // We reached the start of the base path, and want to stay relative,
+      // so don't insert a slash.
+      insert = "";
+      // If we reached the start of the base path with more "../" left over
+      // in the reference path, include those segments in the result.
+      refStart -= backCount * 3;
+    }
+
+    var delta = baseEnd - refStart + insert.length;
+    var newUri = "${base._uri.substring(0, baseEnd)}$insert"
+        "${ref._uri.substring(refStart)}";
+
+    return _SimpleUri(
+        newUri,
+        base._schemeEnd,
+        base._hostStart,
+        base._portStart,
+        base._pathStart,
+        ref._queryStart + delta,
+        ref._fragmentStart + delta,
+        base._schemeCache);
+  }
+
+  String toFilePath({bool windows}) {
+    if (_schemeEnd >= 0 && !_isFile) {
+      throw UnsupportedError("Cannot extract a file path from a $scheme URI");
+    }
+    if (_queryStart < _uri.length) {
+      if (_queryStart < _fragmentStart) {
+        throw UnsupportedError(
+            "Cannot extract a file path from a URI with a query component");
+      }
+      throw UnsupportedError(
+          "Cannot extract a file path from a URI with a fragment component");
+    }
+    windows ??= _Uri._isWindows;
+    return windows ? _Uri._toWindowsFilePath(this) : _toFilePath();
+  }
+
+  String _toFilePath() {
+    if (_hostStart < _portStart) {
+      // Has authority and non-empty host.
+      throw UnsupportedError(
+          "Cannot extract a non-Windows file path from a file URI "
+          "with an authority");
+    }
+    return this.path;
+  }
+
+  UriData get data {
+    assert(scheme != "data");
+    return null;
+  }
+
+  int get hashCode => _hashCodeCache ??= _uri.hashCode;
+
+  bool operator ==(Object other) {
+    if (identical(this, other)) return true;
+    return other is Uri && _uri == other.toString();
+  }
+
+  Uri _toNonSimple() {
+    return _Uri._internal(
+        this.scheme,
+        this.userInfo,
+        this.hasAuthority ? this.host : null,
+        this.hasPort ? this.port : null,
+        this.path,
+        this.hasQuery ? this.query : null,
+        this.hasFragment ? this.fragment : null);
+  }
+
+  String toString() => _uri;
+}
+
+/// Special [_Uri] created from an existing [UriData].
+class _DataUri extends _Uri {
+  final UriData _data;
+
+  _DataUri(this._data, String path, String query)
+      : super._internal("data", null, null, null, path, query, null);
+
+  UriData get data => _data;
+}
+
+/// Checks whether [text] starts with "data:" at position [start].
+///
+/// The text must be long enough to allow reading five characters
+/// from the [start] position.
+///
+/// Returns an integer value which is zero if text starts with all-lowercase
+/// "data:" and 0x20 if the text starts with "data:" that isn't all lower-case.
+/// All other values means the text starts with some other character.
+int _startsWithData(String text, int start) {
+  // Multiply by 3 to avoid a non-colon character making delta be 0x20.
+  int delta = (text.codeUnitAt(start + 4) ^ _COLON) * 3;
+  delta |= text.codeUnitAt(start) ^ 0x64 /*d*/;
+  delta |= text.codeUnitAt(start + 1) ^ 0x61 /*a*/;
+  delta |= text.codeUnitAt(start + 2) ^ 0x74 /*t*/;
+  delta |= text.codeUnitAt(start + 3) ^ 0x61 /*a*/;
+  return delta;
+}
+
+/// Helper function returning the length of a string, or `0` for `null`.
+int _stringOrNullLength(String s) => (s == null) ? 0 : s.length;
diff --git a/sdk_nnbd/lib/developer/developer.dart b/sdk_nnbd/lib/developer/developer.dart
new file mode 100644
index 0000000..c446fdf
--- /dev/null
+++ b/sdk_nnbd/lib/developer/developer.dart
@@ -0,0 +1,67 @@
+// Copyright (c) 2015, 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.
+
+/// Interact with developer tools such as the debugger and inspector.
+///
+/// This library is platform dependent and has separate implementations for
+/// both web and the Dart VM. A specific platform may not support all
+/// operations.
+///
+/// To use this library in your code:
+///
+///     import 'dart:developer';
+///
+/// {@category Core}
+library dart.developer;
+
+import 'dart:async';
+import 'dart:convert';
+import 'dart:isolate' show Isolate, RawReceivePort, SendPort;
+
+part 'extension.dart';
+part 'profiler.dart';
+part 'service.dart';
+part 'timeline.dart';
+
+/// If [when] is true, stop the program as if a breakpoint were hit at the
+/// following statement.
+///
+/// Returns the value of [when]. Some debuggers may display [message].
+///
+/// NOTE: When invoked, the isolate will not return until a debugger
+/// continues execution. When running in the Dart VM, the behaviour is the same
+/// regardless of whether or not a debugger is connected. When compiled to
+/// JavaScript, this uses the "debugger" statement, and behaves exactly as
+/// that does.
+external bool debugger({bool when: true, String message});
+
+/// Send a reference to [object] to any attached debuggers.
+///
+/// Debuggers may open an inspector on the object. Returns the argument.
+external Object inspect(Object object);
+
+/// Emit a log event.
+///
+/// This function was designed to map closely to the logging information
+/// collected by `package:logging`.
+///
+/// - [message] is the log message
+/// - [time] (optional) is the timestamp
+/// - [sequenceNumber] (optional) is a monotonically increasing sequence number
+/// - [level] (optional) is the severity level (a value between 0 and 2000); see
+///   the `package:logging` `Level` class for an overview of the possible values
+/// - [name] (optional) is the name of the source of the log message
+/// - [zone] (optional) the zone where the log was emitted
+/// - [error] (optional) an error object associated with this log event
+/// - [stackTrace] (optional) a stack trace associated with this log event
+external void log(
+  String message, {
+  DateTime time,
+  int sequenceNumber,
+  int level: 0,
+  String name: '',
+  Zone zone,
+  Object error,
+  StackTrace stackTrace,
+});
diff --git a/sdk_nnbd/lib/developer/developer_sources.gni b/sdk_nnbd/lib/developer/developer_sources.gni
new file mode 100644
index 0000000..df0dbc2
--- /dev/null
+++ b/sdk_nnbd/lib/developer/developer_sources.gni
@@ -0,0 +1,13 @@
+# 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.
+
+developer_sdk_sources = [
+  "developer.dart",
+
+  # The above file needs to be first if additional parts are added to the lib.
+  "extension.dart",
+  "profiler.dart",
+  "service.dart",
+  "timeline.dart",
+]
diff --git a/sdk_nnbd/lib/developer/extension.dart b/sdk_nnbd/lib/developer/extension.dart
new file mode 100644
index 0000000..3cc4ede
--- /dev/null
+++ b/sdk_nnbd/lib/developer/extension.dart
@@ -0,0 +1,161 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.developer;
+
+/// A response to a service protocol extension RPC.
+///
+/// If the RPC was successful, use [ServiceExtensionResponse.result], otherwise
+/// use [ServiceExtensionResponse.error].
+class ServiceExtensionResponse {
+  /// The result of a successful service protocol extension RPC.
+  final String result;
+
+  /// The error code associated with a failed service protocol extension RPC.
+  final int errorCode;
+
+  /// The details of a failed service protocol extension RPC.
+  final String errorDetail;
+
+  /// Creates a successful response to a service protocol extension RPC.
+  ///
+  /// Requires [result] to be a JSON object encoded as a string. When forming
+  /// the JSON-RPC message [result] will be inlined directly.
+  ServiceExtensionResponse.result(String result)
+      : result = result,
+        errorCode = null,
+        errorDetail = null {
+    ArgumentError.checkNotNull(result, "result");
+  }
+
+  /// Creates an error response to a service protocol extension RPC.
+  ///
+  /// Requires [errorCode] to be [invalidParams] or between [extensionErrorMin]
+  /// and [extensionErrorMax]. Requires [errorDetail] to be a JSON object
+  /// encoded as a string. When forming the JSON-RPC message [errorDetail] will
+  /// be inlined directly.
+  ServiceExtensionResponse.error(int errorCode, String errorDetail)
+      : result = null,
+        errorCode = errorCode,
+        errorDetail = errorDetail {
+    _validateErrorCode(errorCode);
+    ArgumentError.checkNotNull(errorDetail, "errorDetail");
+  }
+
+  /// Invalid method parameter(s) error code.
+  @deprecated
+  static const kInvalidParams = invalidParams;
+
+  /// Generic extension error code.
+  @deprecated
+  static const kExtensionError = extensionError;
+
+  /// Maximum extension provided error code.
+  @deprecated
+  static const kExtensionErrorMax = extensionErrorMax;
+
+  /// Minimum extension provided error code.
+  @deprecated
+  static const kExtensionErrorMin = extensionErrorMin;
+
+  /// Invalid method parameter(s) error code.
+  static const invalidParams = -32602;
+
+  /// Generic extension error code.
+  static const extensionError = -32000;
+
+  /// Maximum extension provided error code.
+  static const extensionErrorMax = -32000;
+
+  /// Minimum extension provided error code.
+  static const extensionErrorMin = -32016;
+
+  static String _errorCodeMessage(int errorCode) {
+    _validateErrorCode(errorCode);
+    if (errorCode == invalidParams) {
+      return "Invalid params";
+    }
+    return "Server error";
+  }
+
+  static _validateErrorCode(int errorCode) {
+    ArgumentError.checkNotNull(errorCode, "errorCode");
+    if (errorCode == invalidParams) return;
+    if ((errorCode >= extensionErrorMin) && (errorCode <= extensionErrorMax)) {
+      return;
+    }
+    throw new ArgumentError.value(errorCode, "errorCode", "Out of range");
+  }
+
+  /// Determines if this response represents an error.
+  bool isError() => (errorCode != null) && (errorDetail != null);
+
+  // ignore: unused_element, called from runtime/lib/developer.dart
+  String _toString() {
+    if (result != null) {
+      return result;
+    } else {
+      assert(errorCode != null);
+      assert(errorDetail != null);
+      return json.encode({
+        'code': errorCode,
+        'message': _errorCodeMessage(errorCode),
+        'data': {'details': errorDetail}
+      });
+    }
+  }
+}
+
+/// A service protocol extension handler. Registered with [registerExtension].
+///
+/// Must complete to a [ServiceExtensionResponse]. [method] is the method name
+/// of the service protocol request, and [parameters] is a map holding the
+/// parameters to the service protocol request.
+///
+/// *NOTE*: all parameter names and values are encoded as strings.
+typedef Future<ServiceExtensionResponse> ServiceExtensionHandler(
+    String method, Map<String, String> parameters);
+
+/// Register a [ServiceExtensionHandler] that will be invoked in this isolate
+/// for [method]. *NOTE*: Service protocol extensions must be registered
+/// in each isolate.
+///
+/// *NOTE*: [method] must begin with 'ext.' and you should use the following
+/// structure to avoid conflicts with other packages: 'ext.package.command'.
+/// That is, immediately following the 'ext.' prefix, should be the registering
+/// package name followed by another period ('.') and then the command name.
+/// For example: 'ext.dart.io.getOpenFiles'.
+///
+/// Because service extensions are isolate specific, clients using extensions
+/// must always include an 'isolateId' parameter with each RPC.
+void registerExtension(String method, ServiceExtensionHandler handler) {
+  ArgumentError.checkNotNull(method, 'method');
+  if (!method.startsWith('ext.')) {
+    throw new ArgumentError.value(method, 'method', 'Must begin with ext.');
+  }
+  if (_lookupExtension(method) != null) {
+    throw new ArgumentError('Extension already registered: $method');
+  }
+  ArgumentError.checkNotNull(handler, 'handler');
+  _registerExtension(method, handler);
+}
+
+/// Post an event of [eventKind] with payload of [eventData] to the `Extension`
+/// event stream.
+void postEvent(String eventKind, Map eventData) {
+  ArgumentError.checkNotNull(eventKind, 'eventKind');
+  ArgumentError.checkNotNull(eventData, 'eventData');
+  String eventDataAsString = json.encode(eventData);
+  _postEvent(eventKind, eventDataAsString);
+}
+
+external void _postEvent(String eventKind, String eventData);
+
+// Both of these functions are written inside C++ to avoid updating the data
+// structures in Dart, getting an OOB, and observing stale state. Do not move
+// these into Dart code unless you can ensure that the operations will can be
+// done atomically. Native code lives in vm/isolate.cc-
+// LookupServiceExtensionHandler and RegisterServiceExtensionHandler.
+external ServiceExtensionHandler _lookupExtension(String method);
+external _registerExtension(String method, ServiceExtensionHandler handler);
diff --git a/sdk_nnbd/lib/developer/profiler.dart b/sdk_nnbd/lib/developer/profiler.dart
new file mode 100644
index 0000000..05a9211
--- /dev/null
+++ b/sdk_nnbd/lib/developer/profiler.dart
@@ -0,0 +1,149 @@
+// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.developer;
+
+/// A UserTag can be used to group samples in the Observatory profiler.
+abstract class UserTag {
+  /// The maximum number of UserTag instances that can be created by a program.
+  static const MAX_USER_TAGS = 64;
+
+  external factory UserTag(String label);
+
+  /// Label of [this].
+  String get label;
+
+  /// Make [this] the current tag for the isolate. Returns the current tag
+  /// before setting.
+  UserTag makeCurrent();
+
+  /// The default [UserTag] with label 'Default'.
+  external static UserTag get defaultTag;
+}
+
+/// Returns the current [UserTag] for the isolate.
+external UserTag getCurrentTag();
+
+/// Abstract [Metric] class. Metric names must be unique, are hierarchical,
+/// and use periods as separators. For example, 'a.b.c'. Uniqueness is only
+/// enforced when a Metric is registered. The name of a metric cannot contain
+/// the slash ('/') character.
+abstract class Metric {
+  /// [name] of this metric.
+  final String name;
+
+  /// [description] of this metric.
+  final String description;
+
+  Metric(this.name, this.description) {
+    if ((name == 'vm') || name.contains('/')) {
+      throw new ArgumentError('Invalid Metric name.');
+    }
+  }
+
+  Map _toJSON();
+}
+
+/// A measured value with a min and max. Initial value is min. Value will
+/// be clamped to the interval [min, max].
+class Gauge extends Metric {
+  final double min;
+  final double max;
+
+  double _value;
+  double get value => _value;
+  set value(double v) {
+    if (v < min) {
+      v = min;
+    } else if (v > max) {
+      v = max;
+    }
+    _value = v;
+  }
+
+  Gauge(String name, String description, this.min, this.max)
+      : super(name, description) {
+    ArgumentError.checkNotNull(min, 'min');
+    ArgumentError.checkNotNull(max, 'max');
+    if (!(min < max)) throw new ArgumentError('min must be less than max');
+    _value = min;
+  }
+
+  Map _toJSON() {
+    var map = {
+      'type': 'Gauge',
+      'id': 'metrics/$name',
+      'name': name,
+      'description': description,
+      'value': value,
+      'min': min,
+      'max': max,
+    };
+    return map;
+  }
+}
+
+/// A changing value. Initial value is 0.0.
+class Counter extends Metric {
+  Counter(String name, String description) : super(name, description);
+
+  double _value = 0.0;
+  double get value => _value;
+  set value(double v) {
+    _value = v;
+  }
+
+  Map _toJSON() {
+    var map = {
+      'type': 'Counter',
+      'id': 'metrics/$name',
+      'name': name,
+      'description': description,
+      'value': value,
+    };
+    return map;
+  }
+}
+
+class Metrics {
+  static final Map<String, Metric> _metrics = new Map<String, Metric>();
+
+  /// Register [Metric]s to make them visible to Observatory.
+  static void register(Metric metric) {
+    ArgumentError.checkNotNull(metric, 'metric');
+    if (_metrics[metric.name] != null) {
+      throw new ArgumentError('Registered metrics have unique names');
+    }
+    _metrics[metric.name] = metric;
+  }
+
+  /// Deregister [Metric]s to make them not visible to Observatory.
+  static void deregister(Metric metric) {
+    ArgumentError.checkNotNull(metric, 'metric');
+    _metrics.remove(metric.name);
+  }
+
+  // ignore: unused_element, called from native code
+  static String _printMetric(String id) {
+    var metric = _metrics[id];
+    if (metric == null) {
+      return null;
+    }
+    return json.encode(metric._toJSON());
+  }
+
+  // ignore: unused_element, called from native code
+  @pragma("vm:entry-point", !const bool.fromEnvironment("dart.vm.product"))
+  static String _printMetrics() {
+    var metrics = [];
+    for (var metric in _metrics.values) {
+      metrics.add(metric._toJSON());
+    }
+    var map = {
+      'type': 'MetricList',
+      'metrics': metrics,
+    };
+    return json.encode(map);
+  }
+}
diff --git a/sdk_nnbd/lib/developer/service.dart b/sdk_nnbd/lib/developer/service.dart
new file mode 100644
index 0000000..a4d92b9
--- /dev/null
+++ b/sdk_nnbd/lib/developer/service.dart
@@ -0,0 +1,98 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.developer;
+
+/// Service protocol is the protocol that a client like the Observatory
+/// could use to access the services provided by the Dart VM for
+/// debugging and inspecting Dart programs. This class encapsulates the
+/// version number and Uri for accessing this service.
+class ServiceProtocolInfo {
+  /// The major version of the protocol. If the running Dart environment does
+  /// not support the service protocol, this is 0.
+  final int majorVersion = _getServiceMajorVersion();
+
+  /// The minor version of the protocol. If the running Dart environment does
+  /// not support the service protocol, this is 0.
+  final int minorVersion = _getServiceMinorVersion();
+
+  /// The Uri to access the service. If the web server is not running, this
+  /// will be null.
+  final Uri serverUri;
+
+  ServiceProtocolInfo(this.serverUri);
+
+  String toString() {
+    if (serverUri != null) {
+      return 'Dart VM Service Protocol v$majorVersion.$minorVersion '
+          'listening on $serverUri';
+    } else {
+      return 'Dart VM Service Protocol v$majorVersion.$minorVersion';
+    }
+  }
+}
+
+/// Access information about the service protocol and control the web server
+/// that provides access to the services provided by the Dart VM for
+/// debugging and inspecting Dart programs.
+class Service {
+  /// Get information about the service protocol (version number and
+  /// Uri to access the service).
+  static Future<ServiceProtocolInfo> getInfo() async {
+    // Port to receive response from service isolate.
+    final RawReceivePort receivePort = new RawReceivePort();
+    final Completer<Uri> uriCompleter = new Completer<Uri>();
+    receivePort.handler = (Uri uri) => uriCompleter.complete(uri);
+    // Request the information from the service isolate.
+    _getServerInfo(receivePort.sendPort);
+    // Await the response from the service isolate.
+    Uri uri = await uriCompleter.future;
+    // Close the port.
+    receivePort.close();
+    return new ServiceProtocolInfo(uri);
+  }
+
+  /// Control the web server that the service protocol is accessed through.
+  /// The [enable] argument must be a boolean and is used as a toggle to
+  /// enable (true) or disable (false) the web server servicing requests.
+  static Future<ServiceProtocolInfo> controlWebServer(
+      {bool enable: false}) async {
+    ArgumentError.checkNotNull(enable, 'enable');
+    // Port to receive response from service isolate.
+    final RawReceivePort receivePort = new RawReceivePort();
+    final Completer<Uri> uriCompleter = new Completer<Uri>();
+    receivePort.handler = (Uri uri) => uriCompleter.complete(uri);
+    // Request the information from the service isolate.
+    _webServerControl(receivePort.sendPort, enable);
+    // Await the response from the service isolate.
+    Uri uri = await uriCompleter.future;
+    // Close the port.
+    receivePort.close();
+    return new ServiceProtocolInfo(uri);
+  }
+
+  /// Returns a [String] token representing the ID of [isolate].
+  ///
+  /// Returns null if the running Dart environment does not support the service
+  /// protocol.
+  static String getIsolateID(Isolate isolate) {
+    ArgumentError.checkNotNull(isolate, 'isolate');
+    return _getIsolateIDFromSendPort(isolate.controlPort);
+  }
+}
+
+/// [sendPort] will receive a Uri or null.
+external void _getServerInfo(SendPort sendPort);
+
+/// [sendPort] will receive a Uri or null.
+external void _webServerControl(SendPort sendPort, bool enable);
+
+/// Returns the major version of the service protocol.
+external int _getServiceMajorVersion();
+
+/// Returns the minor version of the service protocol.
+external int _getServiceMinorVersion();
+
+/// Returns the service id for the isolate that owns [sendPort].
+external String _getIsolateIDFromSendPort(SendPort sendPort);
diff --git a/sdk_nnbd/lib/developer/timeline.dart b/sdk_nnbd/lib/developer/timeline.dart
new file mode 100644
index 0000000..02f9c98
--- /dev/null
+++ b/sdk_nnbd/lib/developer/timeline.dart
@@ -0,0 +1,344 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.developer;
+
+const bool _hasTimeline =
+    const bool.fromEnvironment("dart.developer.timeline", defaultValue: true);
+
+/// A typedef for the function argument to [Timeline.timeSync].
+typedef TimelineSyncFunction<T> = T Function();
+
+// TODO: This typedef is not used.
+typedef Future TimelineAsyncFunction();
+
+/// A class to represent Flow events.
+///
+/// [Flow] objects are used to thread flow events between timeline slices,
+/// for example, those created with the [Timeline] class below. Adding
+/// [Flow] objects cause arrows to be drawn between slices in Chrome's trace
+/// viewer. The arrows start at e.g [Timeline] events that are passed a
+/// [Flow.begin] object, go through [Timeline] events that are passed a
+/// [Flow.step] object, and end at [Timeline] events that are passed a
+/// [Flow.end] object, all having the same [Flow.id]. For example:
+///
+/// ```dart
+/// var flow = Flow.begin();
+/// Timeline.timeSync('flow_test', () {
+///   doSomething();
+/// }, flow: flow);
+///
+/// Timeline.timeSync('flow_test', () {
+///   doSomething();
+/// }, flow: Flow.step(flow.id));
+///
+/// Timeline.timeSync('flow_test', () {
+///   doSomething();
+/// }, flow: Flow.end(flow.id));
+/// ```
+class Flow {
+  // These values must be kept in sync with the enum "EventType" in
+  // runtime/vm/timeline.h.
+  static const int _begin = 9;
+  static const int _step = 10;
+  static const int _end = 11;
+
+  final int _type;
+
+  /// The flow id of the flow event.
+  final int id;
+
+  Flow._(this._type, this.id);
+
+  /// A "begin" Flow event.
+  ///
+  /// When passed to a [Timeline] method, generates a "begin" Flow event.
+  /// If [id] is not provided, an id that conflicts with no other Dart-generated
+  /// flow id's will be generated.
+  static Flow begin({int id}) {
+    return new Flow._(_begin, id ?? _getNextAsyncId());
+  }
+
+  /// A "step" Flow event.
+  ///
+  /// When passed to a [Timeline] method, generates a "step" Flow event.
+  /// The [id] argument is required. It can come either from another [Flow]
+  /// event, or some id that comes from the environment.
+  static Flow step(int id) => new Flow._(_step, id);
+
+  /// An "end" Flow event.
+  ///
+  /// When passed to a [Timeline] method, generates a "end" Flow event.
+  /// The [id] argument is required. It can come either from another [Flow]
+  /// event, or some id that comes from the environment.
+  static Flow end(int id) => new Flow._(_end, id);
+}
+
+/// Add to the timeline.
+///
+/// [Timeline]'s methods add synchronous events to the timeline. When
+/// generating a timeline in Chrome's tracing format, using [Timeline] generates
+/// "Complete" events. [Timeline]'s [startSync] and [finishSync] can be used
+/// explicitly, or implicitly by wrapping a closure in [timeSync]. For example:
+///
+/// ```dart
+/// Timeline.startSync("Doing Something");
+/// doSomething();
+/// Timeline.finishSync();
+/// ```
+///
+/// Or:
+///
+/// ```dart
+/// Timeline.timeSync("Doing Something", () {
+///   doSomething();
+/// });
+/// ```
+class Timeline {
+  /// Start a synchronous operation labeled [name]. Optionally takes
+  /// a [Map] of [arguments]. This slice may also optionally be associated with
+  /// a [Flow] event. This operation must be finished before
+  /// returning to the event queue.
+  static void startSync(String name, {Map arguments, Flow flow}) {
+    if (!_hasTimeline) return;
+    ArgumentError.checkNotNull(name, 'name');
+    if (!_isDartStreamEnabled()) {
+      // Push a null onto the stack and return.
+      _stack.add(null);
+      return;
+    }
+    var block = new _SyncBlock._(name, _getTraceClock(), _getThreadCpuClock());
+    if (arguments != null) {
+      block._arguments = arguments;
+    }
+    if (flow != null) {
+      block.flow = flow;
+    }
+    _stack.add(block);
+  }
+
+  /// Finish the last synchronous operation that was started.
+  static void finishSync() {
+    if (!_hasTimeline) {
+      return;
+    }
+    if (_stack.length == 0) {
+      throw new StateError('Uneven calls to startSync and finishSync');
+    }
+    // Pop top item off of stack.
+    var block = _stack.removeLast();
+    if (block == null) {
+      // Dart stream was disabled when startSync was called.
+      return;
+    }
+    // Finish it.
+    block.finish();
+  }
+
+  /// Emit an instant event.
+  static void instantSync(String name, {Map arguments}) {
+    if (!_hasTimeline) return;
+    ArgumentError.checkNotNull(name, 'name');
+    if (!_isDartStreamEnabled()) {
+      // Stream is disabled.
+      return;
+    }
+    Map instantArguments;
+    if (arguments != null) {
+      instantArguments = new Map.from(arguments);
+    }
+    _reportInstantEvent(
+        _getTraceClock(), 'Dart', name, _argumentsAsJson(instantArguments));
+  }
+
+  /// A utility method to time a synchronous [function]. Internally calls
+  /// [function] bracketed by calls to [startSync] and [finishSync].
+  static T timeSync<T>(String name, TimelineSyncFunction<T> function,
+      {Map arguments, Flow flow}) {
+    startSync(name, arguments: arguments, flow: flow);
+    try {
+      return function();
+    } finally {
+      finishSync();
+    }
+  }
+
+  /// The current time stamp from the clock used by the timeline. Units are
+  /// microseconds.
+  ///
+  /// When run on the Dart VM, uses the same monotonic clock as the embedding
+  /// API's `Dart_TimelineGetMicros`.
+  static int get now => _getTraceClock();
+  static final List<_SyncBlock> _stack = new List<_SyncBlock>();
+}
+
+/// An asynchronous task on the timeline. An asynchronous task can have many
+/// (nested) synchronous operations. Synchronous operations can live longer than
+/// the current isolate event. To pass a [TimelineTask] to another isolate,
+/// you must first call [pass] to get the task id and then construct a new
+/// [TimelineTask] in the other isolate.
+class TimelineTask {
+  /// Create a task. The task ID will be set by the system.
+  TimelineTask() : _taskId = _getNextAsyncId() {}
+
+  /// Create a task with an explicit [taskId]. This is useful if you are
+  /// passing a task from one isolate to another.
+  TimelineTask.withTaskId(int taskId) : _taskId = taskId {
+    ArgumentError.checkNotNull(taskId, 'taskId');
+  }
+
+  /// Start a synchronous operation within this task named [name].
+  /// Optionally takes a [Map] of [arguments].
+  void start(String name, {Map arguments}) {
+    if (!_hasTimeline) return;
+    ArgumentError.checkNotNull(name, 'name');
+    var block = new _AsyncBlock._(name, _taskId);
+    _stack.add(block);
+    block._start(arguments);
+  }
+
+  /// Emit an instant event for this task.
+  /// Optionally takes a [Map] of [arguments].
+  void instant(String name, {Map arguments}) {
+    if (!_hasTimeline) return;
+    ArgumentError.checkNotNull(name, 'name');
+    Map instantArguments;
+    if (arguments != null) {
+      instantArguments = new Map.from(arguments);
+    }
+    _reportTaskEvent(_getTraceClock(), _taskId, 'n', 'Dart', name,
+        _argumentsAsJson(instantArguments));
+  }
+
+  /// Finish the last synchronous operation that was started.
+  /// Optionally takes a [Map] of [arguments].
+  void finish({Map arguments}) {
+    if (!_hasTimeline) {
+      return;
+    }
+    if (_stack.length == 0) {
+      throw new StateError('Uneven calls to start and finish');
+    }
+    // Pop top item off of stack.
+    var block = _stack.removeLast();
+    block._finish(arguments);
+  }
+
+  /// Retrieve the [TimelineTask]'s task id. Will throw an exception if the
+  /// stack is not empty.
+  int pass() {
+    if (_stack.length > 0) {
+      throw new StateError(
+          'You cannot pass a TimelineTask without finishing all started '
+          'operations');
+    }
+    int r = _taskId;
+    return r;
+  }
+
+  final int _taskId;
+  final List<_AsyncBlock> _stack = [];
+}
+
+/// An asynchronous block of time on the timeline. This block can be kept
+/// open across isolate messages.
+class _AsyncBlock {
+  /// The category this block belongs to.
+  final String category = 'Dart';
+
+  /// The name of this block.
+  final String name;
+
+  /// The asynchronous task id.
+  final int _taskId;
+
+  _AsyncBlock._(this.name, this._taskId);
+
+  // Emit the start event.
+  void _start(Map arguments) {
+    _reportTaskEvent(_getTraceClock(), _taskId, 'b', category, name,
+        _argumentsAsJson(arguments));
+  }
+
+  // Emit the finish event.
+  void _finish(Map arguments) {
+    _reportTaskEvent(_getTraceClock(), _taskId, 'e', category, name,
+        _argumentsAsJson(arguments));
+  }
+}
+
+/// A synchronous block of time on the timeline. This block should not be
+/// kept open across isolate messages.
+class _SyncBlock {
+  /// The category this block belongs to.
+  final String category = 'Dart';
+
+  /// The name of this block.
+  final String name;
+
+  /// An (optional) set of arguments which will be serialized to JSON and
+  /// associated with this block.
+  Map _arguments;
+  // The start time stamp.
+  final int _start;
+  // The start time stamp of the thread cpu clock.
+  final int _startCpu;
+
+  /// An (optional) flow event associated with this block.
+  Flow _flow;
+
+  _SyncBlock._(this.name, this._start, this._startCpu);
+
+  /// Finish this block of time. At this point, this block can no longer be
+  /// used.
+  void finish() {
+    // Report event to runtime.
+    _reportCompleteEvent(
+        _start, _startCpu, category, name, _argumentsAsJson(_arguments));
+    if (_flow != null) {
+      _reportFlowEvent(_start, _startCpu, category, "${_flow.id}", _flow._type,
+          _flow.id, _argumentsAsJson(null));
+    }
+  }
+
+  void set flow(Flow f) {
+    _flow = f;
+  }
+}
+
+String _argumentsAsJson(Map arguments) {
+  if ((arguments == null) || (arguments.length == 0)) {
+    // Fast path no arguments. Avoid calling jsonEncode.
+    return '{}';
+  }
+  return json.encode(arguments);
+}
+
+/// Returns true if the Dart Timeline stream is enabled.
+external bool _isDartStreamEnabled();
+
+/// Returns the next async task id.
+external int _getNextAsyncId();
+
+/// Returns the current value from the trace clock.
+external int _getTraceClock();
+
+/// Returns the current value from the thread CPU usage clock.
+external int _getThreadCpuClock();
+
+/// Reports an event for a task.
+external void _reportTaskEvent(int start, int taskId, String phase,
+    String category, String name, String argumentsAsJson);
+
+/// Reports a complete synchronous event.
+external void _reportCompleteEvent(int start, int startCpu, String category,
+    String name, String argumentsAsJson);
+
+/// Reports a flow event.
+external void _reportFlowEvent(int start, int startCpu, String category,
+    String name, int type, int id, String argumentsAsJson);
+
+/// Reports an instant event.
+external void _reportInstantEvent(
+    int start, String category, String name, String argumentsAsJson);
diff --git a/sdk_nnbd/lib/ffi/annotations.dart b/sdk_nnbd/lib/ffi/annotations.dart
new file mode 100644
index 0000000..d246b56
--- /dev/null
+++ b/sdk_nnbd/lib/ffi/annotations.dart
@@ -0,0 +1,37 @@
+// 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.
+
+part of dart.ffi;
+
+class DartRepresentationOf {
+  /// Represents the Dart type corresponding to a [NativeType].
+  ///
+  /// [Int8]                               -> [int]
+  /// [Int16]                              -> [int]
+  /// [Int32]                              -> [int]
+  /// [Int64]                              -> [int]
+  /// [Uint8]                              -> [int]
+  /// [Uint16]                             -> [int]
+  /// [Uint32]                             -> [int]
+  /// [Uint64]                             -> [int]
+  /// [IntPtr]                             -> [int]
+  /// [Double]                             -> [double]
+  /// [Float]                              -> [double]
+  /// [Pointer]<T>                         -> [Pointer]<T>
+  /// [NativeFunction]<T1 Function(T2, T3) -> S1 Function(S2, S3)
+  ///    where DartRepresentationOf(Tn) -> Sn
+  /// T extends Struct<T>                  -> T
+  const DartRepresentationOf(String nativeType);
+}
+
+class Unsized {
+  const Unsized();
+}
+
+/// This [NativeType] does not have predefined size.
+///
+/// Unsized NativeTypes do not support [sizeOf] because their size is unknown.
+/// Consequently, [allocate], [Pointer.load], [Pointer.store], and
+/// [Pointer.elementAt] are not available.
+const unsized = const Unsized();
diff --git a/sdk_nnbd/lib/ffi/dynamic_library.dart b/sdk_nnbd/lib/ffi/dynamic_library.dart
new file mode 100644
index 0000000..ec68eeb
--- /dev/null
+++ b/sdk_nnbd/lib/ffi/dynamic_library.dart
@@ -0,0 +1,43 @@
+// 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.
+
+part of dart.ffi;
+
+/// Represents a dynamically loaded C library.
+class DynamicLibrary {
+  /// Creates a dynamic library holding all global symbols.
+  ///
+  /// Any symbol in a library currently loaded with global visibility (including
+  /// the executable itself) may be resolved in this library.
+  ///
+  /// This feature is not available on Windows, instead an exception is thrown.
+  external factory DynamicLibrary.process();
+
+  /// Creates a dynamic library representing the running executable.
+  external factory DynamicLibrary.executable();
+
+  /// Loads a dynamic library file with local visibility.
+  ///
+  /// Throws an [ArgumentError] if loading the dynamic library fails.
+  external factory DynamicLibrary.open(String name);
+
+  /// Looks up a symbol in the [DynamicLibrary] and returns its address in
+  /// memory. Equivalent of dlsym.
+  ///
+  /// Throws an [ArgumentError] if it fails to lookup the symbol.
+  external Pointer<T> lookup<T extends NativeType>(String symbolName);
+
+  /// Helper that combines lookup and cast to a Dart function.
+  external F lookupFunction<T extends Function, F extends Function>(
+      String symbolName);
+
+  /// Dynamic libraries are equal if they load the same library.
+  external bool operator ==(other);
+
+  /// The hash code for a DynamicLibrary only depends on the loaded library
+  external int get hashCode;
+
+  /// The handle to the dynamic library.
+  external Pointer<Void> get handle;
+}
diff --git a/sdk_nnbd/lib/ffi/ffi.dart b/sdk_nnbd/lib/ffi/ffi.dart
new file mode 100644
index 0000000..a975a13
--- /dev/null
+++ b/sdk_nnbd/lib/ffi/ffi.dart
@@ -0,0 +1,144 @@
+// 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
+
+/**
+ * Foreign Function Interface for interoperability with the C programming language.
+ *
+ * **NOTE**: Dart:FFI is in technical preview. The overall feature is incomplete,
+ * may contain issues, and breaking API changes are still expected.
+ *
+ * For further details, please see: https://dart.dev/server/c-interop
+ *
+ * {@category VM}
+ */
+library dart.ffi;
+
+import 'dart:typed_data' show TypedData;
+
+part "native_type.dart";
+part "annotations.dart";
+part "dynamic_library.dart";
+part "struct.dart";
+
+/// Number of bytes used by native type T.
+///
+/// Includes padding and alignment of structs.
+external int sizeOf<T extends NativeType>();
+
+/// Represents a pointer into the native C memory.
+final Pointer<Void> nullptr = Pointer.fromAddress(0);
+
+/// Represents a pointer into the native C memory. Cannot be extended.
+@pragma("vm:entry-point")
+class Pointer<T extends NativeType> extends NativeType {
+  /// Allocate [count] elements of type [T] on the native heap via malloc() and
+  /// return a pointer to the newly allocated memory.
+  ///
+  /// Note that the memory is uninitialized.
+  external factory Pointer.allocate({int count: 1});
+
+  /// Construction from raw integer.
+  external factory Pointer.fromAddress(int ptr);
+
+  /// Convert Dart function to a C function pointer, automatically marshalling
+  /// the arguments and return value
+  ///
+  /// If an exception is thrown while calling `f()`, the native function will
+  /// return `exceptionalReturn`, which must be assignable to return type of `f`.
+  ///
+  /// The returned function address can only be invoked on the mutator (main)
+  /// thread of the current isolate. It will abort the process if invoked on any
+  /// other thread.
+  ///
+  /// The pointer returned will remain alive for the duration of the current
+  /// isolate's lifetime. After the isolate it was created in is terminated,
+  /// invoking it from native code will cause undefined behavior.
+  ///
+  /// Does not accept dynamic invocations -- where the type of the receiver is
+  /// [dynamic].
+  external static Pointer<NativeFunction<T>> fromFunction<T extends Function>(
+      @DartRepresentationOf("T") Function f,
+      [Object exceptionalReturn]);
+
+  /// Store a Dart value into this location.
+  ///
+  /// The [value] is automatically marshalled into its native representation.
+  /// Note that ints which do not fit in [T] are truncated and sign extended,
+  /// and doubles stored into Pointer<[Float]> lose precision.
+  external void store(@DartRepresentationOf("T") Object value);
+
+  /// Load a Dart value from this location.
+  ///
+  /// The value is automatically unmarshalled from its native representation.
+  /// Loading a [Struct] reference returns a reference backed by native memory
+  /// (the same pointer as it's loaded from).
+  external R load<@DartRepresentationOf("T") R>();
+
+  /// Access to the raw pointer value.
+  /// On 32-bit systems, the upper 32-bits of the result are 0.
+  external int get address;
+
+  /// Pointer arithmetic (takes element size into account).
+  external Pointer<T> elementAt(int index);
+
+  /// Pointer arithmetic (byte offset).
+  // TODO(dacoharkes): remove this?
+  // https://github.com/dart-lang/sdk/issues/35883
+  external Pointer<T> offsetBy(int offsetInBytes);
+
+  /// Cast Pointer<T> to a Pointer<V>.
+  external Pointer<U> cast<U extends NativeType>();
+
+  /// Convert to Dart function, automatically marshalling the arguments
+  /// and return value.
+  ///
+  /// Can only be called on [Pointer]<[NativeFunction]>. Does not accept dynamic
+  /// invocations -- where the type of the receiver is [dynamic].
+  external R asFunction<@DartRepresentationOf("T") R extends Function>();
+
+  /// Free memory on the C heap pointed to by this pointer with free().
+  ///
+  /// Note that this zeros out the address.
+  external void free();
+
+  /// Creates an *external* typed data array backed by this pointer.
+  ///
+  /// The typed data array returned is only valid for as long as the backing
+  /// [Pointer]. Accessing any element of the type data array after this
+  /// [Pointer] has been [Pointer.free()]d will cause undefined behavior.
+  ///
+  /// Since [Pointer]s do not know their length, the size of the typed data is
+  /// controlled by `count`, in units of the size of the native type for this
+  /// [Pointer] (similarly to [Pointer.allocate]).
+  ///
+  /// The kind of TypedData produced depends on the native type:
+  ///
+  ///   Pointer<Int8> -> Int8List
+  ///   Pointer<Uint8> -> Uint8List
+  ///   etc. up to Int64/Uint64
+  ///   Pointer<IntPtr> -> Int32List/Int64List depending on platform word size
+  ///   Pointer<Float> -> Float32List
+  ///   Pointer<Double> -> Float64List
+  ///
+  /// Creation of a [Uint8ClampedList] is not supported. Creation of a typed
+  /// data from a [Pointer] to any other native type is not supported.
+  ///
+  /// The pointer must be aligned to a multiple of the native type's size.
+  //
+  // TODO(37773): Use extension methods to articulate more precise return types.
+  // We should still keep this member though as a generic way to access a
+  // Pointer of unknown type.
+  external TypedData asExternalTypedData({int count: 1});
+
+  /// Equality for Pointers only depends on their address.
+  bool operator ==(other) {
+    if (other == null) return false;
+    return address == other.address;
+  }
+
+  /// The hash code for a Pointer only depends on its address.
+  int get hashCode {
+    return address.hashCode;
+  }
+}
diff --git a/sdk_nnbd/lib/ffi/ffi_sources.gni b/sdk_nnbd/lib/ffi/ffi_sources.gni
new file mode 100644
index 0000000..d2bb279
--- /dev/null
+++ b/sdk_nnbd/lib/ffi/ffi_sources.gni
@@ -0,0 +1,13 @@
+# 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.
+
+ffi_sdk_sources = [
+  "ffi.dart",
+
+  # The above file needs to be first as it lists the parts below.
+  "annotations.dart",
+  "dynamic_library.dart",
+  "native_type.dart",
+  "struct.dart"
+]
diff --git a/sdk_nnbd/lib/ffi/native_type.dart b/sdk_nnbd/lib/ffi/native_type.dart
new file mode 100644
index 0000000..aa30e63
--- /dev/null
+++ b/sdk_nnbd/lib/ffi/native_type.dart
@@ -0,0 +1,131 @@
+// 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.
+
+part of dart.ffi;
+
+/// [NativeType]'s subtypes represent a native type in C.
+///
+/// [NativeType]'s subtypes are not constructible in the Dart code and serve
+/// purely as markers in type signatures.
+abstract class NativeType {
+  const NativeType();
+}
+
+/// [_NativeInteger]'s subtypes represent a native integer in C.
+///
+/// [_NativeInteger]'s subtypes are not constructible in the Dart code and serve
+/// purely as markers in type signatures.
+class _NativeInteger extends NativeType {
+  const _NativeInteger();
+}
+
+/// [_NativeDouble]'s subtypes represent a native float or double in C.
+///
+/// [_NativeDouble]'s subtypes are not constructible in the Dart code and serve
+/// purely as markers in type signatures.
+class _NativeDouble extends NativeType {
+  const _NativeDouble();
+}
+
+/// Represents a native signed 8 bit integer in C.
+///
+/// [Int8] is not constructible in the Dart code and serves purely as marker in
+/// type signatures.
+class Int8 extends _NativeInteger {
+  const Int8();
+}
+
+/// Represents a native signed 16 bit integer in C.
+///
+/// [Int16] is not constructible in the Dart code and serves purely as marker in
+/// type signatures.
+class Int16 extends _NativeInteger {
+  const Int16();
+}
+
+/// Represents a native signed 32 bit integer in C.
+///
+/// [Int32] is not constructible in the Dart code and serves purely as marker in
+/// type signatures.
+class Int32 extends _NativeInteger {
+  const Int32();
+}
+
+/// Represents a native signed 64 bit integer in C.
+///
+/// [Int64] is not constructible in the Dart code and serves purely as marker in
+/// type signatures.
+class Int64 extends _NativeInteger {
+  const Int64();
+}
+
+/// Represents a native unsigned 8 bit integer in C.
+///
+/// [Uint8] is not constructible in the Dart code and serves purely as marker in
+/// type signatures.
+class Uint8 extends _NativeInteger {
+  const Uint8();
+}
+
+/// Represents a native unsigned 16 bit integer in C.
+///
+/// [Uint16] is not constructible in the Dart code and serves purely as marker
+/// in type signatures.
+class Uint16 extends _NativeInteger {
+  const Uint16();
+}
+
+/// Represents a native unsigned 32 bit integer in C.
+///
+/// [Uint32] is not constructible in the Dart code and serves purely as marker
+/// in type signatures.
+class Uint32 extends _NativeInteger {
+  const Uint32();
+}
+
+/// Represents a native unsigned 64 bit integer in C.
+///
+/// [Uint64] is not constructible in the Dart code and serves purely as marker
+/// in type signatures.
+class Uint64 extends _NativeInteger {
+  const Uint64();
+}
+
+/// Represents a native pointer-sized integer in C.
+///
+/// [IntPtr] is not constructible in the Dart code and serves purely as marker
+/// in type signatures.
+class IntPtr extends _NativeInteger {
+  const IntPtr();
+}
+
+/// Represents a native 32 bit float in C.
+///
+/// [Float] is not constructible in the Dart code and serves purely as marker
+/// in type signatures.
+class Float extends _NativeDouble {
+  const Float();
+}
+
+/// Represents a native 64 bit double in C.
+///
+/// [Double] is not constructible in the Dart code and serves purely as marker
+/// in type signatures.
+class Double extends _NativeDouble {
+  const Double();
+}
+
+/// Represents a void type in C.
+///
+/// [Void] is not constructible in the Dart code and serves purely as marker in
+/// type signatures.
+@unsized
+abstract class Void extends NativeType {}
+
+/// Represents a function type in C.
+///
+/// [NativeFunction] is not constructible in the Dart code and serves purely as
+/// marker in type signatures.
+@unsized
+abstract class NativeFunction<T extends Function> extends NativeType {}
diff --git a/sdk_nnbd/lib/ffi/struct.dart b/sdk_nnbd/lib/ffi/struct.dart
new file mode 100644
index 0000000..23124eb
--- /dev/null
+++ b/sdk_nnbd/lib/ffi/struct.dart
@@ -0,0 +1,26 @@
+// 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.
+
+part of dart.ffi;
+
+/// This class is extended to define structs.
+///
+/// Fields in a struct, annotated with a subtype of [NativeType], are
+/// automatically transformed into wrappers to access the fields of the struct
+/// in native memory.
+///
+/// All fields in a struct must either have a type which extends [NativeType] or
+/// else have an annotation indicating the corresponding native type (e.g.
+/// "@Int32()" for "int").
+///
+/// Instances of a subclass of [Struct] have reference semantics and are backed
+/// by native memory. The may allocated via [Pointer.allocate] or loaded from a
+/// [Pointer], but not by a generative constructor.
+abstract class Struct<S extends NativeType> extends NativeType {
+  /// Returns the address backing the reference.
+  final Pointer<S> addressOf;
+
+  Struct() : addressOf = null;
+  Struct.fromPointer(this.addressOf);
+}
diff --git a/sdk_nnbd/lib/html/dart2js/html_dart2js.dart b/sdk_nnbd/lib/html/dart2js/html_dart2js.dart
new file mode 100644
index 0000000..303ec9e
--- /dev/null
+++ b/sdk_nnbd/lib/html/dart2js/html_dart2js.dart
@@ -0,0 +1,39523 @@
+/**
+ * HTML elements and other resources for web-based applications that need to
+ * interact with the browser and the DOM (Document Object Model).
+ *
+ * This library includes DOM element types, CSS styling, local storage,
+ * media, speech, events, and more.
+ * To get started,
+ * check out the [Element] class, the base class for many of the HTML
+ * DOM types.
+ *
+ * For information on writing web apps with Dart, see https://webdev.dartlang.org.
+ *
+ * {@category Web}
+ */
+library dart.dom.html;
+
+import 'dart:async';
+import 'dart:collection' hide LinkedList, LinkedListEntry;
+import 'dart:_internal' hide Symbol;
+import 'dart:html_common';
+import 'dart:indexed_db';
+import "dart:convert";
+import 'dart:math';
+import 'dart:_native_typed_data';
+import 'dart:typed_data';
+import 'dart:svg' as svg;
+import 'dart:svg' show Matrix;
+import 'dart:svg' show SvgSvgElement;
+import 'dart:web_audio' as web_audio;
+import 'dart:web_audio' show AudioBuffer, AudioTrack, AudioTrackList;
+import 'dart:web_gl' as gl;
+import 'dart:web_gl' show RenderingContext, RenderingContext2;
+import 'dart:web_sql';
+import 'dart:_foreign_helper' show JS, JS_INTERCEPTOR_CONSTANT;
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// DO NOT EDIT - unless you are editing documentation as per:
+// https://code.google.com/p/dart/wiki/ContributingHTMLDocumentation
+// Auto-generated dart:html library.
+
+// Not actually used, but imported since dart:html can generate these objects.
+import 'dart:_js_helper'
+    show
+        convertDartClosureToJS,
+        Creates,
+        JavaScriptIndexingBehavior,
+        JSName,
+        Native,
+        Returns,
+        ForceInline,
+        findDispatchTagForInterceptorClass,
+        setNativeSubclassDispatchRecord,
+        makeLeafDispatchRecord,
+        registerGlobalObject,
+        applyExtension;
+import 'dart:_interceptors'
+    show
+        Interceptor,
+        JavaScriptFunction,
+        JSExtendableArray,
+        JSUInt31,
+        findInterceptorConstructorForType,
+        findConstructorForNativeSubclassType,
+        getNativeInterceptor,
+        setDispatchProperty;
+
+export 'dart:math' show Rectangle, Point;
+export 'dart:_internal' show HttpStatus;
+
+/**
+ * Top-level container for a web page, which is usually a browser tab or window.
+ *
+ * Each web page loaded in the browser has its own [Window], which is a
+ * container for the web page.
+ *
+ * If the web page has any `<iframe>` elements, then each `<iframe>` has its own
+ * [Window] object, which is accessible only to that `<iframe>`.
+ *
+ * See also:
+ *
+ *   * [Window](https://developer.mozilla.org/en-US/docs/Web/API/window) from MDN.
+ */
+Window get window => JS('Window', 'window');
+
+/**
+ * Root node for all content in a web page.
+ */
+HtmlDocument get document =>
+    JS('returns:HtmlDocument;depends:none;effects:none;gvn:true', 'document');
+
+// Supoort to convert JS Promise to a Dart Future.
+Future<T> promiseToFuture<T>(jsPromise) {
+  var completer = new Completer<T>();
+
+  var thenSuccessCode = (promiseValue) => completer.complete(promiseValue);
+  var thenErrorCode = (promiseError) => completer.completeError(promiseError);
+
+  JS("", "#.then(#, #)", jsPromise, convertDartClosureToJS(thenSuccessCode, 1),
+      convertDartClosureToJS(thenErrorCode, 1));
+
+  return completer.future;
+}
+
+// Supoort to convert JS Promise to a Dart Future<Map<String, dynamic>>.  Each property of the JS
+// object is added to the Map as a key of type String with a value of type dynamic.
+Future<Map<String, dynamic>> promiseToFutureAsMap(jsPromise) {
+  var completer = new Completer<Map<String, dynamic>>();
+
+  var thenSuccessCode = (promiseValue) =>
+      completer.complete(convertNativeToDart_Dictionary(promiseValue));
+  var thenErrorCode = (promiseError) => completer.completeError(promiseError);
+
+  JS("", "#.then(#, #)", jsPromise, convertDartClosureToJS(thenSuccessCode, 1),
+      convertDartClosureToJS(thenErrorCode, 1));
+
+  return completer.future;
+}
+
+// Workaround for tags like <cite> that lack their own Element subclass --
+// Dart issue 1990.
+@Native("HTMLElement")
+class HtmlElement extends Element implements NoncedElement {
+  factory HtmlElement() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  HtmlElement.created() : super.created();
+
+  // From NoncedElement
+  String nonce;
+}
+
+/**
+ * Emitted for any setlike IDL entry needs a callback signature.
+ * Today there is only one.
+ */
+typedef void FontFaceSetForEachCallback(
+    FontFace fontFace, FontFace fontFaceAgain, FontFaceSet set);
+
+WorkerGlobalScope get _workerSelf => JS('WorkerGlobalScope', 'self');
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("AbortPaymentEvent")
+class AbortPaymentEvent extends ExtendableEvent {
+  // To suppress missing implicit constructor warnings.
+  factory AbortPaymentEvent._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory AbortPaymentEvent(String type, Map eventInitDict) {
+    var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+    return AbortPaymentEvent._create_1(type, eventInitDict_1);
+  }
+  static AbortPaymentEvent _create_1(type, eventInitDict) => JS(
+      'AbortPaymentEvent', 'new AbortPaymentEvent(#,#)', type, eventInitDict);
+
+  void respondWith(Future paymentAbortedResponse) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("AbsoluteOrientationSensor")
+class AbsoluteOrientationSensor extends OrientationSensor {
+  // To suppress missing implicit constructor warnings.
+  factory AbsoluteOrientationSensor._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory AbsoluteOrientationSensor([Map sensorOptions]) {
+    if (sensorOptions != null) {
+      var sensorOptions_1 = convertDartToNative_Dictionary(sensorOptions);
+      return AbsoluteOrientationSensor._create_1(sensorOptions_1);
+    }
+    return AbsoluteOrientationSensor._create_2();
+  }
+  static AbsoluteOrientationSensor _create_1(sensorOptions) => JS(
+      'AbsoluteOrientationSensor',
+      'new AbsoluteOrientationSensor(#)',
+      sensorOptions);
+  static AbsoluteOrientationSensor _create_2() =>
+      JS('AbsoluteOrientationSensor', 'new AbsoluteOrientationSensor()');
+}
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+abstract class AbstractWorker extends Interceptor implements EventTarget {
+  // To suppress missing implicit constructor warnings.
+  factory AbstractWorker._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  /**
+   * Static factory designed to expose `error` events to event
+   * handlers that are not necessarily instances of [AbstractWorker].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<Event> errorEvent =
+      const EventStreamProvider<Event>('error');
+
+  /// Stream of `error` events handled by this [AbstractWorker].
+  Stream<Event> get onError => errorEvent.forTarget(this);
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("Accelerometer")
+class Accelerometer extends Sensor {
+  // To suppress missing implicit constructor warnings.
+  factory Accelerometer._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory Accelerometer([Map sensorOptions]) {
+    if (sensorOptions != null) {
+      var sensorOptions_1 = convertDartToNative_Dictionary(sensorOptions);
+      return Accelerometer._create_1(sensorOptions_1);
+    }
+    return Accelerometer._create_2();
+  }
+  static Accelerometer _create_1(sensorOptions) =>
+      JS('Accelerometer', 'new Accelerometer(#)', sensorOptions);
+  static Accelerometer _create_2() =>
+      JS('Accelerometer', 'new Accelerometer()');
+
+  final num x;
+
+  final num y;
+
+  final num z;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("AccessibleNode")
+class AccessibleNode extends EventTarget {
+  // To suppress missing implicit constructor warnings.
+  factory AccessibleNode._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  static const EventStreamProvider<Event> accessibleClickEvent =
+      const EventStreamProvider<Event>('accessibleclick');
+
+  static const EventStreamProvider<Event> accessibleContextMenuEvent =
+      const EventStreamProvider<Event>('accessiblecontextmenu');
+
+  static const EventStreamProvider<Event> accessibleDecrementEvent =
+      const EventStreamProvider<Event>('accessibledecrement');
+
+  static const EventStreamProvider<Event> accessibleFocusEvent =
+      const EventStreamProvider<Event>('accessiblefocus');
+
+  static const EventStreamProvider<Event> accessibleIncrementEvent =
+      const EventStreamProvider<Event>('accessibleincrement');
+
+  static const EventStreamProvider<Event> accessibleScrollIntoViewEvent =
+      const EventStreamProvider<Event>('accessiblescrollintoview');
+
+  factory AccessibleNode() {
+    return AccessibleNode._create_1();
+  }
+  static AccessibleNode _create_1() =>
+      JS('AccessibleNode', 'new AccessibleNode()');
+
+  AccessibleNode activeDescendant;
+
+  bool atomic;
+
+  String autocomplete;
+
+  bool busy;
+
+  String checked;
+
+  int colCount;
+
+  int colIndex;
+
+  int colSpan;
+
+  AccessibleNodeList controls;
+
+  String current;
+
+  AccessibleNodeList describedBy;
+
+  AccessibleNode details;
+
+  bool disabled;
+
+  AccessibleNode errorMessage;
+
+  bool expanded;
+
+  AccessibleNodeList flowTo;
+
+  String hasPopUp;
+
+  bool hidden;
+
+  String invalid;
+
+  String keyShortcuts;
+
+  String label;
+
+  AccessibleNodeList labeledBy;
+
+  int level;
+
+  String live;
+
+  bool modal;
+
+  bool multiline;
+
+  bool multiselectable;
+
+  String orientation;
+
+  AccessibleNodeList owns;
+
+  String placeholder;
+
+  int posInSet;
+
+  String pressed;
+
+  bool readOnly;
+
+  String relevant;
+
+  bool required;
+
+  String role;
+
+  String roleDescription;
+
+  int rowCount;
+
+  int rowIndex;
+
+  int rowSpan;
+
+  bool selected;
+
+  int setSize;
+
+  String sort;
+
+  num valueMax;
+
+  num valueMin;
+
+  num valueNow;
+
+  String valueText;
+
+  void appendChild(AccessibleNode child) native;
+
+  Stream<Event> get onAccessibleClick => accessibleClickEvent.forTarget(this);
+
+  Stream<Event> get onAccessibleContextMenu =>
+      accessibleContextMenuEvent.forTarget(this);
+
+  Stream<Event> get onAccessibleDecrement =>
+      accessibleDecrementEvent.forTarget(this);
+
+  Stream<Event> get onAccessibleFocus => accessibleFocusEvent.forTarget(this);
+
+  Stream<Event> get onAccessibleIncrement =>
+      accessibleIncrementEvent.forTarget(this);
+
+  Stream<Event> get onAccessibleScrollIntoView =>
+      accessibleScrollIntoViewEvent.forTarget(this);
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("AccessibleNodeList")
+class AccessibleNodeList extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory AccessibleNodeList._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory AccessibleNodeList([List<AccessibleNode> nodes]) {
+    if (nodes != null) {
+      return AccessibleNodeList._create_1(nodes);
+    }
+    return AccessibleNodeList._create_2();
+  }
+  static AccessibleNodeList _create_1(nodes) =>
+      JS('AccessibleNodeList', 'new AccessibleNodeList(#)', nodes);
+  static AccessibleNodeList _create_2() =>
+      JS('AccessibleNodeList', 'new AccessibleNodeList()');
+
+  int length;
+
+  void __setter__(int index, AccessibleNode node) native;
+
+  void add(AccessibleNode node, AccessibleNode before) native;
+
+  AccessibleNode item(int index) native;
+
+  void remove(int index) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("AmbientLightSensor")
+class AmbientLightSensor extends Sensor {
+  // To suppress missing implicit constructor warnings.
+  factory AmbientLightSensor._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory AmbientLightSensor([Map sensorOptions]) {
+    if (sensorOptions != null) {
+      var sensorOptions_1 = convertDartToNative_Dictionary(sensorOptions);
+      return AmbientLightSensor._create_1(sensorOptions_1);
+    }
+    return AmbientLightSensor._create_2();
+  }
+  static AmbientLightSensor _create_1(sensorOptions) =>
+      JS('AmbientLightSensor', 'new AmbientLightSensor(#)', sensorOptions);
+  static AmbientLightSensor _create_2() =>
+      JS('AmbientLightSensor', 'new AmbientLightSensor()');
+
+  final num illuminance;
+}
+// Copyright (c) 2015, 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.
+
+@Native("HTMLAnchorElement")
+class AnchorElement extends HtmlElement implements HtmlHyperlinkElementUtils {
+  // To suppress missing implicit constructor warnings.
+  factory AnchorElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory AnchorElement({String href}) {
+    AnchorElement e = JS('returns:AnchorElement;creates:AnchorElement;new:true',
+        '#.createElement(#)', document, "a");
+    if (href != null) e.href = href;
+    return e;
+  }
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  AnchorElement.created() : super.created();
+
+  String download;
+
+  String hreflang;
+
+  String referrerPolicy;
+
+  String rel;
+
+  String target;
+
+  String type;
+
+  // From HTMLHyperlinkElementUtils
+
+  String hash;
+
+  String host;
+
+  String hostname;
+
+  String href;
+
+  final String origin;
+
+  String password;
+
+  String pathname;
+
+  String port;
+
+  String protocol;
+
+  String search;
+
+  String username;
+
+  String toString() => JS('String', 'String(#)', this);
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("Animation")
+class Animation extends EventTarget {
+  // To suppress missing implicit constructor warnings.
+  factory Animation._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  static const EventStreamProvider<Event> cancelEvent =
+      const EventStreamProvider<Event>('cancel');
+
+  static const EventStreamProvider<Event> finishEvent =
+      const EventStreamProvider<Event>('finish');
+
+  factory Animation(
+      [AnimationEffectReadOnly effect, AnimationTimeline timeline]) {
+    if (timeline != null) {
+      return Animation._create_1(effect, timeline);
+    }
+    if (effect != null) {
+      return Animation._create_2(effect);
+    }
+    return Animation._create_3();
+  }
+  static Animation _create_1(effect, timeline) =>
+      JS('Animation', 'new Animation(#,#)', effect, timeline);
+  static Animation _create_2(effect) =>
+      JS('Animation', 'new Animation(#)', effect);
+  static Animation _create_3() => JS('Animation', 'new Animation()');
+
+  /// Checks if this type is supported on the current platform.
+  static bool get supported => JS('bool', '!!(document.body.animate)');
+
+  num currentTime;
+
+  AnimationEffectReadOnly effect;
+
+  Future<Animation> get finished =>
+      promiseToFuture<Animation>(JS("", "#.finished", this));
+
+  String id;
+
+  final String playState;
+
+  num playbackRate;
+
+  Future<Animation> get ready =>
+      promiseToFuture<Animation>(JS("", "#.ready", this));
+
+  num startTime;
+
+  final AnimationTimeline timeline;
+
+  void cancel() native;
+
+  void finish() native;
+
+  void pause() native;
+
+  void play() native;
+
+  void reverse() native;
+
+  Stream<Event> get onCancel => cancelEvent.forTarget(this);
+
+  Stream<Event> get onFinish => finishEvent.forTarget(this);
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("AnimationEffectReadOnly")
+class AnimationEffectReadOnly extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory AnimationEffectReadOnly._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final AnimationEffectTimingReadOnly timing;
+
+  Map getComputedTiming() {
+    return convertNativeToDart_Dictionary(_getComputedTiming_1());
+  }
+
+  @JSName('getComputedTiming')
+  _getComputedTiming_1() native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("AnimationEffectTiming")
+class AnimationEffectTiming extends AnimationEffectTimingReadOnly {
+  // To suppress missing implicit constructor warnings.
+  factory AnimationEffectTiming._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  // Shadowing definition.
+  num get delay => JS("num", "#.delay", this);
+
+  set delay(num value) {
+    JS("void", "#.delay = #", this, value);
+  }
+
+  // Shadowing definition.
+  String get direction => JS("String", "#.direction", this);
+
+  set direction(String value) {
+    JS("void", "#.direction = #", this, value);
+  }
+
+  // Shadowing definition.
+  Object get duration => JS("Object", "#.duration", this);
+
+  set duration(Object value) {
+    JS("void", "#.duration = #", this, value);
+  }
+
+  // Shadowing definition.
+  String get easing => JS("String", "#.easing", this);
+
+  set easing(String value) {
+    JS("void", "#.easing = #", this, value);
+  }
+
+  // Shadowing definition.
+  num get endDelay => JS("num", "#.endDelay", this);
+
+  set endDelay(num value) {
+    JS("void", "#.endDelay = #", this, value);
+  }
+
+  // Shadowing definition.
+  String get fill => JS("String", "#.fill", this);
+
+  set fill(String value) {
+    JS("void", "#.fill = #", this, value);
+  }
+
+  // Shadowing definition.
+  num get iterationStart => JS("num", "#.iterationStart", this);
+
+  set iterationStart(num value) {
+    JS("void", "#.iterationStart = #", this, value);
+  }
+
+  // Shadowing definition.
+  num get iterations => JS("num", "#.iterations", this);
+
+  set iterations(num value) {
+    JS("void", "#.iterations = #", this, value);
+  }
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("AnimationEffectTimingReadOnly")
+class AnimationEffectTimingReadOnly extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory AnimationEffectTimingReadOnly._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final num delay;
+
+  final String direction;
+
+  final Object duration;
+
+  final String easing;
+
+  final num endDelay;
+
+  final String fill;
+
+  final num iterationStart;
+
+  final num iterations;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("AnimationEvent")
+class AnimationEvent extends Event {
+  // To suppress missing implicit constructor warnings.
+  factory AnimationEvent._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory AnimationEvent(String type, [Map eventInitDict]) {
+    if (eventInitDict != null) {
+      var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+      return AnimationEvent._create_1(type, eventInitDict_1);
+    }
+    return AnimationEvent._create_2(type);
+  }
+  static AnimationEvent _create_1(type, eventInitDict) =>
+      JS('AnimationEvent', 'new AnimationEvent(#,#)', type, eventInitDict);
+  static AnimationEvent _create_2(type) =>
+      JS('AnimationEvent', 'new AnimationEvent(#)', type);
+
+  final String animationName;
+
+  final num elapsedTime;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("AnimationPlaybackEvent")
+class AnimationPlaybackEvent extends Event {
+  // To suppress missing implicit constructor warnings.
+  factory AnimationPlaybackEvent._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory AnimationPlaybackEvent(String type, [Map eventInitDict]) {
+    if (eventInitDict != null) {
+      var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+      return AnimationPlaybackEvent._create_1(type, eventInitDict_1);
+    }
+    return AnimationPlaybackEvent._create_2(type);
+  }
+  static AnimationPlaybackEvent _create_1(type, eventInitDict) => JS(
+      'AnimationPlaybackEvent',
+      'new AnimationPlaybackEvent(#,#)',
+      type,
+      eventInitDict);
+  static AnimationPlaybackEvent _create_2(type) =>
+      JS('AnimationPlaybackEvent', 'new AnimationPlaybackEvent(#)', type);
+
+  final num currentTime;
+
+  final num timelineTime;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("AnimationTimeline")
+class AnimationTimeline extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory AnimationTimeline._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final num currentTime;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("AnimationWorkletGlobalScope")
+class AnimationWorkletGlobalScope extends WorkletGlobalScope {
+  // To suppress missing implicit constructor warnings.
+  factory AnimationWorkletGlobalScope._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  void registerAnimator(String name, Object animatorConstructor) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/**
+ * ApplicationCache is accessed via [Window.applicationCache].
+ */
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.FIREFOX)
+@SupportedBrowser(SupportedBrowser.IE, '10')
+@SupportedBrowser(SupportedBrowser.OPERA)
+@SupportedBrowser(SupportedBrowser.SAFARI)
+@Unstable()
+@Native("ApplicationCache,DOMApplicationCache,OfflineResourceList")
+class ApplicationCache extends EventTarget {
+  // To suppress missing implicit constructor warnings.
+  factory ApplicationCache._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  /**
+   * Static factory designed to expose `cached` events to event
+   * handlers that are not necessarily instances of [ApplicationCache].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<Event> cachedEvent =
+      const EventStreamProvider<Event>('cached');
+
+  /**
+   * Static factory designed to expose `checking` events to event
+   * handlers that are not necessarily instances of [ApplicationCache].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<Event> checkingEvent =
+      const EventStreamProvider<Event>('checking');
+
+  /**
+   * Static factory designed to expose `downloading` events to event
+   * handlers that are not necessarily instances of [ApplicationCache].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<Event> downloadingEvent =
+      const EventStreamProvider<Event>('downloading');
+
+  /**
+   * Static factory designed to expose `error` events to event
+   * handlers that are not necessarily instances of [ApplicationCache].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<Event> errorEvent =
+      const EventStreamProvider<Event>('error');
+
+  /**
+   * Static factory designed to expose `noupdate` events to event
+   * handlers that are not necessarily instances of [ApplicationCache].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<Event> noUpdateEvent =
+      const EventStreamProvider<Event>('noupdate');
+
+  /**
+   * Static factory designed to expose `obsolete` events to event
+   * handlers that are not necessarily instances of [ApplicationCache].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<Event> obsoleteEvent =
+      const EventStreamProvider<Event>('obsolete');
+
+  /**
+   * Static factory designed to expose `progress` events to event
+   * handlers that are not necessarily instances of [ApplicationCache].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<ProgressEvent> progressEvent =
+      const EventStreamProvider<ProgressEvent>('progress');
+
+  /**
+   * Static factory designed to expose `updateready` events to event
+   * handlers that are not necessarily instances of [ApplicationCache].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<Event> updateReadyEvent =
+      const EventStreamProvider<Event>('updateready');
+
+  /// Checks if this type is supported on the current platform.
+  static bool get supported => JS('bool', '!!(window.applicationCache)');
+
+  static const int CHECKING = 2;
+
+  static const int DOWNLOADING = 3;
+
+  static const int IDLE = 1;
+
+  static const int OBSOLETE = 5;
+
+  static const int UNCACHED = 0;
+
+  static const int UPDATEREADY = 4;
+
+  final int status;
+
+  void abort() native;
+
+  void swapCache() native;
+
+  void update() native;
+
+  /// Stream of `cached` events handled by this [ApplicationCache].
+  Stream<Event> get onCached => cachedEvent.forTarget(this);
+
+  /// Stream of `checking` events handled by this [ApplicationCache].
+  Stream<Event> get onChecking => checkingEvent.forTarget(this);
+
+  /// Stream of `downloading` events handled by this [ApplicationCache].
+  Stream<Event> get onDownloading => downloadingEvent.forTarget(this);
+
+  /// Stream of `error` events handled by this [ApplicationCache].
+  Stream<Event> get onError => errorEvent.forTarget(this);
+
+  /// Stream of `noupdate` events handled by this [ApplicationCache].
+  Stream<Event> get onNoUpdate => noUpdateEvent.forTarget(this);
+
+  /// Stream of `obsolete` events handled by this [ApplicationCache].
+  Stream<Event> get onObsolete => obsoleteEvent.forTarget(this);
+
+  /// Stream of `progress` events handled by this [ApplicationCache].
+  Stream<ProgressEvent> get onProgress => progressEvent.forTarget(this);
+
+  /// Stream of `updateready` events handled by this [ApplicationCache].
+  Stream<Event> get onUpdateReady => updateReadyEvent.forTarget(this);
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("ApplicationCacheErrorEvent")
+class ApplicationCacheErrorEvent extends Event {
+  // To suppress missing implicit constructor warnings.
+  factory ApplicationCacheErrorEvent._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory ApplicationCacheErrorEvent(String type, [Map eventInitDict]) {
+    if (eventInitDict != null) {
+      var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+      return ApplicationCacheErrorEvent._create_1(type, eventInitDict_1);
+    }
+    return ApplicationCacheErrorEvent._create_2(type);
+  }
+  static ApplicationCacheErrorEvent _create_1(type, eventInitDict) => JS(
+      'ApplicationCacheErrorEvent',
+      'new ApplicationCacheErrorEvent(#,#)',
+      type,
+      eventInitDict);
+  static ApplicationCacheErrorEvent _create_2(type) => JS(
+      'ApplicationCacheErrorEvent', 'new ApplicationCacheErrorEvent(#)', type);
+
+  final String message;
+
+  final String reason;
+
+  final int status;
+
+  final String url;
+}
+// Copyright (c) 2015, 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.
+
+/**
+ * DOM Area Element, which links regions of an image map with a hyperlink.
+ *
+ * The element can also define an uninteractive region of the map.
+ *
+ * See also:
+ *
+ * * [`<area>`](https://developer.mozilla.org/en-US/docs/HTML/Element/area)
+ * on MDN.
+ */
+@Native("HTMLAreaElement")
+class AreaElement extends HtmlElement implements HtmlHyperlinkElementUtils {
+  // To suppress missing implicit constructor warnings.
+  factory AreaElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory AreaElement() => JS(
+      'returns:AreaElement;creates:AreaElement;new:true',
+      '#.createElement(#)',
+      document,
+      "area");
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  AreaElement.created() : super.created();
+
+  String alt;
+
+  String coords;
+
+  String download;
+
+  String referrerPolicy;
+
+  String rel;
+
+  String shape;
+
+  String target;
+
+  // From HTMLHyperlinkElementUtils
+
+  String hash;
+
+  String host;
+
+  String hostname;
+
+  String href;
+
+  final String origin;
+
+  String password;
+
+  String pathname;
+
+  String port;
+
+  String protocol;
+
+  String search;
+
+  String username;
+
+  String toString() => JS('String', 'String(#)', this);
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("HTMLAudioElement")
+class AudioElement extends MediaElement {
+  factory AudioElement._([String src]) {
+    if (src != null) {
+      return AudioElement._create_1(src);
+    }
+    return AudioElement._create_2();
+  }
+  static AudioElement _create_1(src) => JS('AudioElement', 'new Audio(#)', src);
+  static AudioElement _create_2() => JS('AudioElement', 'new Audio()');
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  AudioElement.created() : super.created();
+
+  factory AudioElement([String src]) => new AudioElement._(src);
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("AuthenticatorAssertionResponse")
+class AuthenticatorAssertionResponse extends AuthenticatorResponse {
+  // To suppress missing implicit constructor warnings.
+  factory AuthenticatorAssertionResponse._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final ByteBuffer authenticatorData;
+
+  final ByteBuffer signature;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("AuthenticatorAttestationResponse")
+class AuthenticatorAttestationResponse extends AuthenticatorResponse {
+  // To suppress missing implicit constructor warnings.
+  factory AuthenticatorAttestationResponse._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final ByteBuffer attestationObject;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("AuthenticatorResponse")
+class AuthenticatorResponse extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory AuthenticatorResponse._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  @JSName('clientDataJSON')
+  final ByteBuffer clientDataJson;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("HTMLBRElement")
+class BRElement extends HtmlElement {
+  // To suppress missing implicit constructor warnings.
+  factory BRElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory BRElement() => JS('returns:BRElement;creates:BRElement;new:true',
+      '#.createElement(#)', document, "br");
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  BRElement.created() : super.created();
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("BackgroundFetchClickEvent")
+class BackgroundFetchClickEvent extends BackgroundFetchEvent {
+  // To suppress missing implicit constructor warnings.
+  factory BackgroundFetchClickEvent._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory BackgroundFetchClickEvent(String type, Map init) {
+    var init_1 = convertDartToNative_Dictionary(init);
+    return BackgroundFetchClickEvent._create_1(type, init_1);
+  }
+  static BackgroundFetchClickEvent _create_1(type, init) => JS(
+      'BackgroundFetchClickEvent',
+      'new BackgroundFetchClickEvent(#,#)',
+      type,
+      init);
+
+  final String state;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("BackgroundFetchEvent")
+class BackgroundFetchEvent extends ExtendableEvent {
+  // To suppress missing implicit constructor warnings.
+  factory BackgroundFetchEvent._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory BackgroundFetchEvent(String type, Map init) {
+    var init_1 = convertDartToNative_Dictionary(init);
+    return BackgroundFetchEvent._create_1(type, init_1);
+  }
+  static BackgroundFetchEvent _create_1(type, init) =>
+      JS('BackgroundFetchEvent', 'new BackgroundFetchEvent(#,#)', type, init);
+
+  final String id;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("BackgroundFetchFailEvent")
+class BackgroundFetchFailEvent extends BackgroundFetchEvent {
+  // To suppress missing implicit constructor warnings.
+  factory BackgroundFetchFailEvent._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory BackgroundFetchFailEvent(String type, Map init) {
+    var init_1 = convertDartToNative_Dictionary(init);
+    return BackgroundFetchFailEvent._create_1(type, init_1);
+  }
+  static BackgroundFetchFailEvent _create_1(type, init) => JS(
+      'BackgroundFetchFailEvent',
+      'new BackgroundFetchFailEvent(#,#)',
+      type,
+      init);
+
+  final List<BackgroundFetchSettledFetch> fetches;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("BackgroundFetchFetch")
+class BackgroundFetchFetch extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory BackgroundFetchFetch._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final _Request request;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("BackgroundFetchManager")
+class BackgroundFetchManager extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory BackgroundFetchManager._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  Future<BackgroundFetchRegistration> fetch(String id, Object requests,
+      [Map options]) {
+    var options_dict = null;
+    if (options != null) {
+      options_dict = convertDartToNative_Dictionary(options);
+    }
+    return promiseToFuture<BackgroundFetchRegistration>(
+        JS("", "#.fetch(#, #, #)", this, id, requests, options_dict));
+  }
+
+  Future<BackgroundFetchRegistration> get(String id) =>
+      promiseToFuture<BackgroundFetchRegistration>(
+          JS("", "#.get(#)", this, id));
+
+  Future<List<String>> getIds() =>
+      promiseToFuture<List<String>>(JS("", "#.getIds()", this));
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("BackgroundFetchRegistration")
+class BackgroundFetchRegistration extends EventTarget {
+  // To suppress missing implicit constructor warnings.
+  factory BackgroundFetchRegistration._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final int downloadTotal;
+
+  final int downloaded;
+
+  final String id;
+
+  final String title;
+
+  final int totalDownloadSize;
+
+  final int uploadTotal;
+
+  final int uploaded;
+
+  Future<bool> abort() => promiseToFuture<bool>(JS("", "#.abort()", this));
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("BackgroundFetchSettledFetch")
+class BackgroundFetchSettledFetch extends BackgroundFetchFetch {
+  // To suppress missing implicit constructor warnings.
+  factory BackgroundFetchSettledFetch._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory BackgroundFetchSettledFetch(_Request request, _Response response) {
+    return BackgroundFetchSettledFetch._create_1(request, response);
+  }
+  static BackgroundFetchSettledFetch _create_1(request, response) => JS(
+      'BackgroundFetchSettledFetch',
+      'new BackgroundFetchSettledFetch(#,#)',
+      request,
+      response);
+
+  final _Response response;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("BackgroundFetchedEvent")
+class BackgroundFetchedEvent extends BackgroundFetchEvent {
+  // To suppress missing implicit constructor warnings.
+  factory BackgroundFetchedEvent._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory BackgroundFetchedEvent(String type, Map init) {
+    var init_1 = convertDartToNative_Dictionary(init);
+    return BackgroundFetchedEvent._create_1(type, init_1);
+  }
+  static BackgroundFetchedEvent _create_1(type, init) => JS(
+      'BackgroundFetchedEvent', 'new BackgroundFetchedEvent(#,#)', type, init);
+
+  final List<BackgroundFetchSettledFetch> fetches;
+
+  Future updateUI(String title) =>
+      promiseToFuture(JS("", "#.updateUI(#)", this, title));
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// http://www.whatwg.org/specs/web-apps/current-work/multipage/browsers.html#barprop
+@deprecated // standard
+@Native("BarProp")
+class BarProp extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory BarProp._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final bool visible;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("BarcodeDetector")
+class BarcodeDetector extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory BarcodeDetector._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory BarcodeDetector() {
+    return BarcodeDetector._create_1();
+  }
+  static BarcodeDetector _create_1() =>
+      JS('BarcodeDetector', 'new BarcodeDetector()');
+
+  Future<List<DetectedBarcode>> detect(/*ImageBitmapSource*/ image) =>
+      promiseToFuture<List<DetectedBarcode>>(
+          JS("", "#.detect(#)", this, image));
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("HTMLBaseElement")
+class BaseElement extends HtmlElement {
+  // To suppress missing implicit constructor warnings.
+  factory BaseElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory BaseElement() => JS(
+      'returns:BaseElement;creates:BaseElement;new:true',
+      '#.createElement(#)',
+      document,
+      "base");
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  BaseElement.created() : super.created();
+
+  String href;
+
+  String target;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("BatteryManager")
+class BatteryManager extends EventTarget {
+  // To suppress missing implicit constructor warnings.
+  factory BatteryManager._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final bool charging;
+
+  final num chargingTime;
+
+  final num dischargingTime;
+
+  final num level;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("BeforeInstallPromptEvent")
+class BeforeInstallPromptEvent extends Event {
+  // To suppress missing implicit constructor warnings.
+  factory BeforeInstallPromptEvent._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory BeforeInstallPromptEvent(String type, [Map eventInitDict]) {
+    if (eventInitDict != null) {
+      var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+      return BeforeInstallPromptEvent._create_1(type, eventInitDict_1);
+    }
+    return BeforeInstallPromptEvent._create_2(type);
+  }
+  static BeforeInstallPromptEvent _create_1(type, eventInitDict) => JS(
+      'BeforeInstallPromptEvent',
+      'new BeforeInstallPromptEvent(#,#)',
+      type,
+      eventInitDict);
+  static BeforeInstallPromptEvent _create_2(type) =>
+      JS('BeforeInstallPromptEvent', 'new BeforeInstallPromptEvent(#)', type);
+
+  final List<String> platforms;
+
+  Future<Map<String, dynamic>> get userChoice =>
+      promiseToFutureAsMap(JS("", "#.userChoice", this));
+
+  Future prompt() => promiseToFuture(JS("", "#.prompt()", this));
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("BeforeUnloadEvent")
+class BeforeUnloadEvent extends Event {
+  // To suppress missing implicit constructor warnings.
+  factory BeforeUnloadEvent._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  // Shadowing definition.
+  String get returnValue => JS("String", "#.returnValue", this);
+
+  set returnValue(String value) {
+    JS("void", "#.returnValue = #", this, value);
+  }
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("Blob")
+class Blob extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory Blob._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final int size;
+
+  final String type;
+
+  Blob slice([int start, int end, String contentType]) native;
+
+  factory Blob(List blobParts, [String type, String endings]) {
+    // TODO: validate that blobParts is a JS Array and convert if not.
+    // TODO: any coercions on the elements of blobParts, e.g. coerce a typed
+    // array to ArrayBuffer if it is a total view.
+    if (type == null && endings == null) {
+      return _create_1(blobParts);
+    }
+    var bag = _create_bag();
+    if (type != null) _bag_set(bag, 'type', type);
+    if (endings != null) _bag_set(bag, 'endings', endings);
+    return _create_2(blobParts, bag);
+  }
+
+  static _create_1(parts) => JS('Blob', 'new self.Blob(#)', parts);
+  static _create_2(parts, bag) => JS('Blob', 'new self.Blob(#, #)', parts, bag);
+
+  static _create_bag() => JS('var', '{}');
+  static _bag_set(bag, key, value) {
+    JS('void', '#[#] = #', bag, key, value);
+  }
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+typedef void BlobCallback(Blob blob);
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("BlobEvent")
+class BlobEvent extends Event {
+  // To suppress missing implicit constructor warnings.
+  factory BlobEvent._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory BlobEvent(String type, Map eventInitDict) {
+    var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+    return BlobEvent._create_1(type, eventInitDict_1);
+  }
+  static BlobEvent _create_1(type, eventInitDict) =>
+      JS('BlobEvent', 'new BlobEvent(#,#)', type, eventInitDict);
+
+  final Blob data;
+
+  final num timecode;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("BluetoothRemoteGATTDescriptor")
+class BluetoothRemoteGattDescriptor extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory BluetoothRemoteGattDescriptor._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final _BluetoothRemoteGATTCharacteristic characteristic;
+
+  final String uuid;
+
+  final ByteData value;
+
+  Future readValue() => promiseToFuture(JS("", "#.readValue()", this));
+
+  Future writeValue(/*BufferSource*/ value) =>
+      promiseToFuture(JS("", "#.writeValue(#)", this, value));
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("Body")
+class Body extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory Body._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final bool bodyUsed;
+
+  Future arrayBuffer() => promiseToFuture(JS("", "#.arrayBuffer()", this));
+
+  Future<Blob> blob() => promiseToFuture<Blob>(JS("", "#.blob()", this));
+
+  Future<FormData> formData() =>
+      promiseToFuture<FormData>(JS("", "#.formData()", this));
+
+  Future json() => promiseToFuture(JS("", "#.json()", this));
+
+  Future<String> text() => promiseToFuture<String>(JS("", "#.text()", this));
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("HTMLBodyElement")
+class BodyElement extends HtmlElement implements WindowEventHandlers {
+  // To suppress missing implicit constructor warnings.
+  factory BodyElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  /**
+   * Static factory designed to expose `blur` events to event
+   * handlers that are not necessarily instances of [BodyElement].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<Event> blurEvent =
+      const EventStreamProvider<Event>('blur');
+
+  /**
+   * Static factory designed to expose `error` events to event
+   * handlers that are not necessarily instances of [BodyElement].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<Event> errorEvent =
+      const EventStreamProvider<Event>('error');
+
+  /**
+   * Static factory designed to expose `focus` events to event
+   * handlers that are not necessarily instances of [BodyElement].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<Event> focusEvent =
+      const EventStreamProvider<Event>('focus');
+
+  /**
+   * Static factory designed to expose `hashchange` events to event
+   * handlers that are not necessarily instances of [BodyElement].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<Event> hashChangeEvent =
+      const EventStreamProvider<Event>('hashchange');
+
+  /**
+   * Static factory designed to expose `load` events to event
+   * handlers that are not necessarily instances of [BodyElement].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<Event> loadEvent =
+      const EventStreamProvider<Event>('load');
+
+  /**
+   * Static factory designed to expose `message` events to event
+   * handlers that are not necessarily instances of [BodyElement].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<MessageEvent> messageEvent =
+      const EventStreamProvider<MessageEvent>('message');
+
+  /**
+   * Static factory designed to expose `offline` events to event
+   * handlers that are not necessarily instances of [BodyElement].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<Event> offlineEvent =
+      const EventStreamProvider<Event>('offline');
+
+  /**
+   * Static factory designed to expose `online` events to event
+   * handlers that are not necessarily instances of [BodyElement].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<Event> onlineEvent =
+      const EventStreamProvider<Event>('online');
+
+  /**
+   * Static factory designed to expose `popstate` events to event
+   * handlers that are not necessarily instances of [BodyElement].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<PopStateEvent> popStateEvent =
+      const EventStreamProvider<PopStateEvent>('popstate');
+
+  /**
+   * Static factory designed to expose `resize` events to event
+   * handlers that are not necessarily instances of [BodyElement].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<Event> resizeEvent =
+      const EventStreamProvider<Event>('resize');
+
+  static const EventStreamProvider<Event> scrollEvent =
+      const EventStreamProvider<Event>('scroll');
+
+  /**
+   * Static factory designed to expose `storage` events to event
+   * handlers that are not necessarily instances of [BodyElement].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<StorageEvent> storageEvent =
+      const EventStreamProvider<StorageEvent>('storage');
+
+  /**
+   * Static factory designed to expose `unload` events to event
+   * handlers that are not necessarily instances of [BodyElement].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<Event> unloadEvent =
+      const EventStreamProvider<Event>('unload');
+
+  factory BodyElement() => JS(
+      'returns:BodyElement;creates:BodyElement;new:true',
+      '#.createElement(#)',
+      document,
+      "body");
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  BodyElement.created() : super.created();
+
+  /// Stream of `blur` events handled by this [BodyElement].
+  ElementStream<Event> get onBlur => blurEvent.forElement(this);
+
+  /// Stream of `error` events handled by this [BodyElement].
+  ElementStream<Event> get onError => errorEvent.forElement(this);
+
+  /// Stream of `focus` events handled by this [BodyElement].
+  ElementStream<Event> get onFocus => focusEvent.forElement(this);
+
+  /// Stream of `hashchange` events handled by this [BodyElement].
+  ElementStream<Event> get onHashChange => hashChangeEvent.forElement(this);
+
+  /// Stream of `load` events handled by this [BodyElement].
+  ElementStream<Event> get onLoad => loadEvent.forElement(this);
+
+  /// Stream of `message` events handled by this [BodyElement].
+  ElementStream<MessageEvent> get onMessage => messageEvent.forElement(this);
+
+  /// Stream of `offline` events handled by this [BodyElement].
+  ElementStream<Event> get onOffline => offlineEvent.forElement(this);
+
+  /// Stream of `online` events handled by this [BodyElement].
+  ElementStream<Event> get onOnline => onlineEvent.forElement(this);
+
+  /// Stream of `popstate` events handled by this [BodyElement].
+  ElementStream<PopStateEvent> get onPopState => popStateEvent.forElement(this);
+
+  /// Stream of `resize` events handled by this [BodyElement].
+  ElementStream<Event> get onResize => resizeEvent.forElement(this);
+
+  ElementStream<Event> get onScroll => scrollEvent.forElement(this);
+
+  /// Stream of `storage` events handled by this [BodyElement].
+  ElementStream<StorageEvent> get onStorage => storageEvent.forElement(this);
+
+  /// Stream of `unload` events handled by this [BodyElement].
+  ElementStream<Event> get onUnload => unloadEvent.forElement(this);
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("BroadcastChannel")
+class BroadcastChannel extends EventTarget {
+  // To suppress missing implicit constructor warnings.
+  factory BroadcastChannel._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  static const EventStreamProvider<MessageEvent> messageEvent =
+      const EventStreamProvider<MessageEvent>('message');
+
+  factory BroadcastChannel(String name) {
+    return BroadcastChannel._create_1(name);
+  }
+  static BroadcastChannel _create_1(name) =>
+      JS('BroadcastChannel', 'new BroadcastChannel(#)', name);
+
+  final String name;
+
+  void close() native;
+
+  void postMessage(Object message) native;
+
+  Stream<MessageEvent> get onMessage => messageEvent.forTarget(this);
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("BudgetState")
+class BudgetState extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory BudgetState._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final num budgetAt;
+
+  final int time;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("HTMLButtonElement")
+class ButtonElement extends HtmlElement {
+  // To suppress missing implicit constructor warnings.
+  factory ButtonElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory ButtonElement() => JS(
+      'returns:ButtonElement;creates:ButtonElement;new:true',
+      '#.createElement(#)',
+      document,
+      "button");
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  ButtonElement.created() : super.created();
+
+  bool autofocus;
+
+  bool disabled;
+
+  final FormElement form;
+
+  String formAction;
+
+  String formEnctype;
+
+  String formMethod;
+
+  bool formNoValidate;
+
+  String formTarget;
+
+  @Unstable()
+  @Returns('NodeList|Null')
+  @Creates('NodeList')
+  final List<Node> labels;
+
+  String name;
+
+  String type;
+
+  final String validationMessage;
+
+  final ValidityState validity;
+
+  String value;
+
+  final bool willValidate;
+
+  bool checkValidity() native;
+
+  bool reportValidity() native;
+
+  void setCustomValidity(String error) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// http://dom.spec.whatwg.org/#cdatasection
+@deprecated // deprecated
+@Native("CDATASection")
+class CDataSection extends Text {
+  // To suppress missing implicit constructor warnings.
+  factory CDataSection._() {
+    throw new UnsupportedError("Not supported");
+  }
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("CacheStorage")
+class CacheStorage extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory CacheStorage._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  Future delete(String cacheName) =>
+      promiseToFuture(JS("", "#.delete(#)", this, cacheName));
+
+  Future has(String cacheName) =>
+      promiseToFuture(JS("", "#.has(#)", this, cacheName));
+
+  Future keys() => promiseToFuture(JS("", "#.keys()", this));
+
+  Future match(/*RequestInfo*/ request, [Map options]) {
+    var options_dict = null;
+    if (options != null) {
+      options_dict = convertDartToNative_Dictionary(options);
+    }
+    return promiseToFuture(
+        JS("", "#.match(#, #)", this, request, options_dict));
+  }
+
+  Future open(String cacheName) =>
+      promiseToFuture(JS("", "#.open(#)", this, cacheName));
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("CanMakePaymentEvent")
+class CanMakePaymentEvent extends ExtendableEvent {
+  // To suppress missing implicit constructor warnings.
+  factory CanMakePaymentEvent._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory CanMakePaymentEvent(String type, Map eventInitDict) {
+    var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+    return CanMakePaymentEvent._create_1(type, eventInitDict_1);
+  }
+  static CanMakePaymentEvent _create_1(type, eventInitDict) => JS(
+      'CanMakePaymentEvent',
+      'new CanMakePaymentEvent(#,#)',
+      type,
+      eventInitDict);
+
+  final List methodData;
+
+  final List modifiers;
+
+  final String paymentRequestOrigin;
+
+  final String topLevelOrigin;
+
+  void respondWith(Future canMakePaymentResponse) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("CanvasCaptureMediaStreamTrack")
+class CanvasCaptureMediaStreamTrack extends MediaStreamTrack {
+  // To suppress missing implicit constructor warnings.
+  factory CanvasCaptureMediaStreamTrack._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final CanvasElement canvas;
+
+  void requestFrame() native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("HTMLCanvasElement")
+class CanvasElement extends HtmlElement implements CanvasImageSource {
+  // To suppress missing implicit constructor warnings.
+  factory CanvasElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  /**
+   * Static factory designed to expose `webglcontextlost` events to event
+   * handlers that are not necessarily instances of [CanvasElement].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<gl.ContextEvent> webGlContextLostEvent =
+      const EventStreamProvider<gl.ContextEvent>('webglcontextlost');
+
+  /**
+   * Static factory designed to expose `webglcontextrestored` events to event
+   * handlers that are not necessarily instances of [CanvasElement].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<gl.ContextEvent> webGlContextRestoredEvent =
+      const EventStreamProvider<gl.ContextEvent>('webglcontextrestored');
+
+  factory CanvasElement({int width, int height}) {
+    CanvasElement e = JS('returns:CanvasElement;creates:CanvasElement;new:true',
+        '#.createElement(#)', document, "canvas");
+    if (width != null) e.width = width;
+    if (height != null) e.height = height;
+    return e;
+  }
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  CanvasElement.created() : super.created();
+
+  /// The height of this canvas element in CSS pixels.
+  int height;
+
+  /// The width of this canvas element in CSS pixels.
+  int width;
+
+  MediaStream captureStream([num frameRate]) native;
+
+  @Creates('CanvasRenderingContext2D|RenderingContext|RenderingContext2')
+  @Returns('CanvasRenderingContext2D|RenderingContext|RenderingContext2|Null')
+  Object getContext(String contextId, [Map attributes]) {
+    if (attributes != null) {
+      var attributes_1 = convertDartToNative_Dictionary(attributes);
+      return _getContext_1(contextId, attributes_1);
+    }
+    return _getContext_2(contextId);
+  }
+
+  @JSName('getContext')
+  @Creates('CanvasRenderingContext2D|RenderingContext|RenderingContext2')
+  @Returns('CanvasRenderingContext2D|RenderingContext|RenderingContext2|Null')
+  Object _getContext_1(contextId, attributes) native;
+  @JSName('getContext')
+  @Creates('CanvasRenderingContext2D|RenderingContext|RenderingContext2')
+  @Returns('CanvasRenderingContext2D|RenderingContext|RenderingContext2|Null')
+  Object _getContext_2(contextId) native;
+
+  @JSName('toDataURL')
+  String _toDataUrl(String type, [arguments_OR_quality]) native;
+
+  OffscreenCanvas transferControlToOffscreen() native;
+
+  /// Stream of `webglcontextlost` events handled by this [CanvasElement].
+  ElementStream<gl.ContextEvent> get onWebGlContextLost =>
+      webGlContextLostEvent.forElement(this);
+
+  /// Stream of `webglcontextrestored` events handled by this [CanvasElement].
+  ElementStream<gl.ContextEvent> get onWebGlContextRestored =>
+      webGlContextRestoredEvent.forElement(this);
+
+  /** An API for drawing on this canvas. */
+  CanvasRenderingContext2D get context2D =>
+      JS('Null|CanvasRenderingContext2D', '#.getContext(#)', this, '2d');
+
+  /**
+   * Returns a new Web GL context for this canvas.
+   *
+   * ## Other resources
+   *
+   * * [WebGL fundamentals](http://www.html5rocks.com/en/tutorials/webgl/webgl_fundamentals/)
+   *   from HTML5Rocks.
+   * * [WebGL homepage](http://get.webgl.org/).
+   */
+  @SupportedBrowser(SupportedBrowser.CHROME)
+  @SupportedBrowser(SupportedBrowser.FIREFOX)
+  gl.RenderingContext getContext3d(
+      {alpha: true,
+      depth: true,
+      stencil: false,
+      antialias: true,
+      premultipliedAlpha: true,
+      preserveDrawingBuffer: false}) {
+    var options = {
+      'alpha': alpha,
+      'depth': depth,
+      'stencil': stencil,
+      'antialias': antialias,
+      'premultipliedAlpha': premultipliedAlpha,
+      'preserveDrawingBuffer': preserveDrawingBuffer,
+    };
+    var context = getContext('webgl', options);
+    if (context == null) {
+      context = getContext('experimental-webgl', options);
+    }
+    return context;
+  }
+
+  /**
+   * Returns a data URI containing a representation of the image in the
+   * format specified by type (defaults to 'image/png').
+   *
+   * Data Uri format is as follow
+   * `data:[<MIME-type>][;charset=<encoding>][;base64],<data>`
+   *
+   * Optional parameter [quality] in the range of 0.0 and 1.0 can be used when
+   * requesting [type] 'image/jpeg' or 'image/webp'. If [quality] is not passed
+   * the default value is used. Note: the default value varies by browser.
+   *
+   * If the height or width of this canvas element is 0, then 'data:' is
+   * returned, representing no data.
+   *
+   * If the type requested is not 'image/png', and the returned value is
+   * 'data:image/png', then the requested type is not supported.
+   *
+   * Example usage:
+   *
+   *     CanvasElement canvas = new CanvasElement();
+   *     var ctx = canvas.context2D
+   *     ..fillStyle = "rgb(200,0,0)"
+   *     ..fillRect(10, 10, 55, 50);
+   *     var dataUrl = canvas.toDataUrl("image/jpeg", 0.95);
+   *     // The Data Uri would look similar to
+   *     // 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUA
+   *     // AAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO
+   *     // 9TXL0Y4OHwAAAABJRU5ErkJggg=='
+   *     //Create a new image element from the data URI.
+   *     var img = new ImageElement();
+   *     img.src = dataUrl;
+   *     document.body.children.add(img);
+   *
+   * See also:
+   *
+   * * [Data URI Scheme](http://en.wikipedia.org/wiki/Data_URI_scheme) from Wikipedia.
+   *
+   * * [HTMLCanvasElement](https://developer.mozilla.org/en-US/docs/DOM/HTMLCanvasElement) from MDN.
+   *
+   * * [toDataUrl](http://dev.w3.org/html5/spec/the-canvas-element.html#dom-canvas-todataurl) from W3C.
+   */
+  String toDataUrl([String type = 'image/png', num quality]) =>
+      _toDataUrl(type, quality);
+
+  @JSName('toBlob')
+  void _toBlob(BlobCallback callback, String type, [Object arguments]) native;
+
+  Future<Blob> toBlob(String type, [Object arguments]) {
+    var completer = new Completer<Blob>();
+    _toBlob((value) {
+      completer.complete(value);
+    }, type, arguments);
+    return completer.future;
+  }
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/**
+ * An opaque canvas object representing a gradient.
+ *
+ * Created by calling [createLinearGradient] or [createRadialGradient] on a
+ * [CanvasRenderingContext2D] object.
+ *
+ * Example usage:
+ *
+ *     var canvas = new CanvasElement(width: 600, height: 600);
+ *     var ctx = canvas.context2D;
+ *     ctx.clearRect(0, 0, 600, 600);
+ *     ctx.save();
+ *     // Create radial gradient.
+ *     CanvasGradient gradient = ctx.createRadialGradient(0, 0, 0, 0, 0, 600);
+ *     gradient.addColorStop(0, '#000');
+ *     gradient.addColorStop(1, 'rgb(255, 255, 255)');
+ *     // Assign gradients to fill.
+ *     ctx.fillStyle = gradient;
+ *     // Draw a rectangle with a gradient fill.
+ *     ctx.fillRect(0, 0, 600, 600);
+ *     ctx.save();
+ *     document.body.children.add(canvas);
+ *
+ * See also:
+ *
+ * * [CanvasGradient](https://developer.mozilla.org/en-US/docs/DOM/CanvasGradient) from MDN.
+ * * [CanvasGradient](https://html.spec.whatwg.org/multipage/scripting.html#canvasgradient)
+ *   from WHATWG.
+ * * [CanvasGradient](http://www.w3.org/TR/2010/WD-2dcontext-20100304/#canvasgradient) from W3C.
+ */
+@Native("CanvasGradient")
+class CanvasGradient extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory CanvasGradient._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  /**
+   * Adds a color stop to this gradient at the offset.
+   *
+   * The [offset] can range between 0.0 and 1.0.
+   *
+   * See also:
+   *
+   * * [Multiple Color Stops](https://developer.mozilla.org/en-US/docs/CSS/linear-gradient#Gradient_with_multiple_color_stops) from MDN.
+   */
+  void addColorStop(num offset, String color) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/**
+ * An opaque object representing a pattern of image, canvas, or video.
+ *
+ * Created by calling [createPattern] on a [CanvasRenderingContext2D] object.
+ *
+ * Example usage:
+ *
+ *     var canvas = new CanvasElement(width: 600, height: 600);
+ *     var ctx = canvas.context2D;
+ *     var img = new ImageElement();
+ *     // Image src needs to be loaded before pattern is applied.
+ *     img.onLoad.listen((event) {
+ *       // When the image is loaded, create a pattern
+ *       // from the ImageElement.
+ *       CanvasPattern pattern = ctx.createPattern(img, 'repeat');
+ *       ctx.rect(0, 0, canvas.width, canvas.height);
+ *       ctx.fillStyle = pattern;
+ *       ctx.fill();
+ *     });
+ *     img.src = "images/foo.jpg";
+ *     document.body.children.add(canvas);
+ *
+ * See also:
+ * * [CanvasPattern](https://developer.mozilla.org/en-US/docs/DOM/CanvasPattern) from MDN.
+ * * [CanvasPattern](https://html.spec.whatwg.org/multipage/scripting.html#canvaspattern)
+ *   from WHATWG.
+ * * [CanvasPattern](http://www.w3.org/TR/2010/WD-2dcontext-20100304/#canvaspattern) from W3C.
+ */
+@Native("CanvasPattern")
+class CanvasPattern extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory CanvasPattern._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  void setTransform(Matrix transform) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+abstract class CanvasRenderingContext {
+  CanvasElement get canvas;
+}
+
+@Native("CanvasRenderingContext2D")
+class CanvasRenderingContext2D extends Interceptor
+    implements CanvasRenderingContext {
+  // To suppress missing implicit constructor warnings.
+  factory CanvasRenderingContext2D._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final CanvasElement canvas;
+
+  Matrix currentTransform;
+
+  String direction;
+
+  @Creates('String|CanvasGradient|CanvasPattern')
+  @Returns('String|CanvasGradient|CanvasPattern')
+  Object fillStyle;
+
+  String filter;
+
+  String font;
+
+  num globalAlpha;
+
+  String globalCompositeOperation;
+
+  /**
+   * Whether images and patterns on this canvas will be smoothed when this
+   * canvas is scaled.
+   *
+   * ## Other resources
+   *
+   * * [Image
+   *   smoothing](https://html.spec.whatwg.org/multipage/scripting.html#image-smoothing)
+   *   from WHATWG.
+   */
+  bool imageSmoothingEnabled;
+
+  String imageSmoothingQuality;
+
+  String lineCap;
+
+  String lineJoin;
+
+  num lineWidth;
+
+  num miterLimit;
+
+  num shadowBlur;
+
+  String shadowColor;
+
+  num shadowOffsetX;
+
+  num shadowOffsetY;
+
+  @Creates('String|CanvasGradient|CanvasPattern')
+  @Returns('String|CanvasGradient|CanvasPattern')
+  Object strokeStyle;
+
+  String textAlign;
+
+  String textBaseline;
+
+  void addHitRegion([Map options]) {
+    if (options != null) {
+      var options_1 = convertDartToNative_Dictionary(options);
+      _addHitRegion_1(options_1);
+      return;
+    }
+    _addHitRegion_2();
+    return;
+  }
+
+  @JSName('addHitRegion')
+  void _addHitRegion_1(options) native;
+  @JSName('addHitRegion')
+  void _addHitRegion_2() native;
+
+  void beginPath() native;
+
+  void clearHitRegions() native;
+
+  void clearRect(num x, num y, num width, num height) native;
+
+  void clip([path_OR_winding, String winding]) native;
+
+  @Creates('ImageData|=Object')
+  ImageData createImageData(data_OR_imagedata_OR_sw,
+      [int sh_OR_sw,
+      imageDataColorSettings_OR_sh,
+      Map imageDataColorSettings]) {
+    if ((data_OR_imagedata_OR_sw is ImageData) &&
+        sh_OR_sw == null &&
+        imageDataColorSettings_OR_sh == null &&
+        imageDataColorSettings == null) {
+      var imagedata_1 = convertDartToNative_ImageData(data_OR_imagedata_OR_sw);
+      return convertNativeToDart_ImageData(_createImageData_1(imagedata_1));
+    }
+    if (sh_OR_sw != null &&
+        (data_OR_imagedata_OR_sw is int) &&
+        imageDataColorSettings_OR_sh == null &&
+        imageDataColorSettings == null) {
+      return convertNativeToDart_ImageData(
+          _createImageData_2(data_OR_imagedata_OR_sw, sh_OR_sw));
+    }
+    if ((imageDataColorSettings_OR_sh is Map) &&
+        sh_OR_sw != null &&
+        (data_OR_imagedata_OR_sw is int) &&
+        imageDataColorSettings == null) {
+      var imageDataColorSettings_1 =
+          convertDartToNative_Dictionary(imageDataColorSettings_OR_sh);
+      return convertNativeToDart_ImageData(_createImageData_3(
+          data_OR_imagedata_OR_sw, sh_OR_sw, imageDataColorSettings_1));
+    }
+    if ((imageDataColorSettings_OR_sh is int) &&
+        sh_OR_sw != null &&
+        data_OR_imagedata_OR_sw != null &&
+        imageDataColorSettings == null) {
+      return convertNativeToDart_ImageData(_createImageData_4(
+          data_OR_imagedata_OR_sw, sh_OR_sw, imageDataColorSettings_OR_sh));
+    }
+    if (imageDataColorSettings != null &&
+        (imageDataColorSettings_OR_sh is int) &&
+        sh_OR_sw != null &&
+        data_OR_imagedata_OR_sw != null) {
+      var imageDataColorSettings_1 =
+          convertDartToNative_Dictionary(imageDataColorSettings);
+      return convertNativeToDart_ImageData(_createImageData_5(
+          data_OR_imagedata_OR_sw,
+          sh_OR_sw,
+          imageDataColorSettings_OR_sh,
+          imageDataColorSettings_1));
+    }
+    throw new ArgumentError("Incorrect number or type of arguments");
+  }
+
+  @JSName('createImageData')
+  @Creates('ImageData|=Object')
+  _createImageData_1(imagedata) native;
+  @JSName('createImageData')
+  @Creates('ImageData|=Object')
+  _createImageData_2(int sw, sh) native;
+  @JSName('createImageData')
+  @Creates('ImageData|=Object')
+  _createImageData_3(int sw, sh, imageDataColorSettings) native;
+  @JSName('createImageData')
+  @Creates('ImageData|=Object')
+  _createImageData_4(data, sw, int sh) native;
+  @JSName('createImageData')
+  @Creates('ImageData|=Object')
+  _createImageData_5(data, sw, int sh, imageDataColorSettings) native;
+
+  CanvasGradient createLinearGradient(num x0, num y0, num x1, num y1) native;
+
+  CanvasPattern createPattern(Object image, String repetitionType) native;
+
+  CanvasGradient createRadialGradient(
+      num x0, num y0, num r0, num x1, num y1, num r1) native;
+
+  void drawFocusIfNeeded(element_OR_path, [Element element]) native;
+
+  void fill([path_OR_winding, String winding]) native;
+
+  void fillRect(num x, num y, num width, num height) native;
+
+  Map getContextAttributes() {
+    return convertNativeToDart_Dictionary(_getContextAttributes_1());
+  }
+
+  @JSName('getContextAttributes')
+  _getContextAttributes_1() native;
+
+  @Creates('ImageData|=Object')
+  ImageData getImageData(int sx, int sy, int sw, int sh) {
+    return convertNativeToDart_ImageData(_getImageData_1(sx, sy, sw, sh));
+  }
+
+  @JSName('getImageData')
+  @Creates('ImageData|=Object')
+  _getImageData_1(sx, sy, sw, sh) native;
+
+  @JSName('getLineDash')
+  List<num> _getLineDash() native;
+
+  bool isContextLost() native;
+
+  bool isPointInPath(path_OR_x, num x_OR_y, [winding_OR_y, String winding])
+      native;
+
+  bool isPointInStroke(path_OR_x, num x_OR_y, [num y]) native;
+
+  TextMetrics measureText(String text) native;
+
+  void putImageData(ImageData imagedata, int dx, int dy,
+      [int dirtyX, int dirtyY, int dirtyWidth, int dirtyHeight]) {
+    if (dirtyX == null &&
+        dirtyY == null &&
+        dirtyWidth == null &&
+        dirtyHeight == null) {
+      var imagedata_1 = convertDartToNative_ImageData(imagedata);
+      _putImageData_1(imagedata_1, dx, dy);
+      return;
+    }
+    if (dirtyHeight != null &&
+        dirtyWidth != null &&
+        dirtyY != null &&
+        dirtyX != null) {
+      var imagedata_1 = convertDartToNative_ImageData(imagedata);
+      _putImageData_2(
+          imagedata_1, dx, dy, dirtyX, dirtyY, dirtyWidth, dirtyHeight);
+      return;
+    }
+    throw new ArgumentError("Incorrect number or type of arguments");
+  }
+
+  @JSName('putImageData')
+  void _putImageData_1(imagedata, dx, dy) native;
+  @JSName('putImageData')
+  void _putImageData_2(
+      imagedata, dx, dy, dirtyX, dirtyY, dirtyWidth, dirtyHeight) native;
+
+  void removeHitRegion(String id) native;
+
+  void resetTransform() native;
+
+  void restore() native;
+
+  void rotate(num angle) native;
+
+  void save() native;
+
+  void scale(num x, num y) native;
+
+  void scrollPathIntoView([Path2D path]) native;
+
+  void setTransform(num a, num b, num c, num d, num e, num f) native;
+
+  void stroke([Path2D path]) native;
+
+  void strokeRect(num x, num y, num width, num height) native;
+
+  void strokeText(String text, num x, num y, [num maxWidth]) native;
+
+  void transform(num a, num b, num c, num d, num e, num f) native;
+
+  void translate(num x, num y) native;
+
+  // From CanvasPath
+
+  @JSName('arc')
+  void _arc(num x, num y, num radius, num startAngle, num endAngle,
+      bool anticlockwise) native;
+
+  void arcTo(num x1, num y1, num x2, num y2, num radius) native;
+
+  void bezierCurveTo(num cp1x, num cp1y, num cp2x, num cp2y, num x, num y)
+      native;
+
+  void closePath() native;
+
+  void ellipse(num x, num y, num radiusX, num radiusY, num rotation,
+      num startAngle, num endAngle, bool anticlockwise) native;
+
+  void lineTo(num x, num y) native;
+
+  void moveTo(num x, num y) native;
+
+  void quadraticCurveTo(num cpx, num cpy, num x, num y) native;
+
+  void rect(num x, num y, num width, num height) native;
+
+  ImageData createImageDataFromImageData(ImageData imagedata) =>
+      JS('ImageData', '#.createImageData(#)', this, imagedata);
+
+  /**
+   * Sets the color used inside shapes.
+   * [r], [g], [b] are 0-255, [a] is 0-1.
+   */
+  void setFillColorRgb(int r, int g, int b, [num a = 1]) {
+    this.fillStyle = 'rgba($r, $g, $b, $a)';
+  }
+
+  /**
+   * Sets the color used inside shapes.
+   * [h] is in degrees, 0-360.
+   * [s], [l] are in percent, 0-100.
+   * [a] is 0-1.
+   */
+  void setFillColorHsl(int h, num s, num l, [num a = 1]) {
+    this.fillStyle = 'hsla($h, $s%, $l%, $a)';
+  }
+
+  /**
+   * Sets the color used for stroking shapes.
+   * [r], [g], [b] are 0-255, [a] is 0-1.
+   */
+  void setStrokeColorRgb(int r, int g, int b, [num a = 1]) {
+    this.strokeStyle = 'rgba($r, $g, $b, $a)';
+  }
+
+  /**
+   * Sets the color used for stroking shapes.
+   * [h] is in degrees, 0-360.
+   * [s], [l] are in percent, 0-100.
+   * [a] is 0-1.
+   */
+  void setStrokeColorHsl(int h, num s, num l, [num a = 1]) {
+    this.strokeStyle = 'hsla($h, $s%, $l%, $a)';
+  }
+
+  void arc(num x, num y, num radius, num startAngle, num endAngle,
+      [bool anticlockwise = false]) {
+    // TODO(terry): This should not be needed: dartbug.com/20939.
+    JS('void', '#.arc(#, #, #, #, #, #)', this, x, y, radius, startAngle,
+        endAngle, anticlockwise);
+  }
+
+  CanvasPattern createPatternFromImage(
+          ImageElement image, String repetitionType) =>
+      JS('CanvasPattern', '#.createPattern(#, #)', this, image, repetitionType);
+
+  /**
+   * Draws an image from a CanvasImageSource to an area of this canvas.
+   *
+   * The image will be drawn to an area of this canvas defined by
+   * [destRect]. [sourceRect] defines the region of the source image that is
+   * drawn.
+   * If [sourceRect] is not provided, then
+   * the entire rectangular image from [source] will be drawn to this context.
+   *
+   * If the image is larger than canvas
+   * will allow, the image will be clipped to fit the available space.
+   *
+   *     CanvasElement canvas = new CanvasElement(width: 600, height: 600);
+   *     CanvasRenderingContext2D ctx = canvas.context2D;
+   *     ImageElement img = document.query('img');
+   *     img.width = 100;
+   *     img.height = 100;
+   *
+   *     // Scale the image to 20x20.
+   *     ctx.drawImageToRect(img, new Rectangle(50, 50, 20, 20));
+   *
+   *     VideoElement video = document.query('video');
+   *     video.width = 100;
+   *     video.height = 100;
+   *     // Take the middle 20x20 pixels from the video and stretch them.
+   *     ctx.drawImageToRect(video, new Rectangle(50, 50, 100, 100),
+   *         sourceRect: new Rectangle(40, 40, 20, 20));
+   *
+   *     // Draw the top 100x20 pixels from the otherCanvas.
+   *     CanvasElement otherCanvas = document.query('canvas');
+   *     ctx.drawImageToRect(otherCanvas, new Rectangle(0, 0, 100, 20),
+   *         sourceRect: new Rectangle(0, 0, 100, 20));
+   *
+   * See also:
+   *
+   *   * [CanvasImageSource] for more information on what data is retrieved
+   * from [source].
+   *   * [drawImage](http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html#dom-context-2d-drawimage)
+   * from the WHATWG.
+   */
+  void drawImageToRect(CanvasImageSource source, Rectangle destRect,
+      {Rectangle sourceRect}) {
+    if (sourceRect == null) {
+      drawImageScaled(
+          source, destRect.left, destRect.top, destRect.width, destRect.height);
+    } else {
+      drawImageScaledFromSource(
+          source,
+          sourceRect.left,
+          sourceRect.top,
+          sourceRect.width,
+          sourceRect.height,
+          destRect.left,
+          destRect.top,
+          destRect.width,
+          destRect.height);
+    }
+  }
+
+  /**
+   * Draws an image from a CanvasImageSource to this canvas.
+   *
+   * The entire image from [source] will be drawn to this context with its top
+   * left corner at the point ([destX], [destY]). If the image is
+   * larger than canvas will allow, the image will be clipped to fit the
+   * available space.
+   *
+   *     CanvasElement canvas = new CanvasElement(width: 600, height: 600);
+   *     CanvasRenderingContext2D ctx = canvas.context2D;
+   *     ImageElement img = document.query('img');
+   *
+   *     ctx.drawImage(img, 100, 100);
+   *
+   *     VideoElement video = document.query('video');
+   *     ctx.drawImage(video, 0, 0);
+   *
+   *     CanvasElement otherCanvas = document.query('canvas');
+   *     otherCanvas.width = 100;
+   *     otherCanvas.height = 100;
+   *     ctx.drawImage(otherCanvas, 590, 590); // will get clipped
+   *
+   * See also:
+   *
+   *   * [CanvasImageSource] for more information on what data is retrieved
+   * from [source].
+   *   * [drawImage](http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html#dom-context-2d-drawimage)
+   * from the WHATWG.
+   */
+  @JSName('drawImage')
+  void drawImage(CanvasImageSource source, num destX, num destY) native;
+
+  /**
+   * Draws an image from a CanvasImageSource to an area of this canvas.
+   *
+   * The image will be drawn to this context with its top left corner at the
+   * point ([destX], [destY]) and will be scaled to be [destWidth] wide and
+   * [destHeight] tall.
+   *
+   * If the image is larger than canvas
+   * will allow, the image will be clipped to fit the available space.
+   *
+   *     CanvasElement canvas = new CanvasElement(width: 600, height: 600);
+   *     CanvasRenderingContext2D ctx = canvas.context2D;
+   *     ImageElement img = document.query('img');
+   *     img.width = 100;
+   *     img.height = 100;
+   *
+   *     // Scale the image to 300x50 at the point (20, 20)
+   *     ctx.drawImageScaled(img, 20, 20, 300, 50);
+   *
+   * See also:
+   *
+   *   * [CanvasImageSource] for more information on what data is retrieved
+   * from [source].
+   *   * [drawImage](http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html#dom-context-2d-drawimage)
+   * from the WHATWG.
+   */
+  @JSName('drawImage')
+  void drawImageScaled(CanvasImageSource source, num destX, num destY,
+      num destWidth, num destHeight) native;
+
+  /**
+   * Draws an image from a CanvasImageSource to an area of this canvas.
+   *
+   * The image is a region of [source] that is [sourceWidth] wide and
+   * [destHeight] tall with top left corner at ([sourceX], [sourceY]).
+   * The image will be drawn to this context with its top left corner at the
+   * point ([destX], [destY]) and will be scaled to be [destWidth] wide and
+   * [destHeight] tall.
+   *
+   * If the image is larger than canvas
+   * will allow, the image will be clipped to fit the available space.
+   *
+   *     VideoElement video = document.query('video');
+   *     video.width = 100;
+   *     video.height = 100;
+   *     // Take the middle 20x20 pixels from the video and stretch them.
+   *     ctx.drawImageScaledFromSource(video, 40, 40, 20, 20, 50, 50, 100, 100);
+   *
+   *     // Draw the top 100x20 pixels from the otherCanvas to this one.
+   *     CanvasElement otherCanvas = document.query('canvas');
+   *     ctx.drawImageScaledFromSource(otherCanvas, 0, 0, 100, 20, 0, 0, 100, 20);
+   *
+   * See also:
+   *
+   *   * [CanvasImageSource] for more information on what data is retrieved
+   * from [source].
+   *   * [drawImage](http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html#dom-context-2d-drawimage)
+   * from the WHATWG.
+   */
+  @JSName('drawImage')
+  void drawImageScaledFromSource(
+      CanvasImageSource source,
+      num sourceX,
+      num sourceY,
+      num sourceWidth,
+      num sourceHeight,
+      num destX,
+      num destY,
+      num destWidth,
+      num destHeight) native;
+
+  @SupportedBrowser(SupportedBrowser.CHROME)
+  @SupportedBrowser(SupportedBrowser.SAFARI)
+  @SupportedBrowser(SupportedBrowser.IE, '11')
+  @Unstable()
+  // TODO(14316): Firefox has this functionality with mozDashOffset, but it
+  // needs to be polyfilled.
+  num get lineDashOffset =>
+      JS('num', '#.lineDashOffset || #.webkitLineDashOffset', this, this);
+
+  @SupportedBrowser(SupportedBrowser.CHROME)
+  @SupportedBrowser(SupportedBrowser.SAFARI)
+  @SupportedBrowser(SupportedBrowser.IE, '11')
+  @Unstable()
+  // TODO(14316): Firefox has this functionality with mozDashOffset, but it
+  // needs to be polyfilled.
+  set lineDashOffset(num value) {
+    JS(
+        'void',
+        'typeof #.lineDashOffset != "undefined" ? #.lineDashOffset = # : '
+            '#.webkitLineDashOffset = #',
+        this,
+        this,
+        value,
+        this,
+        value);
+  }
+
+  @SupportedBrowser(SupportedBrowser.CHROME)
+  @SupportedBrowser(SupportedBrowser.SAFARI)
+  @SupportedBrowser(SupportedBrowser.IE, '11')
+  @Unstable()
+  List<num> getLineDash() {
+    // TODO(14316): Firefox has this functionality with mozDash, but it's a bit
+    // different.
+    if (JS('bool', '!!#.getLineDash', this)) {
+      return JS('List<num>', '#.getLineDash()', this);
+    } else if (JS('bool', '!!#.webkitLineDash', this)) {
+      return JS('List<num>', '#.webkitLineDash', this);
+    }
+  }
+
+  @SupportedBrowser(SupportedBrowser.CHROME)
+  @SupportedBrowser(SupportedBrowser.SAFARI)
+  @SupportedBrowser(SupportedBrowser.IE, '11')
+  @Unstable()
+  void setLineDash(List<num> dash) {
+    // TODO(14316): Firefox has this functionality with mozDash, but it's a bit
+    // different.
+    if (JS('bool', '!!#.setLineDash', this)) {
+      JS('void', '#.setLineDash(#)', this, dash);
+    } else if (JS('bool', '!!#.webkitLineDash', this)) {
+      JS('void', '#.webkitLineDash = #', this, dash);
+    }
+  }
+
+  /**
+   * Draws text to the canvas.
+   *
+   * The text is drawn starting at coordinates ([x], [y]).
+   * If [maxWidth] is provided and the [text] is computed to be wider than
+   * [maxWidth], then the drawn text is scaled down horizontally to fit.
+   *
+   * The text uses the current [CanvasRenderingContext2D.font] property for font
+   * options, such as typeface and size, and the current
+   * [CanvasRenderingContext2D.fillStyle] for style options such as color.
+   * The current [CanvasRenderingContext2D.textAlign] and
+   * [CanvasRenderingContext2D.textBaseLine] properties are also applied to the
+   * drawn text.
+   */
+  void fillText(String text, num x, num y, [num maxWidth]) {
+    if (maxWidth != null) {
+      JS('void', '#.fillText(#, #, #, #)', this, text, x, y, maxWidth);
+    } else {
+      JS('void', '#.fillText(#, #, #)', this, text, x, y);
+    }
+  }
+
+  /** Deprecated always returns 1.0 */
+  @deprecated
+  double get backingStorePixelRatio => 1.0;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("CharacterData")
+class CharacterData extends Node
+    implements NonDocumentTypeChildNode, ChildNode {
+  // To suppress missing implicit constructor warnings.
+  factory CharacterData._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  String data;
+
+  final int length;
+
+  void appendData(String data) native;
+
+  void deleteData(int offset, int count) native;
+
+  void insertData(int offset, String data) native;
+
+  void replaceData(int offset, int count, String data) native;
+
+  String substringData(int offset, int count) native;
+
+  // From ChildNode
+
+  void after(Object nodes) native;
+
+  void before(Object nodes) native;
+
+  // From NonDocumentTypeChildNode
+
+  final Element nextElementSibling;
+
+  final Element previousElementSibling;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+abstract class ChildNode extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory ChildNode._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  void after(Object nodes);
+
+  void before(Object nodes);
+
+  void remove();
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("Client")
+class Client extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory Client._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final String frameType;
+
+  final String id;
+
+  final String type;
+
+  final String url;
+
+  void postMessage(Object message, [List<Object> transfer]) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("Clients")
+class Clients extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory Clients._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  Future claim() => promiseToFuture(JS("", "#.claim()", this));
+
+  Future get(String id) => promiseToFuture(JS("", "#.get(#)", this, id));
+
+  Future<List<Client>> matchAll([Map options]) {
+    var options_dict = null;
+    if (options != null) {
+      options_dict = convertDartToNative_Dictionary(options);
+    }
+    return promiseToFuture<List<Client>>(
+        JS("", "#.matchAll(#)", this, options_dict));
+  }
+
+  Future<WindowClient> openWindow(String url) =>
+      promiseToFuture<WindowClient>(JS("", "#.openWindow(#)", this, url));
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("ClipboardEvent")
+class ClipboardEvent extends Event {
+  // To suppress missing implicit constructor warnings.
+  factory ClipboardEvent._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory ClipboardEvent(String type, [Map eventInitDict]) {
+    if (eventInitDict != null) {
+      var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+      return ClipboardEvent._create_1(type, eventInitDict_1);
+    }
+    return ClipboardEvent._create_2(type);
+  }
+  static ClipboardEvent _create_1(type, eventInitDict) =>
+      JS('ClipboardEvent', 'new ClipboardEvent(#,#)', type, eventInitDict);
+  static ClipboardEvent _create_2(type) =>
+      JS('ClipboardEvent', 'new ClipboardEvent(#)', type);
+
+  final DataTransfer clipboardData;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("CloseEvent")
+class CloseEvent extends Event {
+  // To suppress missing implicit constructor warnings.
+  factory CloseEvent._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory CloseEvent(String type, [Map eventInitDict]) {
+    if (eventInitDict != null) {
+      var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+      return CloseEvent._create_1(type, eventInitDict_1);
+    }
+    return CloseEvent._create_2(type);
+  }
+  static CloseEvent _create_1(type, eventInitDict) =>
+      JS('CloseEvent', 'new CloseEvent(#,#)', type, eventInitDict);
+  static CloseEvent _create_2(type) =>
+      JS('CloseEvent', 'new CloseEvent(#)', type);
+
+  final int code;
+
+  final String reason;
+
+  final bool wasClean;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("Comment")
+class Comment extends CharacterData {
+  factory Comment([String data]) {
+    return JS('returns:Comment;depends:none;effects:none;new:true',
+        '#.createComment(#)', document, data == null ? "" : data);
+  }
+  // To suppress missing implicit constructor warnings.
+  factory Comment._() {
+    throw new UnsupportedError("Not supported");
+  }
+}
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+@Native("CompositionEvent")
+class CompositionEvent extends UIEvent {
+  factory CompositionEvent(String type,
+      {bool canBubble: false,
+      bool cancelable: false,
+      Window view,
+      String data,
+      String locale}) {
+    if (view == null) {
+      view = window;
+    }
+    CompositionEvent e = document._createEvent("CompositionEvent");
+
+    if (Device.isFirefox) {
+      // Firefox requires the locale parameter that isn't supported elsewhere.
+      JS('void', '#.initCompositionEvent(#, #, #, #, #, #)', e, type, canBubble,
+          cancelable, view, data, locale);
+    } else {
+      e._initCompositionEvent(type, canBubble, cancelable, view, data);
+    }
+
+    return e;
+  }
+
+  factory CompositionEvent._(String type, [Map eventInitDict]) {
+    if (eventInitDict != null) {
+      var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+      return CompositionEvent._create_1(type, eventInitDict_1);
+    }
+    return CompositionEvent._create_2(type);
+  }
+  static CompositionEvent _create_1(type, eventInitDict) =>
+      JS('CompositionEvent', 'new CompositionEvent(#,#)', type, eventInitDict);
+  static CompositionEvent _create_2(type) =>
+      JS('CompositionEvent', 'new CompositionEvent(#)', type);
+
+  final String data;
+
+  @JSName('initCompositionEvent')
+  void _initCompositionEvent(String type, bool bubbles, bool cancelable,
+      Window view, String data) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME, '26')
+@Native("HTMLContentElement")
+class ContentElement extends HtmlElement {
+  // To suppress missing implicit constructor warnings.
+  factory ContentElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory ContentElement() => document.createElement("content");
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  ContentElement.created() : super.created();
+
+  /// Checks if this type is supported on the current platform.
+  static bool get supported => Element.isTagSupported('content');
+
+  String select;
+
+  @Returns('NodeList|Null')
+  @Creates('NodeList')
+  List<Node> getDistributedNodes() native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("CookieStore")
+class CookieStore extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory CookieStore._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  Future getAll([Map options]) {
+    var options_dict = null;
+    if (options != null) {
+      options_dict = convertDartToNative_Dictionary(options);
+    }
+    return promiseToFuture(JS("", "#.getAll(#)", this, options_dict));
+  }
+
+  Future set(String name, String value, [Map options]) {
+    var options_dict = null;
+    if (options != null) {
+      options_dict = convertDartToNative_Dictionary(options);
+    }
+    return promiseToFuture(
+        JS("", "#.set(#, #, #)", this, name, value, options_dict));
+  }
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("Coordinates")
+class Coordinates extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory Coordinates._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final num accuracy;
+
+  final num altitude;
+
+  final num altitudeAccuracy;
+
+  final num heading;
+
+  final num latitude;
+
+  final num longitude;
+
+  final num speed;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("Credential")
+class Credential extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory Credential._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final String id;
+
+  final String type;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("CredentialUserData")
+class CredentialUserData extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory CredentialUserData._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  @JSName('iconURL')
+  final String iconUrl;
+
+  final String name;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("CredentialsContainer")
+class CredentialsContainer extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory CredentialsContainer._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  Future create([Map options]) {
+    var options_dict = null;
+    if (options != null) {
+      options_dict = convertDartToNative_Dictionary(options);
+    }
+    return promiseToFuture(JS("", "#.create(#)", this, options_dict));
+  }
+
+  Future get([Map options]) {
+    var options_dict = null;
+    if (options != null) {
+      options_dict = convertDartToNative_Dictionary(options);
+    }
+    return promiseToFuture(JS("", "#.get(#)", this, options_dict));
+  }
+
+  Future preventSilentAccess() =>
+      promiseToFuture(JS("", "#.preventSilentAccess()", this));
+
+  Future requireUserMediation() =>
+      promiseToFuture(JS("", "#.requireUserMediation()", this));
+
+  Future store(Credential credential) =>
+      promiseToFuture(JS("", "#.store(#)", this, credential));
+}
+// Copyright (c) 2015, 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.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.SAFARI)
+@Native("Crypto")
+class Crypto extends Interceptor {
+  TypedData getRandomValues(TypedData array) {
+    return _getRandomValues(array);
+  }
+
+  // To suppress missing implicit constructor warnings.
+  factory Crypto._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  /// Checks if this type is supported on the current platform.
+  static bool get supported =>
+      JS('bool', '!!(window.crypto && window.crypto.getRandomValues)');
+
+  final _SubtleCrypto subtle;
+
+  @JSName('getRandomValues')
+  @Creates('TypedData')
+  @Returns('TypedData|Null')
+  TypedData _getRandomValues(TypedData array) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("CryptoKey")
+class CryptoKey extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory CryptoKey._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  @Creates('Null')
+  final Object algorithm;
+
+  final bool extractable;
+
+  final String type;
+
+  final Object usages;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("CSS")
+class Css extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory Css._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  static final _Worklet paintWorklet;
+
+  static CssUnitValue Hz(num value) native;
+
+  static CssUnitValue ch(num value) native;
+
+  static CssUnitValue cm(num value) native;
+
+  static CssUnitValue deg(num value) native;
+
+  static CssUnitValue dpcm(num value) native;
+
+  static CssUnitValue dpi(num value) native;
+
+  static CssUnitValue dppx(num value) native;
+
+  static CssUnitValue em(num value) native;
+
+  static String escape(String ident) native;
+
+  static CssUnitValue ex(num value) native;
+
+  static CssUnitValue fr(num value) native;
+
+  static CssUnitValue grad(num value) native;
+
+  @JSName('in')
+  static CssUnitValue inch(num value) native;
+
+  static CssUnitValue kHz(num value) native;
+
+  static CssUnitValue mm(num value) native;
+
+  static CssUnitValue ms(num value) native;
+
+  static CssUnitValue number(num value) native;
+
+  static CssUnitValue pc(num value) native;
+
+  static CssUnitValue percent(num value) native;
+
+  static CssUnitValue pt(num value) native;
+
+  static CssUnitValue px(num value) native;
+
+  static CssUnitValue rad(num value) native;
+
+  static void registerProperty(Map descriptor) {
+    var descriptor_1 = convertDartToNative_Dictionary(descriptor);
+    _registerProperty_1(descriptor_1);
+    return;
+  }
+
+  @JSName('registerProperty')
+  static void _registerProperty_1(descriptor) native;
+
+  static CssUnitValue rem(num value) native;
+
+  static CssUnitValue s(num value) native;
+
+  static bool supports(String property, String value) native;
+
+  @JSName('supports')
+  static bool supportsCondition(String conditionText) native;
+
+  static CssUnitValue turn(num value) native;
+
+  static CssUnitValue vh(num value) native;
+
+  static CssUnitValue vmax(num value) native;
+
+  static CssUnitValue vmin(num value) native;
+
+  static CssUnitValue vw(num value) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("CSSCharsetRule")
+class CssCharsetRule extends CssRule {
+  // To suppress missing implicit constructor warnings.
+  factory CssCharsetRule._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  String encoding;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("CSSConditionRule")
+class CssConditionRule extends CssGroupingRule {
+  // To suppress missing implicit constructor warnings.
+  factory CssConditionRule._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final String conditionText;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("CSSFontFaceRule")
+class CssFontFaceRule extends CssRule {
+  // To suppress missing implicit constructor warnings.
+  factory CssFontFaceRule._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final CssStyleDeclaration style;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("CSSGroupingRule")
+class CssGroupingRule extends CssRule {
+  // To suppress missing implicit constructor warnings.
+  factory CssGroupingRule._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  @Returns('_CssRuleList|Null')
+  @Creates('_CssRuleList')
+  final List<CssRule> cssRules;
+
+  void deleteRule(int index) native;
+
+  int insertRule(String rule, int index) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("CSSImageValue")
+class CssImageValue extends CssResourceValue {
+  // To suppress missing implicit constructor warnings.
+  factory CssImageValue._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final num intrinsicHeight;
+
+  final num intrinsicRatio;
+
+  final num intrinsicWidth;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("CSSImportRule")
+class CssImportRule extends CssRule {
+  // To suppress missing implicit constructor warnings.
+  factory CssImportRule._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final String href;
+
+  final MediaList media;
+
+  final CssStyleSheet styleSheet;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("CSSKeyframeRule,MozCSSKeyframeRule,WebKitCSSKeyframeRule")
+class CssKeyframeRule extends CssRule {
+  // To suppress missing implicit constructor warnings.
+  factory CssKeyframeRule._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  String keyText;
+
+  final CssStyleDeclaration style;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("CSSKeyframesRule,MozCSSKeyframesRule,WebKitCSSKeyframesRule")
+class CssKeyframesRule extends CssRule {
+  // To suppress missing implicit constructor warnings.
+  factory CssKeyframesRule._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  @Returns('_CssRuleList|Null')
+  @Creates('_CssRuleList')
+  final List<CssRule> cssRules;
+
+  String name;
+
+  CssKeyframeRule __getter__(int index) native;
+
+  void appendRule(String rule) native;
+
+  void deleteRule(String select) native;
+
+  CssKeyframeRule findRule(String select) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("CSSKeywordValue")
+class CssKeywordValue extends CssStyleValue {
+  // To suppress missing implicit constructor warnings.
+  factory CssKeywordValue._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory CssKeywordValue(String keyword) {
+    return CssKeywordValue._create_1(keyword);
+  }
+  static CssKeywordValue _create_1(keyword) =>
+      JS('CssKeywordValue', 'new CSSKeywordValue(#)', keyword);
+
+  String value;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("CSSMatrixComponent")
+class CssMatrixComponent extends CssTransformComponent {
+  // To suppress missing implicit constructor warnings.
+  factory CssMatrixComponent._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory CssMatrixComponent(DomMatrixReadOnly matrix, [Map options]) {
+    if (options != null) {
+      var options_1 = convertDartToNative_Dictionary(options);
+      return CssMatrixComponent._create_1(matrix, options_1);
+    }
+    return CssMatrixComponent._create_2(matrix);
+  }
+  static CssMatrixComponent _create_1(matrix, options) =>
+      JS('CssMatrixComponent', 'new CSSMatrixComponent(#,#)', matrix, options);
+  static CssMatrixComponent _create_2(matrix) =>
+      JS('CssMatrixComponent', 'new CSSMatrixComponent(#)', matrix);
+
+  DomMatrix matrix;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("CSSMediaRule")
+class CssMediaRule extends CssConditionRule {
+  // To suppress missing implicit constructor warnings.
+  factory CssMediaRule._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final MediaList media;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("CSSNamespaceRule")
+class CssNamespaceRule extends CssRule {
+  // To suppress missing implicit constructor warnings.
+  factory CssNamespaceRule._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  @JSName('namespaceURI')
+  final String namespaceUri;
+
+  final String prefix;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("CSSNumericValue")
+class CssNumericValue extends CssStyleValue {
+  // To suppress missing implicit constructor warnings.
+  factory CssNumericValue._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  CssNumericValue add(CssNumericValue value) native;
+
+  CssNumericValue div(num value) native;
+
+  CssNumericValue mul(num value) native;
+
+  static CssNumericValue parse(String cssText) native;
+
+  CssNumericValue sub(CssNumericValue value) native;
+
+  CssNumericValue to(String unit) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("CSSPageRule")
+class CssPageRule extends CssRule {
+  // To suppress missing implicit constructor warnings.
+  factory CssPageRule._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  String selectorText;
+
+  final CssStyleDeclaration style;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("CSSPerspective")
+class CssPerspective extends CssTransformComponent {
+  // To suppress missing implicit constructor warnings.
+  factory CssPerspective._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory CssPerspective(CssNumericValue length) {
+    return CssPerspective._create_1(length);
+  }
+  static CssPerspective _create_1(length) =>
+      JS('CssPerspective', 'new CSSPerspective(#)', length);
+
+  CssNumericValue length;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("CSSPositionValue")
+class CssPositionValue extends CssStyleValue {
+  // To suppress missing implicit constructor warnings.
+  factory CssPositionValue._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory CssPositionValue(CssNumericValue x, CssNumericValue y) {
+    return CssPositionValue._create_1(x, y);
+  }
+  static CssPositionValue _create_1(x, y) =>
+      JS('CssPositionValue', 'new CSSPositionValue(#,#)', x, y);
+
+  CssNumericValue x;
+
+  CssNumericValue y;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("CSSResourceValue")
+class CssResourceValue extends CssStyleValue {
+  // To suppress missing implicit constructor warnings.
+  factory CssResourceValue._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final String state;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("CSSRotation")
+class CssRotation extends CssTransformComponent {
+  // To suppress missing implicit constructor warnings.
+  factory CssRotation._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory CssRotation(angleValue_OR_x, [num y, num z, CssNumericValue angle]) {
+    if ((angleValue_OR_x is CssNumericValue) &&
+        y == null &&
+        z == null &&
+        angle == null) {
+      return CssRotation._create_1(angleValue_OR_x);
+    }
+    if ((angle is CssNumericValue) &&
+        (z is num) &&
+        (y is num) &&
+        (angleValue_OR_x is num)) {
+      return CssRotation._create_2(angleValue_OR_x, y, z, angle);
+    }
+    throw new ArgumentError("Incorrect number or type of arguments");
+  }
+  static CssRotation _create_1(angleValue_OR_x) =>
+      JS('CssRotation', 'new CSSRotation(#)', angleValue_OR_x);
+  static CssRotation _create_2(angleValue_OR_x, y, z, angle) => JS(
+      'CssRotation', 'new CSSRotation(#,#,#,#)', angleValue_OR_x, y, z, angle);
+
+  CssNumericValue angle;
+
+  num x;
+
+  num y;
+
+  num z;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("CSSRule")
+class CssRule extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory CssRule._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  static const int CHARSET_RULE = 2;
+
+  static const int FONT_FACE_RULE = 5;
+
+  static const int IMPORT_RULE = 3;
+
+  static const int KEYFRAMES_RULE = 7;
+
+  static const int KEYFRAME_RULE = 8;
+
+  static const int MEDIA_RULE = 4;
+
+  static const int NAMESPACE_RULE = 10;
+
+  static const int PAGE_RULE = 6;
+
+  static const int STYLE_RULE = 1;
+
+  static const int SUPPORTS_RULE = 12;
+
+  static const int VIEWPORT_RULE = 15;
+
+  String cssText;
+
+  final CssRule parentRule;
+
+  final CssStyleSheet parentStyleSheet;
+
+  final int type;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("CSSScale")
+class CssScale extends CssTransformComponent {
+  // To suppress missing implicit constructor warnings.
+  factory CssScale._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory CssScale(num x, num y, [num z]) {
+    if ((y is num) && (x is num) && z == null) {
+      return CssScale._create_1(x, y);
+    }
+    if ((z is num) && (y is num) && (x is num)) {
+      return CssScale._create_2(x, y, z);
+    }
+    throw new ArgumentError("Incorrect number or type of arguments");
+  }
+  static CssScale _create_1(x, y) => JS('CssScale', 'new CSSScale(#,#)', x, y);
+  static CssScale _create_2(x, y, z) =>
+      JS('CssScale', 'new CSSScale(#,#,#)', x, y, z);
+
+  num x;
+
+  num y;
+
+  num z;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("CSSSkew")
+class CssSkew extends CssTransformComponent {
+  // To suppress missing implicit constructor warnings.
+  factory CssSkew._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory CssSkew(CssNumericValue ax, CssNumericValue ay) {
+    return CssSkew._create_1(ax, ay);
+  }
+  static CssSkew _create_1(ax, ay) => JS('CssSkew', 'new CSSSkew(#,#)', ax, ay);
+
+  CssNumericValue ax;
+
+  CssNumericValue ay;
+}
+
+// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: DO NOT EDIT THIS TEMPLATE FILE.
+// The template file was generated by scripts/css_code_generator.py
+
+// Source of CSS properties:
+//   CSSPropertyNames.in
+
+@Native("CSSStyleDeclaration,MSStyleCSSProperties,CSS2Properties")
+class CssStyleDeclaration extends Interceptor with CssStyleDeclarationBase {
+  factory CssStyleDeclaration() => new CssStyleDeclaration.css('');
+
+  factory CssStyleDeclaration.css(String css) {
+    final style = new DivElement().style;
+    style.cssText = css;
+    return style;
+  }
+
+  /// Returns the value of the property if the provided *CSS* property
+  /// name is supported on this element and if the value is set. Otherwise
+  /// returns an empty string.
+  ///
+  /// Please note the property name uses camelCase, not-hyphens.
+  String getPropertyValue(String propertyName) {
+    var propValue = _getPropertyValueHelper(propertyName);
+    return propValue ?? '';
+  }
+
+  String _getPropertyValueHelper(String propertyName) {
+    return _getPropertyValue(_browserPropertyName(propertyName));
+  }
+
+  /**
+   * Returns true if the provided *CSS* property name is supported on this
+   * element.
+   *
+   * Please note the property name camelCase, not-hyphens. This
+   * method returns true if the property is accessible via an unprefixed _or_
+   * prefixed property.
+   */
+  bool supportsProperty(String propertyName) {
+    return _supportsProperty(propertyName) ||
+        _supportsProperty(_camelCase("${Device.cssPrefix}$propertyName"));
+  }
+
+  bool _supportsProperty(String propertyName) {
+    return JS('bool', '# in #', propertyName, this);
+  }
+
+  void setProperty(String propertyName, String value, [String priority]) {
+    return _setPropertyHelper(
+        _browserPropertyName(propertyName), value, priority);
+  }
+
+  String _browserPropertyName(String propertyName) {
+    String name = _readCache(propertyName);
+    if (name is String) return name;
+    name = _supportedBrowserPropertyName(propertyName);
+    _writeCache(propertyName, name);
+    return name;
+  }
+
+  String _supportedBrowserPropertyName(String propertyName) {
+    if (_supportsProperty(_camelCase(propertyName))) {
+      return propertyName;
+    }
+    var prefixed = "${Device.cssPrefix}$propertyName";
+    if (_supportsProperty(prefixed)) {
+      return prefixed;
+    }
+    // May be a CSS variable, just use it as provided.
+    return propertyName;
+  }
+
+  static final _propertyCache = JS('', '{}');
+  static String _readCache(String key) =>
+      JS('String|Null', '#[#]', _propertyCache, key);
+  static void _writeCache(String key, String value) {
+    JS('void', '#[#] = #', _propertyCache, key, value);
+  }
+
+  static String _camelCase(String hyphenated) {
+    var replacedMs = JS('String', r'#.replace(/^-ms-/, "ms-")', hyphenated);
+    return JS(
+        'String',
+        r'#.replace(/-([\da-z])/ig,'
+            r'function(_, letter) { return letter.toUpperCase();})',
+        replacedMs);
+  }
+
+  void _setPropertyHelper(String propertyName, String value,
+      [String priority]) {
+    if (value == null) value = '';
+    if (priority == null) priority = '';
+    JS('void', '#.setProperty(#, #, #)', this, propertyName, value, priority);
+  }
+
+  /**
+   * Checks to see if CSS Transitions are supported.
+   */
+  static bool get supportsTransitions {
+    return document.body.style.supportsProperty('transition');
+  }
+
+  // To suppress missing implicit constructor warnings.
+  factory CssStyleDeclaration._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  String cssFloat;
+
+  String cssText;
+
+  final int length;
+
+  final CssRule parentRule;
+
+  String getPropertyPriority(String property) native;
+
+  @JSName('getPropertyValue')
+  String _getPropertyValue(String property) native;
+
+  String item(int index) native;
+
+  String removeProperty(String property) native;
+
+  /** Gets the value of "background" */
+  String get background => this._background;
+
+  /** Sets the value of "background" */
+  set background(String value) {
+    _background = value == null ? '' : value;
+  }
+
+  @Returns('String')
+  @JSName('background')
+  String _background;
+
+  /** Gets the value of "background-attachment" */
+  String get backgroundAttachment => this._backgroundAttachment;
+
+  /** Sets the value of "background-attachment" */
+  set backgroundAttachment(String value) {
+    _backgroundAttachment = value == null ? '' : value;
+  }
+
+  @Returns('String')
+  @JSName('backgroundAttachment')
+  String _backgroundAttachment;
+
+  /** Gets the value of "background-color" */
+  String get backgroundColor => this._backgroundColor;
+
+  /** Sets the value of "background-color" */
+  set backgroundColor(String value) {
+    _backgroundColor = value == null ? '' : value;
+  }
+
+  @Returns('String')
+  @JSName('backgroundColor')
+  String _backgroundColor;
+
+  /** Gets the value of "background-image" */
+  String get backgroundImage => this._backgroundImage;
+
+  /** Sets the value of "background-image" */
+  set backgroundImage(String value) {
+    _backgroundImage = value == null ? '' : value;
+  }
+
+  @Returns('String')
+  @JSName('backgroundImage')
+  String _backgroundImage;
+
+  /** Gets the value of "background-position" */
+  String get backgroundPosition => this._backgroundPosition;
+
+  /** Sets the value of "background-position" */
+  set backgroundPosition(String value) {
+    _backgroundPosition = value == null ? '' : value;
+  }
+
+  @Returns('String')
+  @JSName('backgroundPosition')
+  String _backgroundPosition;
+
+  /** Gets the value of "background-repeat" */
+  String get backgroundRepeat => this._backgroundRepeat;
+
+  /** Sets the value of "background-repeat" */
+  set backgroundRepeat(String value) {
+    _backgroundRepeat = value == null ? '' : value;
+  }
+
+  @Returns('String')
+  @JSName('backgroundRepeat')
+  String _backgroundRepeat;
+
+  /** Gets the value of "border" */
+  String get border => this._border;
+
+  /** Sets the value of "border" */
+  set border(String value) {
+    _border = value == null ? '' : value;
+  }
+
+  @Returns('String')
+  @JSName('border')
+  String _border;
+
+  /** Gets the value of "border-bottom" */
+  String get borderBottom => this._borderBottom;
+
+  /** Sets the value of "border-bottom" */
+  set borderBottom(String value) {
+    _borderBottom = value == null ? '' : value;
+  }
+
+  @Returns('String')
+  @JSName('borderBottom')
+  String _borderBottom;
+
+  /** Gets the value of "border-bottom-color" */
+  String get borderBottomColor => this._borderBottomColor;
+
+  /** Sets the value of "border-bottom-color" */
+  set borderBottomColor(String value) {
+    _borderBottomColor = value == null ? '' : value;
+  }
+
+  @Returns('String')
+  @JSName('borderBottomColor')
+  String _borderBottomColor;
+
+  /** Gets the value of "border-bottom-style" */
+  String get borderBottomStyle => this._borderBottomStyle;
+
+  /** Sets the value of "border-bottom-style" */
+  set borderBottomStyle(String value) {
+    _borderBottomStyle = value == null ? '' : value;
+  }
+
+  @Returns('String')
+  @JSName('borderBottomStyle')
+  String _borderBottomStyle;
+
+  /** Gets the value of "border-bottom-width" */
+  String get borderBottomWidth => this._borderBottomWidth;
+
+  /** Sets the value of "border-bottom-width" */
+  set borderBottomWidth(String value) {
+    _borderBottomWidth = value == null ? '' : value;
+  }
+
+  @Returns('String')
+  @JSName('borderBottomWidth')
+  String _borderBottomWidth;
+
+  /** Gets the value of "border-collapse" */
+  String get borderCollapse => this._borderCollapse;
+
+  /** Sets the value of "border-collapse" */
+  set borderCollapse(String value) {
+    _borderCollapse = value == null ? '' : value;
+  }
+
+  @Returns('String')
+  @JSName('borderCollapse')
+  String _borderCollapse;
+
+  /** Gets the value of "border-color" */
+  String get borderColor => this._borderColor;
+
+  /** Sets the value of "border-color" */
+  set borderColor(String value) {
+    _borderColor = value == null ? '' : value;
+  }
+
+  @Returns('String')
+  @JSName('borderColor')
+  String _borderColor;
+
+  /** Gets the value of "border-left" */
+  String get borderLeft => this._borderLeft;
+
+  /** Sets the value of "border-left" */
+  set borderLeft(String value) {
+    _borderLeft = value == null ? '' : value;
+  }
+
+  @Returns('String')
+  @JSName('borderLeft')
+  String _borderLeft;
+
+  /** Gets the value of "border-left-color" */
+  String get borderLeftColor => this._borderLeftColor;
+
+  /** Sets the value of "border-left-color" */
+  set borderLeftColor(String value) {
+    _borderLeftColor = value == null ? '' : value;
+  }
+
+  @Returns('String')
+  @JSName('borderLeftColor')
+  String _borderLeftColor;
+
+  /** Gets the value of "border-left-style" */
+  String get borderLeftStyle => this._borderLeftStyle;
+
+  /** Sets the value of "border-left-style" */
+  set borderLeftStyle(String value) {
+    _borderLeftStyle = value == null ? '' : value;
+  }
+
+  @Returns('String')
+  @JSName('borderLeftStyle')
+  String _borderLeftStyle;
+
+  /** Gets the value of "border-left-width" */
+  String get borderLeftWidth => this._borderLeftWidth;
+
+  /** Sets the value of "border-left-width" */
+  set borderLeftWidth(String value) {
+    _borderLeftWidth = value == null ? '' : value;
+  }
+
+  @Returns('String')
+  @JSName('borderLeftWidth')
+  String _borderLeftWidth;
+
+  /** Gets the value of "border-right" */
+  String get borderRight => this._borderRight;
+
+  /** Sets the value of "border-right" */
+  set borderRight(String value) {
+    _borderRight = value == null ? '' : value;
+  }
+
+  @Returns('String')
+  @JSName('borderRight')
+  String _borderRight;
+
+  /** Gets the value of "border-right-color" */
+  String get borderRightColor => this._borderRightColor;
+
+  /** Sets the value of "border-right-color" */
+  set borderRightColor(String value) {
+    _borderRightColor = value == null ? '' : value;
+  }
+
+  @Returns('String')
+  @JSName('borderRightColor')
+  String _borderRightColor;
+
+  /** Gets the value of "border-right-style" */
+  String get borderRightStyle => this._borderRightStyle;
+
+  /** Sets the value of "border-right-style" */
+  set borderRightStyle(String value) {
+    _borderRightStyle = value == null ? '' : value;
+  }
+
+  @Returns('String')
+  @JSName('borderRightStyle')
+  String _borderRightStyle;
+
+  /** Gets the value of "border-right-width" */
+  String get borderRightWidth => this._borderRightWidth;
+
+  /** Sets the value of "border-right-width" */
+  set borderRightWidth(String value) {
+    _borderRightWidth = value == null ? '' : value;
+  }
+
+  @Returns('String')
+  @JSName('borderRightWidth')
+  String _borderRightWidth;
+
+  /** Gets the value of "border-spacing" */
+  String get borderSpacing => this._borderSpacing;
+
+  /** Sets the value of "border-spacing" */
+  set borderSpacing(String value) {
+    _borderSpacing = value == null ? '' : value;
+  }
+
+  @Returns('String')
+  @JSName('borderSpacing')
+  String _borderSpacing;
+
+  /** Gets the value of "border-style" */
+  String get borderStyle => this._borderStyle;
+
+  /** Sets the value of "border-style" */
+  set borderStyle(String value) {
+    _borderStyle = value == null ? '' : value;
+  }
+
+  @Returns('String')
+  @JSName('borderStyle')
+  String _borderStyle;
+
+  /** Gets the value of "border-top" */
+  String get borderTop => this._borderTop;
+
+  /** Sets the value of "border-top" */
+  set borderTop(String value) {
+    _borderTop = value == null ? '' : value;
+  }
+
+  @Returns('String')
+  @JSName('borderTop')
+  String _borderTop;
+
+  /** Gets the value of "border-top-color" */
+  String get borderTopColor => this._borderTopColor;
+
+  /** Sets the value of "border-top-color" */
+  set borderTopColor(String value) {
+    _borderTopColor = value == null ? '' : value;
+  }
+
+  @Returns('String')
+  @JSName('borderTopColor')
+  String _borderTopColor;
+
+  /** Gets the value of "border-top-style" */
+  String get borderTopStyle => this._borderTopStyle;
+
+  /** Sets the value of "border-top-style" */
+  set borderTopStyle(String value) {
+    _borderTopStyle = value == null ? '' : value;
+  }
+
+  @Returns('String')
+  @JSName('borderTopStyle')
+  String _borderTopStyle;
+
+  /** Gets the value of "border-top-width" */
+  String get borderTopWidth => this._borderTopWidth;
+
+  /** Sets the value of "border-top-width" */
+  set borderTopWidth(String value) {
+    _borderTopWidth = value == null ? '' : value;
+  }
+
+  @Returns('String')
+  @JSName('borderTopWidth')
+  String _borderTopWidth;
+
+  /** Gets the value of "border-width" */
+  String get borderWidth => this._borderWidth;
+
+  /** Sets the value of "border-width" */
+  set borderWidth(String value) {
+    _borderWidth = value == null ? '' : value;
+  }
+
+  @Returns('String')
+  @JSName('borderWidth')
+  String _borderWidth;
+
+  /** Gets the value of "bottom" */
+  String get bottom => this._bottom;
+
+  /** Sets the value of "bottom" */
+  set bottom(String value) {
+    _bottom = value == null ? '' : value;
+  }
+
+  @Returns('String')
+  @JSName('bottom')
+  String _bottom;
+
+  /** Gets the value of "caption-side" */
+  String get captionSide => this._captionSide;
+
+  /** Sets the value of "caption-side" */
+  set captionSide(String value) {
+    _captionSide = value == null ? '' : value;
+  }
+
+  @Returns('String')
+  @JSName('captionSide')
+  String _captionSide;
+
+  /** Gets the value of "clear" */
+  String get clear => this._clear;
+
+  /** Sets the value of "clear" */
+  set clear(String value) {
+    _clear = value == null ? '' : value;
+  }
+
+  @Returns('String')
+  @JSName('clear')
+  String _clear;
+
+  /** Gets the value of "clip" */
+  String get clip => this._clip;
+
+  /** Sets the value of "clip" */
+  set clip(String value) {
+    _clip = value == null ? '' : value;
+  }
+
+  @Returns('String')
+  @JSName('clip')
+  String _clip;
+
+  /** Gets the value of "color" */
+  String get color => this._color;
+
+  /** Sets the value of "color" */
+  set color(String value) {
+    _color = value == null ? '' : value;
+  }
+
+  @Returns('String')
+  @JSName('color')
+  String _color;
+
+  /** Gets the value of "content" */
+  String get content => this._content;
+
+  /** Sets the value of "content" */
+  set content(String value) {
+    _content = value == null ? '' : value;
+  }
+
+  @Returns('String')
+  @JSName('content')
+  String _content;
+
+  /** Gets the value of "cursor" */
+  String get cursor => this._cursor;
+
+  /** Sets the value of "cursor" */
+  set cursor(String value) {
+    _cursor = value == null ? '' : value;
+  }
+
+  @Returns('String')
+  @JSName('cursor')
+  String _cursor;
+
+  /** Gets the value of "direction" */
+  String get direction => this._direction;
+
+  /** Sets the value of "direction" */
+  set direction(String value) {
+    _direction = value == null ? '' : value;
+  }
+
+  @Returns('String')
+  @JSName('direction')
+  String _direction;
+
+  /** Gets the value of "display" */
+  String get display => this._display;
+
+  /** Sets the value of "display" */
+  set display(String value) {
+    _display = value == null ? '' : value;
+  }
+
+  @Returns('String')
+  @JSName('display')
+  String _display;
+
+  /** Gets the value of "empty-cells" */
+  String get emptyCells => this._emptyCells;
+
+  /** Sets the value of "empty-cells" */
+  set emptyCells(String value) {
+    _emptyCells = value == null ? '' : value;
+  }
+
+  @Returns('String')
+  @JSName('emptyCells')
+  String _emptyCells;
+
+  /** Gets the value of "font" */
+  String get font => this._font;
+
+  /** Sets the value of "font" */
+  set font(String value) {
+    _font = value == null ? '' : value;
+  }
+
+  @Returns('String')
+  @JSName('font')
+  String _font;
+
+  /** Gets the value of "font-family" */
+  String get fontFamily => this._fontFamily;
+
+  /** Sets the value of "font-family" */
+  set fontFamily(String value) {
+    _fontFamily = value == null ? '' : value;
+  }
+
+  @Returns('String')
+  @JSName('fontFamily')
+  String _fontFamily;
+
+  /** Gets the value of "font-size" */
+  String get fontSize => this._fontSize;
+
+  /** Sets the value of "font-size" */
+  set fontSize(String value) {
+    _fontSize = value == null ? '' : value;
+  }
+
+  @Returns('String')
+  @JSName('fontSize')
+  String _fontSize;
+
+  /** Gets the value of "font-style" */
+  String get fontStyle => this._fontStyle;
+
+  /** Sets the value of "font-style" */
+  set fontStyle(String value) {
+    _fontStyle = value == null ? '' : value;
+  }
+
+  @Returns('String')
+  @JSName('fontStyle')
+  String _fontStyle;
+
+  /** Gets the value of "font-variant" */
+  String get fontVariant => this._fontVariant;
+
+  /** Sets the value of "font-variant" */
+  set fontVariant(String value) {
+    _fontVariant = value == null ? '' : value;
+  }
+
+  @Returns('String')
+  @JSName('fontVariant')
+  String _fontVariant;
+
+  /** Gets the value of "font-weight" */
+  String get fontWeight => this._fontWeight;
+
+  /** Sets the value of "font-weight" */
+  set fontWeight(String value) {
+    _fontWeight = value == null ? '' : value;
+  }
+
+  @Returns('String')
+  @JSName('fontWeight')
+  String _fontWeight;
+
+  /** Gets the value of "height" */
+  String get height => this._height;
+
+  /** Sets the value of "height" */
+  set height(String value) {
+    _height = value == null ? '' : value;
+  }
+
+  @Returns('String')
+  @JSName('height')
+  String _height;
+
+  /** Gets the value of "left" */
+  String get left => this._left;
+
+  /** Sets the value of "left" */
+  set left(String value) {
+    _left = value == null ? '' : value;
+  }
+
+  @Returns('String')
+  @JSName('left')
+  String _left;
+
+  /** Gets the value of "letter-spacing" */
+  String get letterSpacing => this._letterSpacing;
+
+  /** Sets the value of "letter-spacing" */
+  set letterSpacing(String value) {
+    _letterSpacing = value == null ? '' : value;
+  }
+
+  @Returns('String')
+  @JSName('letterSpacing')
+  String _letterSpacing;
+
+  /** Gets the value of "line-height" */
+  String get lineHeight => this._lineHeight;
+
+  /** Sets the value of "line-height" */
+  set lineHeight(String value) {
+    _lineHeight = value == null ? '' : value;
+  }
+
+  @Returns('String')
+  @JSName('lineHeight')
+  String _lineHeight;
+
+  /** Gets the value of "list-style" */
+  String get listStyle => this._listStyle;
+
+  /** Sets the value of "list-style" */
+  set listStyle(String value) {
+    _listStyle = value == null ? '' : value;
+  }
+
+  @Returns('String')
+  @JSName('listStyle')
+  String _listStyle;
+
+  /** Gets the value of "list-style-image" */
+  String get listStyleImage => this._listStyleImage;
+
+  /** Sets the value of "list-style-image" */
+  set listStyleImage(String value) {
+    _listStyleImage = value == null ? '' : value;
+  }
+
+  @Returns('String')
+  @JSName('listStyleImage')
+  String _listStyleImage;
+
+  /** Gets the value of "list-style-position" */
+  String get listStylePosition => this._listStylePosition;
+
+  /** Sets the value of "list-style-position" */
+  set listStylePosition(String value) {
+    _listStylePosition = value == null ? '' : value;
+  }
+
+  @Returns('String')
+  @JSName('listStylePosition')
+  String _listStylePosition;
+
+  /** Gets the value of "list-style-type" */
+  String get listStyleType => this._listStyleType;
+
+  /** Sets the value of "list-style-type" */
+  set listStyleType(String value) {
+    _listStyleType = value == null ? '' : value;
+  }
+
+  @Returns('String')
+  @JSName('listStyleType')
+  String _listStyleType;
+
+  /** Gets the value of "margin" */
+  String get margin => this._margin;
+
+  /** Sets the value of "margin" */
+  set margin(String value) {
+    _margin = value == null ? '' : value;
+  }
+
+  @Returns('String')
+  @JSName('margin')
+  String _margin;
+
+  /** Gets the value of "margin-bottom" */
+  String get marginBottom => this._marginBottom;
+
+  /** Sets the value of "margin-bottom" */
+  set marginBottom(String value) {
+    _marginBottom = value == null ? '' : value;
+  }
+
+  @Returns('String')
+  @JSName('marginBottom')
+  String _marginBottom;
+
+  /** Gets the value of "margin-left" */
+  String get marginLeft => this._marginLeft;
+
+  /** Sets the value of "margin-left" */
+  set marginLeft(String value) {
+    _marginLeft = value == null ? '' : value;
+  }
+
+  @Returns('String')
+  @JSName('marginLeft')
+  String _marginLeft;
+
+  /** Gets the value of "margin-right" */
+  String get marginRight => this._marginRight;
+
+  /** Sets the value of "margin-right" */
+  set marginRight(String value) {
+    _marginRight = value == null ? '' : value;
+  }
+
+  @Returns('String')
+  @JSName('marginRight')
+  String _marginRight;
+
+  /** Gets the value of "margin-top" */
+  String get marginTop => this._marginTop;
+
+  /** Sets the value of "margin-top" */
+  set marginTop(String value) {
+    _marginTop = value == null ? '' : value;
+  }
+
+  @Returns('String')
+  @JSName('marginTop')
+  String _marginTop;
+
+  /** Gets the value of "max-height" */
+  String get maxHeight => this._maxHeight;
+
+  /** Sets the value of "max-height" */
+  set maxHeight(String value) {
+    _maxHeight = value == null ? '' : value;
+  }
+
+  @Returns('String')
+  @JSName('maxHeight')
+  String _maxHeight;
+
+  /** Gets the value of "max-width" */
+  String get maxWidth => this._maxWidth;
+
+  /** Sets the value of "max-width" */
+  set maxWidth(String value) {
+    _maxWidth = value == null ? '' : value;
+  }
+
+  @Returns('String')
+  @JSName('maxWidth')
+  String _maxWidth;
+
+  /** Gets the value of "min-height" */
+  String get minHeight => this._minHeight;
+
+  /** Sets the value of "min-height" */
+  set minHeight(String value) {
+    _minHeight = value == null ? '' : value;
+  }
+
+  @Returns('String')
+  @JSName('minHeight')
+  String _minHeight;
+
+  /** Gets the value of "min-width" */
+  String get minWidth => this._minWidth;
+
+  /** Sets the value of "min-width" */
+  set minWidth(String value) {
+    _minWidth = value == null ? '' : value;
+  }
+
+  @Returns('String')
+  @JSName('minWidth')
+  String _minWidth;
+
+  /** Gets the value of "outline" */
+  String get outline => this._outline;
+
+  /** Sets the value of "outline" */
+  set outline(String value) {
+    _outline = value == null ? '' : value;
+  }
+
+  @Returns('String')
+  @JSName('outline')
+  String _outline;
+
+  /** Gets the value of "outline-color" */
+  String get outlineColor => this._outlineColor;
+
+  /** Sets the value of "outline-color" */
+  set outlineColor(String value) {
+    _outlineColor = value == null ? '' : value;
+  }
+
+  @Returns('String')
+  @JSName('outlineColor')
+  String _outlineColor;
+
+  /** Gets the value of "outline-style" */
+  String get outlineStyle => this._outlineStyle;
+
+  /** Sets the value of "outline-style" */
+  set outlineStyle(String value) {
+    _outlineStyle = value == null ? '' : value;
+  }
+
+  @Returns('String')
+  @JSName('outlineStyle')
+  String _outlineStyle;
+
+  /** Gets the value of "outline-width" */
+  String get outlineWidth => this._outlineWidth;
+
+  /** Sets the value of "outline-width" */
+  set outlineWidth(String value) {
+    _outlineWidth = value == null ? '' : value;
+  }
+
+  @Returns('String')
+  @JSName('outlineWidth')
+  String _outlineWidth;
+
+  /** Gets the value of "overflow" */
+  String get overflow => this._overflow;
+
+  /** Sets the value of "overflow" */
+  set overflow(String value) {
+    _overflow = value == null ? '' : value;
+  }
+
+  @Returns('String')
+  @JSName('overflow')
+  String _overflow;
+
+  /** Gets the value of "padding" */
+  String get padding => this._padding;
+
+  /** Sets the value of "padding" */
+  set padding(String value) {
+    _padding = value == null ? '' : value;
+  }
+
+  @Returns('String')
+  @JSName('padding')
+  String _padding;
+
+  /** Gets the value of "padding-bottom" */
+  String get paddingBottom => this._paddingBottom;
+
+  /** Sets the value of "padding-bottom" */
+  set paddingBottom(String value) {
+    _paddingBottom = value == null ? '' : value;
+  }
+
+  @Returns('String')
+  @JSName('paddingBottom')
+  String _paddingBottom;
+
+  /** Gets the value of "padding-left" */
+  String get paddingLeft => this._paddingLeft;
+
+  /** Sets the value of "padding-left" */
+  set paddingLeft(String value) {
+    _paddingLeft = value == null ? '' : value;
+  }
+
+  @Returns('String')
+  @JSName('paddingLeft')
+  String _paddingLeft;
+
+  /** Gets the value of "padding-right" */
+  String get paddingRight => this._paddingRight;
+
+  /** Sets the value of "padding-right" */
+  set paddingRight(String value) {
+    _paddingRight = value == null ? '' : value;
+  }
+
+  @Returns('String')
+  @JSName('paddingRight')
+  String _paddingRight;
+
+  /** Gets the value of "padding-top" */
+  String get paddingTop => this._paddingTop;
+
+  /** Sets the value of "padding-top" */
+  set paddingTop(String value) {
+    _paddingTop = value == null ? '' : value;
+  }
+
+  @Returns('String')
+  @JSName('paddingTop')
+  String _paddingTop;
+
+  /** Gets the value of "page-break-after" */
+  String get pageBreakAfter => this._pageBreakAfter;
+
+  /** Sets the value of "page-break-after" */
+  set pageBreakAfter(String value) {
+    _pageBreakAfter = value == null ? '' : value;
+  }
+
+  @Returns('String')
+  @JSName('pageBreakAfter')
+  String _pageBreakAfter;
+
+  /** Gets the value of "page-break-before" */
+  String get pageBreakBefore => this._pageBreakBefore;
+
+  /** Sets the value of "page-break-before" */
+  set pageBreakBefore(String value) {
+    _pageBreakBefore = value == null ? '' : value;
+  }
+
+  @Returns('String')
+  @JSName('pageBreakBefore')
+  String _pageBreakBefore;
+
+  /** Gets the value of "page-break-inside" */
+  String get pageBreakInside => this._pageBreakInside;
+
+  /** Sets the value of "page-break-inside" */
+  set pageBreakInside(String value) {
+    _pageBreakInside = value == null ? '' : value;
+  }
+
+  @Returns('String')
+  @JSName('pageBreakInside')
+  String _pageBreakInside;
+
+  /** Gets the value of "position" */
+  String get position => this._position;
+
+  /** Sets the value of "position" */
+  set position(String value) {
+    _position = value == null ? '' : value;
+  }
+
+  @Returns('String')
+  @JSName('position')
+  String _position;
+
+  /** Gets the value of "quotes" */
+  String get quotes => this._quotes;
+
+  /** Sets the value of "quotes" */
+  set quotes(String value) {
+    _quotes = value == null ? '' : value;
+  }
+
+  @Returns('String')
+  @JSName('quotes')
+  String _quotes;
+
+  /** Gets the value of "right" */
+  String get right => this._right;
+
+  /** Sets the value of "right" */
+  set right(String value) {
+    _right = value == null ? '' : value;
+  }
+
+  @Returns('String')
+  @JSName('right')
+  String _right;
+
+  /** Gets the value of "table-layout" */
+  String get tableLayout => this._tableLayout;
+
+  /** Sets the value of "table-layout" */
+  set tableLayout(String value) {
+    _tableLayout = value == null ? '' : value;
+  }
+
+  @Returns('String')
+  @JSName('tableLayout')
+  String _tableLayout;
+
+  /** Gets the value of "text-align" */
+  String get textAlign => this._textAlign;
+
+  /** Sets the value of "text-align" */
+  set textAlign(String value) {
+    _textAlign = value == null ? '' : value;
+  }
+
+  @Returns('String')
+  @JSName('textAlign')
+  String _textAlign;
+
+  /** Gets the value of "text-decoration" */
+  String get textDecoration => this._textDecoration;
+
+  /** Sets the value of "text-decoration" */
+  set textDecoration(String value) {
+    _textDecoration = value == null ? '' : value;
+  }
+
+  @Returns('String')
+  @JSName('textDecoration')
+  String _textDecoration;
+
+  /** Gets the value of "text-indent" */
+  String get textIndent => this._textIndent;
+
+  /** Sets the value of "text-indent" */
+  set textIndent(String value) {
+    _textIndent = value == null ? '' : value;
+  }
+
+  @Returns('String')
+  @JSName('textIndent')
+  String _textIndent;
+
+  /** Gets the value of "text-transform" */
+  String get textTransform => this._textTransform;
+
+  /** Sets the value of "text-transform" */
+  set textTransform(String value) {
+    _textTransform = value == null ? '' : value;
+  }
+
+  @Returns('String')
+  @JSName('textTransform')
+  String _textTransform;
+
+  /** Gets the value of "top" */
+  String get top => this._top;
+
+  /** Sets the value of "top" */
+  set top(String value) {
+    _top = value == null ? '' : value;
+  }
+
+  @Returns('String')
+  @JSName('top')
+  String _top;
+
+  /** Gets the value of "unicode-bidi" */
+  String get unicodeBidi => this._unicodeBidi;
+
+  /** Sets the value of "unicode-bidi" */
+  set unicodeBidi(String value) {
+    _unicodeBidi = value == null ? '' : value;
+  }
+
+  @Returns('String')
+  @JSName('unicodeBidi')
+  String _unicodeBidi;
+
+  /** Gets the value of "vertical-align" */
+  String get verticalAlign => this._verticalAlign;
+
+  /** Sets the value of "vertical-align" */
+  set verticalAlign(String value) {
+    _verticalAlign = value == null ? '' : value;
+  }
+
+  @Returns('String')
+  @JSName('verticalAlign')
+  String _verticalAlign;
+
+  /** Gets the value of "visibility" */
+  String get visibility => this._visibility;
+
+  /** Sets the value of "visibility" */
+  set visibility(String value) {
+    _visibility = value == null ? '' : value;
+  }
+
+  @Returns('String')
+  @JSName('visibility')
+  String _visibility;
+
+  /** Gets the value of "white-space" */
+  String get whiteSpace => this._whiteSpace;
+
+  /** Sets the value of "white-space" */
+  set whiteSpace(String value) {
+    _whiteSpace = value == null ? '' : value;
+  }
+
+  @Returns('String')
+  @JSName('whiteSpace')
+  String _whiteSpace;
+
+  /** Gets the value of "width" */
+  String get width => this._width;
+
+  /** Sets the value of "width" */
+  set width(String value) {
+    _width = value == null ? '' : value;
+  }
+
+  @Returns('String')
+  @JSName('width')
+  String _width;
+
+  /** Gets the value of "word-spacing" */
+  String get wordSpacing => this._wordSpacing;
+
+  /** Sets the value of "word-spacing" */
+  set wordSpacing(String value) {
+    _wordSpacing = value == null ? '' : value;
+  }
+
+  @Returns('String')
+  @JSName('wordSpacing')
+  String _wordSpacing;
+
+  /** Gets the value of "z-index" */
+  String get zIndex => this._zIndex;
+
+  /** Sets the value of "z-index" */
+  set zIndex(String value) {
+    _zIndex = value == null ? '' : value;
+  }
+
+  @Returns('String')
+  @JSName('zIndex')
+  String _zIndex;
+}
+
+class _CssStyleDeclarationSet extends Object with CssStyleDeclarationBase {
+  final Iterable<Element> _elementIterable;
+  Iterable<CssStyleDeclaration> _elementCssStyleDeclarationSetIterable;
+
+  _CssStyleDeclarationSet(this._elementIterable) {
+    _elementCssStyleDeclarationSetIterable =
+        new List.from(_elementIterable).map((e) => e.style);
+  }
+
+  String getPropertyValue(String propertyName) =>
+      _elementCssStyleDeclarationSetIterable.first
+          .getPropertyValue(propertyName);
+
+  void setProperty(String propertyName, String value, [String priority]) {
+    _elementCssStyleDeclarationSetIterable
+        .forEach((e) => e.setProperty(propertyName, value, priority));
+  }
+
+  void _setAll(String propertyName, String value) {
+    value = value == null ? '' : value;
+    for (Element element in _elementIterable) {
+      JS('void', '#.style[#] = #', element, propertyName, value);
+    }
+  }
+
+  /** Sets the value of "background" */
+  set background(String value) {
+    _setAll('background', value);
+  }
+
+  /** Sets the value of "background-attachment" */
+  set backgroundAttachment(String value) {
+    _setAll('backgroundAttachment', value);
+  }
+
+  /** Sets the value of "background-color" */
+  set backgroundColor(String value) {
+    _setAll('backgroundColor', value);
+  }
+
+  /** Sets the value of "background-image" */
+  set backgroundImage(String value) {
+    _setAll('backgroundImage', value);
+  }
+
+  /** Sets the value of "background-position" */
+  set backgroundPosition(String value) {
+    _setAll('backgroundPosition', value);
+  }
+
+  /** Sets the value of "background-repeat" */
+  set backgroundRepeat(String value) {
+    _setAll('backgroundRepeat', value);
+  }
+
+  /** Sets the value of "border" */
+  set border(String value) {
+    _setAll('border', value);
+  }
+
+  /** Sets the value of "border-bottom" */
+  set borderBottom(String value) {
+    _setAll('borderBottom', value);
+  }
+
+  /** Sets the value of "border-bottom-color" */
+  set borderBottomColor(String value) {
+    _setAll('borderBottomColor', value);
+  }
+
+  /** Sets the value of "border-bottom-style" */
+  set borderBottomStyle(String value) {
+    _setAll('borderBottomStyle', value);
+  }
+
+  /** Sets the value of "border-bottom-width" */
+  set borderBottomWidth(String value) {
+    _setAll('borderBottomWidth', value);
+  }
+
+  /** Sets the value of "border-collapse" */
+  set borderCollapse(String value) {
+    _setAll('borderCollapse', value);
+  }
+
+  /** Sets the value of "border-color" */
+  set borderColor(String value) {
+    _setAll('borderColor', value);
+  }
+
+  /** Sets the value of "border-left" */
+  set borderLeft(String value) {
+    _setAll('borderLeft', value);
+  }
+
+  /** Sets the value of "border-left-color" */
+  set borderLeftColor(String value) {
+    _setAll('borderLeftColor', value);
+  }
+
+  /** Sets the value of "border-left-style" */
+  set borderLeftStyle(String value) {
+    _setAll('borderLeftStyle', value);
+  }
+
+  /** Sets the value of "border-left-width" */
+  set borderLeftWidth(String value) {
+    _setAll('borderLeftWidth', value);
+  }
+
+  /** Sets the value of "border-right" */
+  set borderRight(String value) {
+    _setAll('borderRight', value);
+  }
+
+  /** Sets the value of "border-right-color" */
+  set borderRightColor(String value) {
+    _setAll('borderRightColor', value);
+  }
+
+  /** Sets the value of "border-right-style" */
+  set borderRightStyle(String value) {
+    _setAll('borderRightStyle', value);
+  }
+
+  /** Sets the value of "border-right-width" */
+  set borderRightWidth(String value) {
+    _setAll('borderRightWidth', value);
+  }
+
+  /** Sets the value of "border-spacing" */
+  set borderSpacing(String value) {
+    _setAll('borderSpacing', value);
+  }
+
+  /** Sets the value of "border-style" */
+  set borderStyle(String value) {
+    _setAll('borderStyle', value);
+  }
+
+  /** Sets the value of "border-top" */
+  set borderTop(String value) {
+    _setAll('borderTop', value);
+  }
+
+  /** Sets the value of "border-top-color" */
+  set borderTopColor(String value) {
+    _setAll('borderTopColor', value);
+  }
+
+  /** Sets the value of "border-top-style" */
+  set borderTopStyle(String value) {
+    _setAll('borderTopStyle', value);
+  }
+
+  /** Sets the value of "border-top-width" */
+  set borderTopWidth(String value) {
+    _setAll('borderTopWidth', value);
+  }
+
+  /** Sets the value of "border-width" */
+  set borderWidth(String value) {
+    _setAll('borderWidth', value);
+  }
+
+  /** Sets the value of "bottom" */
+  set bottom(String value) {
+    _setAll('bottom', value);
+  }
+
+  /** Sets the value of "caption-side" */
+  set captionSide(String value) {
+    _setAll('captionSide', value);
+  }
+
+  /** Sets the value of "clear" */
+  set clear(String value) {
+    _setAll('clear', value);
+  }
+
+  /** Sets the value of "clip" */
+  set clip(String value) {
+    _setAll('clip', value);
+  }
+
+  /** Sets the value of "color" */
+  set color(String value) {
+    _setAll('color', value);
+  }
+
+  /** Sets the value of "content" */
+  set content(String value) {
+    _setAll('content', value);
+  }
+
+  /** Sets the value of "cursor" */
+  set cursor(String value) {
+    _setAll('cursor', value);
+  }
+
+  /** Sets the value of "direction" */
+  set direction(String value) {
+    _setAll('direction', value);
+  }
+
+  /** Sets the value of "display" */
+  set display(String value) {
+    _setAll('display', value);
+  }
+
+  /** Sets the value of "empty-cells" */
+  set emptyCells(String value) {
+    _setAll('emptyCells', value);
+  }
+
+  /** Sets the value of "font" */
+  set font(String value) {
+    _setAll('font', value);
+  }
+
+  /** Sets the value of "font-family" */
+  set fontFamily(String value) {
+    _setAll('fontFamily', value);
+  }
+
+  /** Sets the value of "font-size" */
+  set fontSize(String value) {
+    _setAll('fontSize', value);
+  }
+
+  /** Sets the value of "font-style" */
+  set fontStyle(String value) {
+    _setAll('fontStyle', value);
+  }
+
+  /** Sets the value of "font-variant" */
+  set fontVariant(String value) {
+    _setAll('fontVariant', value);
+  }
+
+  /** Sets the value of "font-weight" */
+  set fontWeight(String value) {
+    _setAll('fontWeight', value);
+  }
+
+  /** Sets the value of "height" */
+  set height(String value) {
+    _setAll('height', value);
+  }
+
+  /** Sets the value of "left" */
+  set left(String value) {
+    _setAll('left', value);
+  }
+
+  /** Sets the value of "letter-spacing" */
+  set letterSpacing(String value) {
+    _setAll('letterSpacing', value);
+  }
+
+  /** Sets the value of "line-height" */
+  set lineHeight(String value) {
+    _setAll('lineHeight', value);
+  }
+
+  /** Sets the value of "list-style" */
+  set listStyle(String value) {
+    _setAll('listStyle', value);
+  }
+
+  /** Sets the value of "list-style-image" */
+  set listStyleImage(String value) {
+    _setAll('listStyleImage', value);
+  }
+
+  /** Sets the value of "list-style-position" */
+  set listStylePosition(String value) {
+    _setAll('listStylePosition', value);
+  }
+
+  /** Sets the value of "list-style-type" */
+  set listStyleType(String value) {
+    _setAll('listStyleType', value);
+  }
+
+  /** Sets the value of "margin" */
+  set margin(String value) {
+    _setAll('margin', value);
+  }
+
+  /** Sets the value of "margin-bottom" */
+  set marginBottom(String value) {
+    _setAll('marginBottom', value);
+  }
+
+  /** Sets the value of "margin-left" */
+  set marginLeft(String value) {
+    _setAll('marginLeft', value);
+  }
+
+  /** Sets the value of "margin-right" */
+  set marginRight(String value) {
+    _setAll('marginRight', value);
+  }
+
+  /** Sets the value of "margin-top" */
+  set marginTop(String value) {
+    _setAll('marginTop', value);
+  }
+
+  /** Sets the value of "max-height" */
+  set maxHeight(String value) {
+    _setAll('maxHeight', value);
+  }
+
+  /** Sets the value of "max-width" */
+  set maxWidth(String value) {
+    _setAll('maxWidth', value);
+  }
+
+  /** Sets the value of "min-height" */
+  set minHeight(String value) {
+    _setAll('minHeight', value);
+  }
+
+  /** Sets the value of "min-width" */
+  set minWidth(String value) {
+    _setAll('minWidth', value);
+  }
+
+  /** Sets the value of "outline" */
+  set outline(String value) {
+    _setAll('outline', value);
+  }
+
+  /** Sets the value of "outline-color" */
+  set outlineColor(String value) {
+    _setAll('outlineColor', value);
+  }
+
+  /** Sets the value of "outline-style" */
+  set outlineStyle(String value) {
+    _setAll('outlineStyle', value);
+  }
+
+  /** Sets the value of "outline-width" */
+  set outlineWidth(String value) {
+    _setAll('outlineWidth', value);
+  }
+
+  /** Sets the value of "overflow" */
+  set overflow(String value) {
+    _setAll('overflow', value);
+  }
+
+  /** Sets the value of "padding" */
+  set padding(String value) {
+    _setAll('padding', value);
+  }
+
+  /** Sets the value of "padding-bottom" */
+  set paddingBottom(String value) {
+    _setAll('paddingBottom', value);
+  }
+
+  /** Sets the value of "padding-left" */
+  set paddingLeft(String value) {
+    _setAll('paddingLeft', value);
+  }
+
+  /** Sets the value of "padding-right" */
+  set paddingRight(String value) {
+    _setAll('paddingRight', value);
+  }
+
+  /** Sets the value of "padding-top" */
+  set paddingTop(String value) {
+    _setAll('paddingTop', value);
+  }
+
+  /** Sets the value of "page-break-after" */
+  set pageBreakAfter(String value) {
+    _setAll('pageBreakAfter', value);
+  }
+
+  /** Sets the value of "page-break-before" */
+  set pageBreakBefore(String value) {
+    _setAll('pageBreakBefore', value);
+  }
+
+  /** Sets the value of "page-break-inside" */
+  set pageBreakInside(String value) {
+    _setAll('pageBreakInside', value);
+  }
+
+  /** Sets the value of "position" */
+  set position(String value) {
+    _setAll('position', value);
+  }
+
+  /** Sets the value of "quotes" */
+  set quotes(String value) {
+    _setAll('quotes', value);
+  }
+
+  /** Sets the value of "right" */
+  set right(String value) {
+    _setAll('right', value);
+  }
+
+  /** Sets the value of "table-layout" */
+  set tableLayout(String value) {
+    _setAll('tableLayout', value);
+  }
+
+  /** Sets the value of "text-align" */
+  set textAlign(String value) {
+    _setAll('textAlign', value);
+  }
+
+  /** Sets the value of "text-decoration" */
+  set textDecoration(String value) {
+    _setAll('textDecoration', value);
+  }
+
+  /** Sets the value of "text-indent" */
+  set textIndent(String value) {
+    _setAll('textIndent', value);
+  }
+
+  /** Sets the value of "text-transform" */
+  set textTransform(String value) {
+    _setAll('textTransform', value);
+  }
+
+  /** Sets the value of "top" */
+  set top(String value) {
+    _setAll('top', value);
+  }
+
+  /** Sets the value of "unicode-bidi" */
+  set unicodeBidi(String value) {
+    _setAll('unicodeBidi', value);
+  }
+
+  /** Sets the value of "vertical-align" */
+  set verticalAlign(String value) {
+    _setAll('verticalAlign', value);
+  }
+
+  /** Sets the value of "visibility" */
+  set visibility(String value) {
+    _setAll('visibility', value);
+  }
+
+  /** Sets the value of "white-space" */
+  set whiteSpace(String value) {
+    _setAll('whiteSpace', value);
+  }
+
+  /** Sets the value of "width" */
+  set width(String value) {
+    _setAll('width', value);
+  }
+
+  /** Sets the value of "word-spacing" */
+  set wordSpacing(String value) {
+    _setAll('wordSpacing', value);
+  }
+
+  /** Sets the value of "z-index" */
+  set zIndex(String value) {
+    _setAll('zIndex', value);
+  }
+
+  // Important note: CssStyleDeclarationSet does NOT implement every method
+  // available in CssStyleDeclaration. Some of the methods don't make so much
+  // sense in terms of having a resonable value to return when you're
+  // considering a list of Elements. You will need to manually add any of the
+  // items in the MEMBERS set if you want that functionality.
+}
+
+abstract class CssStyleDeclarationBase {
+  String getPropertyValue(String propertyName);
+  void setProperty(String propertyName, String value, [String priority]);
+
+  /** Gets the value of "align-content" */
+  String get alignContent => getPropertyValue('align-content');
+
+  /** Sets the value of "align-content" */
+  set alignContent(String value) {
+    setProperty('align-content', value, '');
+  }
+
+  /** Gets the value of "align-items" */
+  String get alignItems => getPropertyValue('align-items');
+
+  /** Sets the value of "align-items" */
+  set alignItems(String value) {
+    setProperty('align-items', value, '');
+  }
+
+  /** Gets the value of "align-self" */
+  String get alignSelf => getPropertyValue('align-self');
+
+  /** Sets the value of "align-self" */
+  set alignSelf(String value) {
+    setProperty('align-self', value, '');
+  }
+
+  /** Gets the value of "animation" */
+  String get animation => getPropertyValue('animation');
+
+  /** Sets the value of "animation" */
+  set animation(String value) {
+    setProperty('animation', value, '');
+  }
+
+  /** Gets the value of "animation-delay" */
+  String get animationDelay => getPropertyValue('animation-delay');
+
+  /** Sets the value of "animation-delay" */
+  set animationDelay(String value) {
+    setProperty('animation-delay', value, '');
+  }
+
+  /** Gets the value of "animation-direction" */
+  String get animationDirection => getPropertyValue('animation-direction');
+
+  /** Sets the value of "animation-direction" */
+  set animationDirection(String value) {
+    setProperty('animation-direction', value, '');
+  }
+
+  /** Gets the value of "animation-duration" */
+  String get animationDuration => getPropertyValue('animation-duration');
+
+  /** Sets the value of "animation-duration" */
+  set animationDuration(String value) {
+    setProperty('animation-duration', value, '');
+  }
+
+  /** Gets the value of "animation-fill-mode" */
+  String get animationFillMode => getPropertyValue('animation-fill-mode');
+
+  /** Sets the value of "animation-fill-mode" */
+  set animationFillMode(String value) {
+    setProperty('animation-fill-mode', value, '');
+  }
+
+  /** Gets the value of "animation-iteration-count" */
+  String get animationIterationCount =>
+      getPropertyValue('animation-iteration-count');
+
+  /** Sets the value of "animation-iteration-count" */
+  set animationIterationCount(String value) {
+    setProperty('animation-iteration-count', value, '');
+  }
+
+  /** Gets the value of "animation-name" */
+  String get animationName => getPropertyValue('animation-name');
+
+  /** Sets the value of "animation-name" */
+  set animationName(String value) {
+    setProperty('animation-name', value, '');
+  }
+
+  /** Gets the value of "animation-play-state" */
+  String get animationPlayState => getPropertyValue('animation-play-state');
+
+  /** Sets the value of "animation-play-state" */
+  set animationPlayState(String value) {
+    setProperty('animation-play-state', value, '');
+  }
+
+  /** Gets the value of "animation-timing-function" */
+  String get animationTimingFunction =>
+      getPropertyValue('animation-timing-function');
+
+  /** Sets the value of "animation-timing-function" */
+  set animationTimingFunction(String value) {
+    setProperty('animation-timing-function', value, '');
+  }
+
+  /** Gets the value of "app-region" */
+  String get appRegion => getPropertyValue('app-region');
+
+  /** Sets the value of "app-region" */
+  set appRegion(String value) {
+    setProperty('app-region', value, '');
+  }
+
+  /** Gets the value of "appearance" */
+  String get appearance => getPropertyValue('appearance');
+
+  /** Sets the value of "appearance" */
+  set appearance(String value) {
+    setProperty('appearance', value, '');
+  }
+
+  /** Gets the value of "aspect-ratio" */
+  String get aspectRatio => getPropertyValue('aspect-ratio');
+
+  /** Sets the value of "aspect-ratio" */
+  set aspectRatio(String value) {
+    setProperty('aspect-ratio', value, '');
+  }
+
+  /** Gets the value of "backface-visibility" */
+  String get backfaceVisibility => getPropertyValue('backface-visibility');
+
+  /** Sets the value of "backface-visibility" */
+  set backfaceVisibility(String value) {
+    setProperty('backface-visibility', value, '');
+  }
+
+  /** Gets the value of "background" */
+  String get background => getPropertyValue('background');
+
+  /** Sets the value of "background" */
+  set background(String value) {
+    setProperty('background', value, '');
+  }
+
+  /** Gets the value of "background-attachment" */
+  String get backgroundAttachment => getPropertyValue('background-attachment');
+
+  /** Sets the value of "background-attachment" */
+  set backgroundAttachment(String value) {
+    setProperty('background-attachment', value, '');
+  }
+
+  /** Gets the value of "background-blend-mode" */
+  String get backgroundBlendMode => getPropertyValue('background-blend-mode');
+
+  /** Sets the value of "background-blend-mode" */
+  set backgroundBlendMode(String value) {
+    setProperty('background-blend-mode', value, '');
+  }
+
+  /** Gets the value of "background-clip" */
+  String get backgroundClip => getPropertyValue('background-clip');
+
+  /** Sets the value of "background-clip" */
+  set backgroundClip(String value) {
+    setProperty('background-clip', value, '');
+  }
+
+  /** Gets the value of "background-color" */
+  String get backgroundColor => getPropertyValue('background-color');
+
+  /** Sets the value of "background-color" */
+  set backgroundColor(String value) {
+    setProperty('background-color', value, '');
+  }
+
+  /** Gets the value of "background-composite" */
+  String get backgroundComposite => getPropertyValue('background-composite');
+
+  /** Sets the value of "background-composite" */
+  set backgroundComposite(String value) {
+    setProperty('background-composite', value, '');
+  }
+
+  /** Gets the value of "background-image" */
+  String get backgroundImage => getPropertyValue('background-image');
+
+  /** Sets the value of "background-image" */
+  set backgroundImage(String value) {
+    setProperty('background-image', value, '');
+  }
+
+  /** Gets the value of "background-origin" */
+  String get backgroundOrigin => getPropertyValue('background-origin');
+
+  /** Sets the value of "background-origin" */
+  set backgroundOrigin(String value) {
+    setProperty('background-origin', value, '');
+  }
+
+  /** Gets the value of "background-position" */
+  String get backgroundPosition => getPropertyValue('background-position');
+
+  /** Sets the value of "background-position" */
+  set backgroundPosition(String value) {
+    setProperty('background-position', value, '');
+  }
+
+  /** Gets the value of "background-position-x" */
+  String get backgroundPositionX => getPropertyValue('background-position-x');
+
+  /** Sets the value of "background-position-x" */
+  set backgroundPositionX(String value) {
+    setProperty('background-position-x', value, '');
+  }
+
+  /** Gets the value of "background-position-y" */
+  String get backgroundPositionY => getPropertyValue('background-position-y');
+
+  /** Sets the value of "background-position-y" */
+  set backgroundPositionY(String value) {
+    setProperty('background-position-y', value, '');
+  }
+
+  /** Gets the value of "background-repeat" */
+  String get backgroundRepeat => getPropertyValue('background-repeat');
+
+  /** Sets the value of "background-repeat" */
+  set backgroundRepeat(String value) {
+    setProperty('background-repeat', value, '');
+  }
+
+  /** Gets the value of "background-repeat-x" */
+  String get backgroundRepeatX => getPropertyValue('background-repeat-x');
+
+  /** Sets the value of "background-repeat-x" */
+  set backgroundRepeatX(String value) {
+    setProperty('background-repeat-x', value, '');
+  }
+
+  /** Gets the value of "background-repeat-y" */
+  String get backgroundRepeatY => getPropertyValue('background-repeat-y');
+
+  /** Sets the value of "background-repeat-y" */
+  set backgroundRepeatY(String value) {
+    setProperty('background-repeat-y', value, '');
+  }
+
+  /** Gets the value of "background-size" */
+  String get backgroundSize => getPropertyValue('background-size');
+
+  /** Sets the value of "background-size" */
+  set backgroundSize(String value) {
+    setProperty('background-size', value, '');
+  }
+
+  /** Gets the value of "border" */
+  String get border => getPropertyValue('border');
+
+  /** Sets the value of "border" */
+  set border(String value) {
+    setProperty('border', value, '');
+  }
+
+  /** Gets the value of "border-after" */
+  String get borderAfter => getPropertyValue('border-after');
+
+  /** Sets the value of "border-after" */
+  set borderAfter(String value) {
+    setProperty('border-after', value, '');
+  }
+
+  /** Gets the value of "border-after-color" */
+  String get borderAfterColor => getPropertyValue('border-after-color');
+
+  /** Sets the value of "border-after-color" */
+  set borderAfterColor(String value) {
+    setProperty('border-after-color', value, '');
+  }
+
+  /** Gets the value of "border-after-style" */
+  String get borderAfterStyle => getPropertyValue('border-after-style');
+
+  /** Sets the value of "border-after-style" */
+  set borderAfterStyle(String value) {
+    setProperty('border-after-style', value, '');
+  }
+
+  /** Gets the value of "border-after-width" */
+  String get borderAfterWidth => getPropertyValue('border-after-width');
+
+  /** Sets the value of "border-after-width" */
+  set borderAfterWidth(String value) {
+    setProperty('border-after-width', value, '');
+  }
+
+  /** Gets the value of "border-before" */
+  String get borderBefore => getPropertyValue('border-before');
+
+  /** Sets the value of "border-before" */
+  set borderBefore(String value) {
+    setProperty('border-before', value, '');
+  }
+
+  /** Gets the value of "border-before-color" */
+  String get borderBeforeColor => getPropertyValue('border-before-color');
+
+  /** Sets the value of "border-before-color" */
+  set borderBeforeColor(String value) {
+    setProperty('border-before-color', value, '');
+  }
+
+  /** Gets the value of "border-before-style" */
+  String get borderBeforeStyle => getPropertyValue('border-before-style');
+
+  /** Sets the value of "border-before-style" */
+  set borderBeforeStyle(String value) {
+    setProperty('border-before-style', value, '');
+  }
+
+  /** Gets the value of "border-before-width" */
+  String get borderBeforeWidth => getPropertyValue('border-before-width');
+
+  /** Sets the value of "border-before-width" */
+  set borderBeforeWidth(String value) {
+    setProperty('border-before-width', value, '');
+  }
+
+  /** Gets the value of "border-bottom" */
+  String get borderBottom => getPropertyValue('border-bottom');
+
+  /** Sets the value of "border-bottom" */
+  set borderBottom(String value) {
+    setProperty('border-bottom', value, '');
+  }
+
+  /** Gets the value of "border-bottom-color" */
+  String get borderBottomColor => getPropertyValue('border-bottom-color');
+
+  /** Sets the value of "border-bottom-color" */
+  set borderBottomColor(String value) {
+    setProperty('border-bottom-color', value, '');
+  }
+
+  /** Gets the value of "border-bottom-left-radius" */
+  String get borderBottomLeftRadius =>
+      getPropertyValue('border-bottom-left-radius');
+
+  /** Sets the value of "border-bottom-left-radius" */
+  set borderBottomLeftRadius(String value) {
+    setProperty('border-bottom-left-radius', value, '');
+  }
+
+  /** Gets the value of "border-bottom-right-radius" */
+  String get borderBottomRightRadius =>
+      getPropertyValue('border-bottom-right-radius');
+
+  /** Sets the value of "border-bottom-right-radius" */
+  set borderBottomRightRadius(String value) {
+    setProperty('border-bottom-right-radius', value, '');
+  }
+
+  /** Gets the value of "border-bottom-style" */
+  String get borderBottomStyle => getPropertyValue('border-bottom-style');
+
+  /** Sets the value of "border-bottom-style" */
+  set borderBottomStyle(String value) {
+    setProperty('border-bottom-style', value, '');
+  }
+
+  /** Gets the value of "border-bottom-width" */
+  String get borderBottomWidth => getPropertyValue('border-bottom-width');
+
+  /** Sets the value of "border-bottom-width" */
+  set borderBottomWidth(String value) {
+    setProperty('border-bottom-width', value, '');
+  }
+
+  /** Gets the value of "border-collapse" */
+  String get borderCollapse => getPropertyValue('border-collapse');
+
+  /** Sets the value of "border-collapse" */
+  set borderCollapse(String value) {
+    setProperty('border-collapse', value, '');
+  }
+
+  /** Gets the value of "border-color" */
+  String get borderColor => getPropertyValue('border-color');
+
+  /** Sets the value of "border-color" */
+  set borderColor(String value) {
+    setProperty('border-color', value, '');
+  }
+
+  /** Gets the value of "border-end" */
+  String get borderEnd => getPropertyValue('border-end');
+
+  /** Sets the value of "border-end" */
+  set borderEnd(String value) {
+    setProperty('border-end', value, '');
+  }
+
+  /** Gets the value of "border-end-color" */
+  String get borderEndColor => getPropertyValue('border-end-color');
+
+  /** Sets the value of "border-end-color" */
+  set borderEndColor(String value) {
+    setProperty('border-end-color', value, '');
+  }
+
+  /** Gets the value of "border-end-style" */
+  String get borderEndStyle => getPropertyValue('border-end-style');
+
+  /** Sets the value of "border-end-style" */
+  set borderEndStyle(String value) {
+    setProperty('border-end-style', value, '');
+  }
+
+  /** Gets the value of "border-end-width" */
+  String get borderEndWidth => getPropertyValue('border-end-width');
+
+  /** Sets the value of "border-end-width" */
+  set borderEndWidth(String value) {
+    setProperty('border-end-width', value, '');
+  }
+
+  /** Gets the value of "border-fit" */
+  String get borderFit => getPropertyValue('border-fit');
+
+  /** Sets the value of "border-fit" */
+  set borderFit(String value) {
+    setProperty('border-fit', value, '');
+  }
+
+  /** Gets the value of "border-horizontal-spacing" */
+  String get borderHorizontalSpacing =>
+      getPropertyValue('border-horizontal-spacing');
+
+  /** Sets the value of "border-horizontal-spacing" */
+  set borderHorizontalSpacing(String value) {
+    setProperty('border-horizontal-spacing', value, '');
+  }
+
+  /** Gets the value of "border-image" */
+  String get borderImage => getPropertyValue('border-image');
+
+  /** Sets the value of "border-image" */
+  set borderImage(String value) {
+    setProperty('border-image', value, '');
+  }
+
+  /** Gets the value of "border-image-outset" */
+  String get borderImageOutset => getPropertyValue('border-image-outset');
+
+  /** Sets the value of "border-image-outset" */
+  set borderImageOutset(String value) {
+    setProperty('border-image-outset', value, '');
+  }
+
+  /** Gets the value of "border-image-repeat" */
+  String get borderImageRepeat => getPropertyValue('border-image-repeat');
+
+  /** Sets the value of "border-image-repeat" */
+  set borderImageRepeat(String value) {
+    setProperty('border-image-repeat', value, '');
+  }
+
+  /** Gets the value of "border-image-slice" */
+  String get borderImageSlice => getPropertyValue('border-image-slice');
+
+  /** Sets the value of "border-image-slice" */
+  set borderImageSlice(String value) {
+    setProperty('border-image-slice', value, '');
+  }
+
+  /** Gets the value of "border-image-source" */
+  String get borderImageSource => getPropertyValue('border-image-source');
+
+  /** Sets the value of "border-image-source" */
+  set borderImageSource(String value) {
+    setProperty('border-image-source', value, '');
+  }
+
+  /** Gets the value of "border-image-width" */
+  String get borderImageWidth => getPropertyValue('border-image-width');
+
+  /** Sets the value of "border-image-width" */
+  set borderImageWidth(String value) {
+    setProperty('border-image-width', value, '');
+  }
+
+  /** Gets the value of "border-left" */
+  String get borderLeft => getPropertyValue('border-left');
+
+  /** Sets the value of "border-left" */
+  set borderLeft(String value) {
+    setProperty('border-left', value, '');
+  }
+
+  /** Gets the value of "border-left-color" */
+  String get borderLeftColor => getPropertyValue('border-left-color');
+
+  /** Sets the value of "border-left-color" */
+  set borderLeftColor(String value) {
+    setProperty('border-left-color', value, '');
+  }
+
+  /** Gets the value of "border-left-style" */
+  String get borderLeftStyle => getPropertyValue('border-left-style');
+
+  /** Sets the value of "border-left-style" */
+  set borderLeftStyle(String value) {
+    setProperty('border-left-style', value, '');
+  }
+
+  /** Gets the value of "border-left-width" */
+  String get borderLeftWidth => getPropertyValue('border-left-width');
+
+  /** Sets the value of "border-left-width" */
+  set borderLeftWidth(String value) {
+    setProperty('border-left-width', value, '');
+  }
+
+  /** Gets the value of "border-radius" */
+  String get borderRadius => getPropertyValue('border-radius');
+
+  /** Sets the value of "border-radius" */
+  set borderRadius(String value) {
+    setProperty('border-radius', value, '');
+  }
+
+  /** Gets the value of "border-right" */
+  String get borderRight => getPropertyValue('border-right');
+
+  /** Sets the value of "border-right" */
+  set borderRight(String value) {
+    setProperty('border-right', value, '');
+  }
+
+  /** Gets the value of "border-right-color" */
+  String get borderRightColor => getPropertyValue('border-right-color');
+
+  /** Sets the value of "border-right-color" */
+  set borderRightColor(String value) {
+    setProperty('border-right-color', value, '');
+  }
+
+  /** Gets the value of "border-right-style" */
+  String get borderRightStyle => getPropertyValue('border-right-style');
+
+  /** Sets the value of "border-right-style" */
+  set borderRightStyle(String value) {
+    setProperty('border-right-style', value, '');
+  }
+
+  /** Gets the value of "border-right-width" */
+  String get borderRightWidth => getPropertyValue('border-right-width');
+
+  /** Sets the value of "border-right-width" */
+  set borderRightWidth(String value) {
+    setProperty('border-right-width', value, '');
+  }
+
+  /** Gets the value of "border-spacing" */
+  String get borderSpacing => getPropertyValue('border-spacing');
+
+  /** Sets the value of "border-spacing" */
+  set borderSpacing(String value) {
+    setProperty('border-spacing', value, '');
+  }
+
+  /** Gets the value of "border-start" */
+  String get borderStart => getPropertyValue('border-start');
+
+  /** Sets the value of "border-start" */
+  set borderStart(String value) {
+    setProperty('border-start', value, '');
+  }
+
+  /** Gets the value of "border-start-color" */
+  String get borderStartColor => getPropertyValue('border-start-color');
+
+  /** Sets the value of "border-start-color" */
+  set borderStartColor(String value) {
+    setProperty('border-start-color', value, '');
+  }
+
+  /** Gets the value of "border-start-style" */
+  String get borderStartStyle => getPropertyValue('border-start-style');
+
+  /** Sets the value of "border-start-style" */
+  set borderStartStyle(String value) {
+    setProperty('border-start-style', value, '');
+  }
+
+  /** Gets the value of "border-start-width" */
+  String get borderStartWidth => getPropertyValue('border-start-width');
+
+  /** Sets the value of "border-start-width" */
+  set borderStartWidth(String value) {
+    setProperty('border-start-width', value, '');
+  }
+
+  /** Gets the value of "border-style" */
+  String get borderStyle => getPropertyValue('border-style');
+
+  /** Sets the value of "border-style" */
+  set borderStyle(String value) {
+    setProperty('border-style', value, '');
+  }
+
+  /** Gets the value of "border-top" */
+  String get borderTop => getPropertyValue('border-top');
+
+  /** Sets the value of "border-top" */
+  set borderTop(String value) {
+    setProperty('border-top', value, '');
+  }
+
+  /** Gets the value of "border-top-color" */
+  String get borderTopColor => getPropertyValue('border-top-color');
+
+  /** Sets the value of "border-top-color" */
+  set borderTopColor(String value) {
+    setProperty('border-top-color', value, '');
+  }
+
+  /** Gets the value of "border-top-left-radius" */
+  String get borderTopLeftRadius => getPropertyValue('border-top-left-radius');
+
+  /** Sets the value of "border-top-left-radius" */
+  set borderTopLeftRadius(String value) {
+    setProperty('border-top-left-radius', value, '');
+  }
+
+  /** Gets the value of "border-top-right-radius" */
+  String get borderTopRightRadius =>
+      getPropertyValue('border-top-right-radius');
+
+  /** Sets the value of "border-top-right-radius" */
+  set borderTopRightRadius(String value) {
+    setProperty('border-top-right-radius', value, '');
+  }
+
+  /** Gets the value of "border-top-style" */
+  String get borderTopStyle => getPropertyValue('border-top-style');
+
+  /** Sets the value of "border-top-style" */
+  set borderTopStyle(String value) {
+    setProperty('border-top-style', value, '');
+  }
+
+  /** Gets the value of "border-top-width" */
+  String get borderTopWidth => getPropertyValue('border-top-width');
+
+  /** Sets the value of "border-top-width" */
+  set borderTopWidth(String value) {
+    setProperty('border-top-width', value, '');
+  }
+
+  /** Gets the value of "border-vertical-spacing" */
+  String get borderVerticalSpacing =>
+      getPropertyValue('border-vertical-spacing');
+
+  /** Sets the value of "border-vertical-spacing" */
+  set borderVerticalSpacing(String value) {
+    setProperty('border-vertical-spacing', value, '');
+  }
+
+  /** Gets the value of "border-width" */
+  String get borderWidth => getPropertyValue('border-width');
+
+  /** Sets the value of "border-width" */
+  set borderWidth(String value) {
+    setProperty('border-width', value, '');
+  }
+
+  /** Gets the value of "bottom" */
+  String get bottom => getPropertyValue('bottom');
+
+  /** Sets the value of "bottom" */
+  set bottom(String value) {
+    setProperty('bottom', value, '');
+  }
+
+  /** Gets the value of "box-align" */
+  String get boxAlign => getPropertyValue('box-align');
+
+  /** Sets the value of "box-align" */
+  set boxAlign(String value) {
+    setProperty('box-align', value, '');
+  }
+
+  /** Gets the value of "box-decoration-break" */
+  String get boxDecorationBreak => getPropertyValue('box-decoration-break');
+
+  /** Sets the value of "box-decoration-break" */
+  set boxDecorationBreak(String value) {
+    setProperty('box-decoration-break', value, '');
+  }
+
+  /** Gets the value of "box-direction" */
+  String get boxDirection => getPropertyValue('box-direction');
+
+  /** Sets the value of "box-direction" */
+  set boxDirection(String value) {
+    setProperty('box-direction', value, '');
+  }
+
+  /** Gets the value of "box-flex" */
+  String get boxFlex => getPropertyValue('box-flex');
+
+  /** Sets the value of "box-flex" */
+  set boxFlex(String value) {
+    setProperty('box-flex', value, '');
+  }
+
+  /** Gets the value of "box-flex-group" */
+  String get boxFlexGroup => getPropertyValue('box-flex-group');
+
+  /** Sets the value of "box-flex-group" */
+  set boxFlexGroup(String value) {
+    setProperty('box-flex-group', value, '');
+  }
+
+  /** Gets the value of "box-lines" */
+  String get boxLines => getPropertyValue('box-lines');
+
+  /** Sets the value of "box-lines" */
+  set boxLines(String value) {
+    setProperty('box-lines', value, '');
+  }
+
+  /** Gets the value of "box-ordinal-group" */
+  String get boxOrdinalGroup => getPropertyValue('box-ordinal-group');
+
+  /** Sets the value of "box-ordinal-group" */
+  set boxOrdinalGroup(String value) {
+    setProperty('box-ordinal-group', value, '');
+  }
+
+  /** Gets the value of "box-orient" */
+  String get boxOrient => getPropertyValue('box-orient');
+
+  /** Sets the value of "box-orient" */
+  set boxOrient(String value) {
+    setProperty('box-orient', value, '');
+  }
+
+  /** Gets the value of "box-pack" */
+  String get boxPack => getPropertyValue('box-pack');
+
+  /** Sets the value of "box-pack" */
+  set boxPack(String value) {
+    setProperty('box-pack', value, '');
+  }
+
+  /** Gets the value of "box-reflect" */
+  String get boxReflect => getPropertyValue('box-reflect');
+
+  /** Sets the value of "box-reflect" */
+  set boxReflect(String value) {
+    setProperty('box-reflect', value, '');
+  }
+
+  /** Gets the value of "box-shadow" */
+  String get boxShadow => getPropertyValue('box-shadow');
+
+  /** Sets the value of "box-shadow" */
+  set boxShadow(String value) {
+    setProperty('box-shadow', value, '');
+  }
+
+  /** Gets the value of "box-sizing" */
+  String get boxSizing => getPropertyValue('box-sizing');
+
+  /** Sets the value of "box-sizing" */
+  set boxSizing(String value) {
+    setProperty('box-sizing', value, '');
+  }
+
+  /** Gets the value of "caption-side" */
+  String get captionSide => getPropertyValue('caption-side');
+
+  /** Sets the value of "caption-side" */
+  set captionSide(String value) {
+    setProperty('caption-side', value, '');
+  }
+
+  /** Gets the value of "clear" */
+  String get clear => getPropertyValue('clear');
+
+  /** Sets the value of "clear" */
+  set clear(String value) {
+    setProperty('clear', value, '');
+  }
+
+  /** Gets the value of "clip" */
+  String get clip => getPropertyValue('clip');
+
+  /** Sets the value of "clip" */
+  set clip(String value) {
+    setProperty('clip', value, '');
+  }
+
+  /** Gets the value of "clip-path" */
+  String get clipPath => getPropertyValue('clip-path');
+
+  /** Sets the value of "clip-path" */
+  set clipPath(String value) {
+    setProperty('clip-path', value, '');
+  }
+
+  /** Gets the value of "color" */
+  String get color => getPropertyValue('color');
+
+  /** Sets the value of "color" */
+  set color(String value) {
+    setProperty('color', value, '');
+  }
+
+  /** Gets the value of "column-break-after" */
+  String get columnBreakAfter => getPropertyValue('column-break-after');
+
+  /** Sets the value of "column-break-after" */
+  set columnBreakAfter(String value) {
+    setProperty('column-break-after', value, '');
+  }
+
+  /** Gets the value of "column-break-before" */
+  String get columnBreakBefore => getPropertyValue('column-break-before');
+
+  /** Sets the value of "column-break-before" */
+  set columnBreakBefore(String value) {
+    setProperty('column-break-before', value, '');
+  }
+
+  /** Gets the value of "column-break-inside" */
+  String get columnBreakInside => getPropertyValue('column-break-inside');
+
+  /** Sets the value of "column-break-inside" */
+  set columnBreakInside(String value) {
+    setProperty('column-break-inside', value, '');
+  }
+
+  /** Gets the value of "column-count" */
+  String get columnCount => getPropertyValue('column-count');
+
+  /** Sets the value of "column-count" */
+  set columnCount(String value) {
+    setProperty('column-count', value, '');
+  }
+
+  /** Gets the value of "column-fill" */
+  String get columnFill => getPropertyValue('column-fill');
+
+  /** Sets the value of "column-fill" */
+  set columnFill(String value) {
+    setProperty('column-fill', value, '');
+  }
+
+  /** Gets the value of "column-gap" */
+  String get columnGap => getPropertyValue('column-gap');
+
+  /** Sets the value of "column-gap" */
+  set columnGap(String value) {
+    setProperty('column-gap', value, '');
+  }
+
+  /** Gets the value of "column-rule" */
+  String get columnRule => getPropertyValue('column-rule');
+
+  /** Sets the value of "column-rule" */
+  set columnRule(String value) {
+    setProperty('column-rule', value, '');
+  }
+
+  /** Gets the value of "column-rule-color" */
+  String get columnRuleColor => getPropertyValue('column-rule-color');
+
+  /** Sets the value of "column-rule-color" */
+  set columnRuleColor(String value) {
+    setProperty('column-rule-color', value, '');
+  }
+
+  /** Gets the value of "column-rule-style" */
+  String get columnRuleStyle => getPropertyValue('column-rule-style');
+
+  /** Sets the value of "column-rule-style" */
+  set columnRuleStyle(String value) {
+    setProperty('column-rule-style', value, '');
+  }
+
+  /** Gets the value of "column-rule-width" */
+  String get columnRuleWidth => getPropertyValue('column-rule-width');
+
+  /** Sets the value of "column-rule-width" */
+  set columnRuleWidth(String value) {
+    setProperty('column-rule-width', value, '');
+  }
+
+  /** Gets the value of "column-span" */
+  String get columnSpan => getPropertyValue('column-span');
+
+  /** Sets the value of "column-span" */
+  set columnSpan(String value) {
+    setProperty('column-span', value, '');
+  }
+
+  /** Gets the value of "column-width" */
+  String get columnWidth => getPropertyValue('column-width');
+
+  /** Sets the value of "column-width" */
+  set columnWidth(String value) {
+    setProperty('column-width', value, '');
+  }
+
+  /** Gets the value of "columns" */
+  String get columns => getPropertyValue('columns');
+
+  /** Sets the value of "columns" */
+  set columns(String value) {
+    setProperty('columns', value, '');
+  }
+
+  /** Gets the value of "content" */
+  String get content => getPropertyValue('content');
+
+  /** Sets the value of "content" */
+  set content(String value) {
+    setProperty('content', value, '');
+  }
+
+  /** Gets the value of "counter-increment" */
+  String get counterIncrement => getPropertyValue('counter-increment');
+
+  /** Sets the value of "counter-increment" */
+  set counterIncrement(String value) {
+    setProperty('counter-increment', value, '');
+  }
+
+  /** Gets the value of "counter-reset" */
+  String get counterReset => getPropertyValue('counter-reset');
+
+  /** Sets the value of "counter-reset" */
+  set counterReset(String value) {
+    setProperty('counter-reset', value, '');
+  }
+
+  /** Gets the value of "cursor" */
+  String get cursor => getPropertyValue('cursor');
+
+  /** Sets the value of "cursor" */
+  set cursor(String value) {
+    setProperty('cursor', value, '');
+  }
+
+  /** Gets the value of "direction" */
+  String get direction => getPropertyValue('direction');
+
+  /** Sets the value of "direction" */
+  set direction(String value) {
+    setProperty('direction', value, '');
+  }
+
+  /** Gets the value of "display" */
+  String get display => getPropertyValue('display');
+
+  /** Sets the value of "display" */
+  set display(String value) {
+    setProperty('display', value, '');
+  }
+
+  /** Gets the value of "empty-cells" */
+  String get emptyCells => getPropertyValue('empty-cells');
+
+  /** Sets the value of "empty-cells" */
+  set emptyCells(String value) {
+    setProperty('empty-cells', value, '');
+  }
+
+  /** Gets the value of "filter" */
+  String get filter => getPropertyValue('filter');
+
+  /** Sets the value of "filter" */
+  set filter(String value) {
+    setProperty('filter', value, '');
+  }
+
+  /** Gets the value of "flex" */
+  String get flex => getPropertyValue('flex');
+
+  /** Sets the value of "flex" */
+  set flex(String value) {
+    setProperty('flex', value, '');
+  }
+
+  /** Gets the value of "flex-basis" */
+  String get flexBasis => getPropertyValue('flex-basis');
+
+  /** Sets the value of "flex-basis" */
+  set flexBasis(String value) {
+    setProperty('flex-basis', value, '');
+  }
+
+  /** Gets the value of "flex-direction" */
+  String get flexDirection => getPropertyValue('flex-direction');
+
+  /** Sets the value of "flex-direction" */
+  set flexDirection(String value) {
+    setProperty('flex-direction', value, '');
+  }
+
+  /** Gets the value of "flex-flow" */
+  String get flexFlow => getPropertyValue('flex-flow');
+
+  /** Sets the value of "flex-flow" */
+  set flexFlow(String value) {
+    setProperty('flex-flow', value, '');
+  }
+
+  /** Gets the value of "flex-grow" */
+  String get flexGrow => getPropertyValue('flex-grow');
+
+  /** Sets the value of "flex-grow" */
+  set flexGrow(String value) {
+    setProperty('flex-grow', value, '');
+  }
+
+  /** Gets the value of "flex-shrink" */
+  String get flexShrink => getPropertyValue('flex-shrink');
+
+  /** Sets the value of "flex-shrink" */
+  set flexShrink(String value) {
+    setProperty('flex-shrink', value, '');
+  }
+
+  /** Gets the value of "flex-wrap" */
+  String get flexWrap => getPropertyValue('flex-wrap');
+
+  /** Sets the value of "flex-wrap" */
+  set flexWrap(String value) {
+    setProperty('flex-wrap', value, '');
+  }
+
+  /** Gets the value of "float" */
+  String get float => getPropertyValue('float');
+
+  /** Sets the value of "float" */
+  set float(String value) {
+    setProperty('float', value, '');
+  }
+
+  /** Gets the value of "font" */
+  String get font => getPropertyValue('font');
+
+  /** Sets the value of "font" */
+  set font(String value) {
+    setProperty('font', value, '');
+  }
+
+  /** Gets the value of "font-family" */
+  String get fontFamily => getPropertyValue('font-family');
+
+  /** Sets the value of "font-family" */
+  set fontFamily(String value) {
+    setProperty('font-family', value, '');
+  }
+
+  /** Gets the value of "font-feature-settings" */
+  String get fontFeatureSettings => getPropertyValue('font-feature-settings');
+
+  /** Sets the value of "font-feature-settings" */
+  set fontFeatureSettings(String value) {
+    setProperty('font-feature-settings', value, '');
+  }
+
+  /** Gets the value of "font-kerning" */
+  String get fontKerning => getPropertyValue('font-kerning');
+
+  /** Sets the value of "font-kerning" */
+  set fontKerning(String value) {
+    setProperty('font-kerning', value, '');
+  }
+
+  /** Gets the value of "font-size" */
+  String get fontSize => getPropertyValue('font-size');
+
+  /** Sets the value of "font-size" */
+  set fontSize(String value) {
+    setProperty('font-size', value, '');
+  }
+
+  /** Gets the value of "font-size-delta" */
+  String get fontSizeDelta => getPropertyValue('font-size-delta');
+
+  /** Sets the value of "font-size-delta" */
+  set fontSizeDelta(String value) {
+    setProperty('font-size-delta', value, '');
+  }
+
+  /** Gets the value of "font-smoothing" */
+  String get fontSmoothing => getPropertyValue('font-smoothing');
+
+  /** Sets the value of "font-smoothing" */
+  set fontSmoothing(String value) {
+    setProperty('font-smoothing', value, '');
+  }
+
+  /** Gets the value of "font-stretch" */
+  String get fontStretch => getPropertyValue('font-stretch');
+
+  /** Sets the value of "font-stretch" */
+  set fontStretch(String value) {
+    setProperty('font-stretch', value, '');
+  }
+
+  /** Gets the value of "font-style" */
+  String get fontStyle => getPropertyValue('font-style');
+
+  /** Sets the value of "font-style" */
+  set fontStyle(String value) {
+    setProperty('font-style', value, '');
+  }
+
+  /** Gets the value of "font-variant" */
+  String get fontVariant => getPropertyValue('font-variant');
+
+  /** Sets the value of "font-variant" */
+  set fontVariant(String value) {
+    setProperty('font-variant', value, '');
+  }
+
+  /** Gets the value of "font-variant-ligatures" */
+  String get fontVariantLigatures => getPropertyValue('font-variant-ligatures');
+
+  /** Sets the value of "font-variant-ligatures" */
+  set fontVariantLigatures(String value) {
+    setProperty('font-variant-ligatures', value, '');
+  }
+
+  /** Gets the value of "font-weight" */
+  String get fontWeight => getPropertyValue('font-weight');
+
+  /** Sets the value of "font-weight" */
+  set fontWeight(String value) {
+    setProperty('font-weight', value, '');
+  }
+
+  /** Gets the value of "grid" */
+  String get grid => getPropertyValue('grid');
+
+  /** Sets the value of "grid" */
+  set grid(String value) {
+    setProperty('grid', value, '');
+  }
+
+  /** Gets the value of "grid-area" */
+  String get gridArea => getPropertyValue('grid-area');
+
+  /** Sets the value of "grid-area" */
+  set gridArea(String value) {
+    setProperty('grid-area', value, '');
+  }
+
+  /** Gets the value of "grid-auto-columns" */
+  String get gridAutoColumns => getPropertyValue('grid-auto-columns');
+
+  /** Sets the value of "grid-auto-columns" */
+  set gridAutoColumns(String value) {
+    setProperty('grid-auto-columns', value, '');
+  }
+
+  /** Gets the value of "grid-auto-flow" */
+  String get gridAutoFlow => getPropertyValue('grid-auto-flow');
+
+  /** Sets the value of "grid-auto-flow" */
+  set gridAutoFlow(String value) {
+    setProperty('grid-auto-flow', value, '');
+  }
+
+  /** Gets the value of "grid-auto-rows" */
+  String get gridAutoRows => getPropertyValue('grid-auto-rows');
+
+  /** Sets the value of "grid-auto-rows" */
+  set gridAutoRows(String value) {
+    setProperty('grid-auto-rows', value, '');
+  }
+
+  /** Gets the value of "grid-column" */
+  String get gridColumn => getPropertyValue('grid-column');
+
+  /** Sets the value of "grid-column" */
+  set gridColumn(String value) {
+    setProperty('grid-column', value, '');
+  }
+
+  /** Gets the value of "grid-column-end" */
+  String get gridColumnEnd => getPropertyValue('grid-column-end');
+
+  /** Sets the value of "grid-column-end" */
+  set gridColumnEnd(String value) {
+    setProperty('grid-column-end', value, '');
+  }
+
+  /** Gets the value of "grid-column-start" */
+  String get gridColumnStart => getPropertyValue('grid-column-start');
+
+  /** Sets the value of "grid-column-start" */
+  set gridColumnStart(String value) {
+    setProperty('grid-column-start', value, '');
+  }
+
+  /** Gets the value of "grid-row" */
+  String get gridRow => getPropertyValue('grid-row');
+
+  /** Sets the value of "grid-row" */
+  set gridRow(String value) {
+    setProperty('grid-row', value, '');
+  }
+
+  /** Gets the value of "grid-row-end" */
+  String get gridRowEnd => getPropertyValue('grid-row-end');
+
+  /** Sets the value of "grid-row-end" */
+  set gridRowEnd(String value) {
+    setProperty('grid-row-end', value, '');
+  }
+
+  /** Gets the value of "grid-row-start" */
+  String get gridRowStart => getPropertyValue('grid-row-start');
+
+  /** Sets the value of "grid-row-start" */
+  set gridRowStart(String value) {
+    setProperty('grid-row-start', value, '');
+  }
+
+  /** Gets the value of "grid-template" */
+  String get gridTemplate => getPropertyValue('grid-template');
+
+  /** Sets the value of "grid-template" */
+  set gridTemplate(String value) {
+    setProperty('grid-template', value, '');
+  }
+
+  /** Gets the value of "grid-template-areas" */
+  String get gridTemplateAreas => getPropertyValue('grid-template-areas');
+
+  /** Sets the value of "grid-template-areas" */
+  set gridTemplateAreas(String value) {
+    setProperty('grid-template-areas', value, '');
+  }
+
+  /** Gets the value of "grid-template-columns" */
+  String get gridTemplateColumns => getPropertyValue('grid-template-columns');
+
+  /** Sets the value of "grid-template-columns" */
+  set gridTemplateColumns(String value) {
+    setProperty('grid-template-columns', value, '');
+  }
+
+  /** Gets the value of "grid-template-rows" */
+  String get gridTemplateRows => getPropertyValue('grid-template-rows');
+
+  /** Sets the value of "grid-template-rows" */
+  set gridTemplateRows(String value) {
+    setProperty('grid-template-rows', value, '');
+  }
+
+  /** Gets the value of "height" */
+  String get height => getPropertyValue('height');
+
+  /** Sets the value of "height" */
+  set height(String value) {
+    setProperty('height', value, '');
+  }
+
+  /** Gets the value of "highlight" */
+  String get highlight => getPropertyValue('highlight');
+
+  /** Sets the value of "highlight" */
+  set highlight(String value) {
+    setProperty('highlight', value, '');
+  }
+
+  /** Gets the value of "hyphenate-character" */
+  String get hyphenateCharacter => getPropertyValue('hyphenate-character');
+
+  /** Sets the value of "hyphenate-character" */
+  set hyphenateCharacter(String value) {
+    setProperty('hyphenate-character', value, '');
+  }
+
+  /** Gets the value of "image-rendering" */
+  String get imageRendering => getPropertyValue('image-rendering');
+
+  /** Sets the value of "image-rendering" */
+  set imageRendering(String value) {
+    setProperty('image-rendering', value, '');
+  }
+
+  /** Gets the value of "isolation" */
+  String get isolation => getPropertyValue('isolation');
+
+  /** Sets the value of "isolation" */
+  set isolation(String value) {
+    setProperty('isolation', value, '');
+  }
+
+  /** Gets the value of "justify-content" */
+  String get justifyContent => getPropertyValue('justify-content');
+
+  /** Sets the value of "justify-content" */
+  set justifyContent(String value) {
+    setProperty('justify-content', value, '');
+  }
+
+  /** Gets the value of "justify-self" */
+  String get justifySelf => getPropertyValue('justify-self');
+
+  /** Sets the value of "justify-self" */
+  set justifySelf(String value) {
+    setProperty('justify-self', value, '');
+  }
+
+  /** Gets the value of "left" */
+  String get left => getPropertyValue('left');
+
+  /** Sets the value of "left" */
+  set left(String value) {
+    setProperty('left', value, '');
+  }
+
+  /** Gets the value of "letter-spacing" */
+  String get letterSpacing => getPropertyValue('letter-spacing');
+
+  /** Sets the value of "letter-spacing" */
+  set letterSpacing(String value) {
+    setProperty('letter-spacing', value, '');
+  }
+
+  /** Gets the value of "line-box-contain" */
+  String get lineBoxContain => getPropertyValue('line-box-contain');
+
+  /** Sets the value of "line-box-contain" */
+  set lineBoxContain(String value) {
+    setProperty('line-box-contain', value, '');
+  }
+
+  /** Gets the value of "line-break" */
+  String get lineBreak => getPropertyValue('line-break');
+
+  /** Sets the value of "line-break" */
+  set lineBreak(String value) {
+    setProperty('line-break', value, '');
+  }
+
+  /** Gets the value of "line-clamp" */
+  String get lineClamp => getPropertyValue('line-clamp');
+
+  /** Sets the value of "line-clamp" */
+  set lineClamp(String value) {
+    setProperty('line-clamp', value, '');
+  }
+
+  /** Gets the value of "line-height" */
+  String get lineHeight => getPropertyValue('line-height');
+
+  /** Sets the value of "line-height" */
+  set lineHeight(String value) {
+    setProperty('line-height', value, '');
+  }
+
+  /** Gets the value of "list-style" */
+  String get listStyle => getPropertyValue('list-style');
+
+  /** Sets the value of "list-style" */
+  set listStyle(String value) {
+    setProperty('list-style', value, '');
+  }
+
+  /** Gets the value of "list-style-image" */
+  String get listStyleImage => getPropertyValue('list-style-image');
+
+  /** Sets the value of "list-style-image" */
+  set listStyleImage(String value) {
+    setProperty('list-style-image', value, '');
+  }
+
+  /** Gets the value of "list-style-position" */
+  String get listStylePosition => getPropertyValue('list-style-position');
+
+  /** Sets the value of "list-style-position" */
+  set listStylePosition(String value) {
+    setProperty('list-style-position', value, '');
+  }
+
+  /** Gets the value of "list-style-type" */
+  String get listStyleType => getPropertyValue('list-style-type');
+
+  /** Sets the value of "list-style-type" */
+  set listStyleType(String value) {
+    setProperty('list-style-type', value, '');
+  }
+
+  /** Gets the value of "locale" */
+  String get locale => getPropertyValue('locale');
+
+  /** Sets the value of "locale" */
+  set locale(String value) {
+    setProperty('locale', value, '');
+  }
+
+  /** Gets the value of "logical-height" */
+  String get logicalHeight => getPropertyValue('logical-height');
+
+  /** Sets the value of "logical-height" */
+  set logicalHeight(String value) {
+    setProperty('logical-height', value, '');
+  }
+
+  /** Gets the value of "logical-width" */
+  String get logicalWidth => getPropertyValue('logical-width');
+
+  /** Sets the value of "logical-width" */
+  set logicalWidth(String value) {
+    setProperty('logical-width', value, '');
+  }
+
+  /** Gets the value of "margin" */
+  String get margin => getPropertyValue('margin');
+
+  /** Sets the value of "margin" */
+  set margin(String value) {
+    setProperty('margin', value, '');
+  }
+
+  /** Gets the value of "margin-after" */
+  String get marginAfter => getPropertyValue('margin-after');
+
+  /** Sets the value of "margin-after" */
+  set marginAfter(String value) {
+    setProperty('margin-after', value, '');
+  }
+
+  /** Gets the value of "margin-after-collapse" */
+  String get marginAfterCollapse => getPropertyValue('margin-after-collapse');
+
+  /** Sets the value of "margin-after-collapse" */
+  set marginAfterCollapse(String value) {
+    setProperty('margin-after-collapse', value, '');
+  }
+
+  /** Gets the value of "margin-before" */
+  String get marginBefore => getPropertyValue('margin-before');
+
+  /** Sets the value of "margin-before" */
+  set marginBefore(String value) {
+    setProperty('margin-before', value, '');
+  }
+
+  /** Gets the value of "margin-before-collapse" */
+  String get marginBeforeCollapse => getPropertyValue('margin-before-collapse');
+
+  /** Sets the value of "margin-before-collapse" */
+  set marginBeforeCollapse(String value) {
+    setProperty('margin-before-collapse', value, '');
+  }
+
+  /** Gets the value of "margin-bottom" */
+  String get marginBottom => getPropertyValue('margin-bottom');
+
+  /** Sets the value of "margin-bottom" */
+  set marginBottom(String value) {
+    setProperty('margin-bottom', value, '');
+  }
+
+  /** Gets the value of "margin-bottom-collapse" */
+  String get marginBottomCollapse => getPropertyValue('margin-bottom-collapse');
+
+  /** Sets the value of "margin-bottom-collapse" */
+  set marginBottomCollapse(String value) {
+    setProperty('margin-bottom-collapse', value, '');
+  }
+
+  /** Gets the value of "margin-collapse" */
+  String get marginCollapse => getPropertyValue('margin-collapse');
+
+  /** Sets the value of "margin-collapse" */
+  set marginCollapse(String value) {
+    setProperty('margin-collapse', value, '');
+  }
+
+  /** Gets the value of "margin-end" */
+  String get marginEnd => getPropertyValue('margin-end');
+
+  /** Sets the value of "margin-end" */
+  set marginEnd(String value) {
+    setProperty('margin-end', value, '');
+  }
+
+  /** Gets the value of "margin-left" */
+  String get marginLeft => getPropertyValue('margin-left');
+
+  /** Sets the value of "margin-left" */
+  set marginLeft(String value) {
+    setProperty('margin-left', value, '');
+  }
+
+  /** Gets the value of "margin-right" */
+  String get marginRight => getPropertyValue('margin-right');
+
+  /** Sets the value of "margin-right" */
+  set marginRight(String value) {
+    setProperty('margin-right', value, '');
+  }
+
+  /** Gets the value of "margin-start" */
+  String get marginStart => getPropertyValue('margin-start');
+
+  /** Sets the value of "margin-start" */
+  set marginStart(String value) {
+    setProperty('margin-start', value, '');
+  }
+
+  /** Gets the value of "margin-top" */
+  String get marginTop => getPropertyValue('margin-top');
+
+  /** Sets the value of "margin-top" */
+  set marginTop(String value) {
+    setProperty('margin-top', value, '');
+  }
+
+  /** Gets the value of "margin-top-collapse" */
+  String get marginTopCollapse => getPropertyValue('margin-top-collapse');
+
+  /** Sets the value of "margin-top-collapse" */
+  set marginTopCollapse(String value) {
+    setProperty('margin-top-collapse', value, '');
+  }
+
+  /** Gets the value of "mask" */
+  String get mask => getPropertyValue('mask');
+
+  /** Sets the value of "mask" */
+  set mask(String value) {
+    setProperty('mask', value, '');
+  }
+
+  /** Gets the value of "mask-box-image" */
+  String get maskBoxImage => getPropertyValue('mask-box-image');
+
+  /** Sets the value of "mask-box-image" */
+  set maskBoxImage(String value) {
+    setProperty('mask-box-image', value, '');
+  }
+
+  /** Gets the value of "mask-box-image-outset" */
+  String get maskBoxImageOutset => getPropertyValue('mask-box-image-outset');
+
+  /** Sets the value of "mask-box-image-outset" */
+  set maskBoxImageOutset(String value) {
+    setProperty('mask-box-image-outset', value, '');
+  }
+
+  /** Gets the value of "mask-box-image-repeat" */
+  String get maskBoxImageRepeat => getPropertyValue('mask-box-image-repeat');
+
+  /** Sets the value of "mask-box-image-repeat" */
+  set maskBoxImageRepeat(String value) {
+    setProperty('mask-box-image-repeat', value, '');
+  }
+
+  /** Gets the value of "mask-box-image-slice" */
+  String get maskBoxImageSlice => getPropertyValue('mask-box-image-slice');
+
+  /** Sets the value of "mask-box-image-slice" */
+  set maskBoxImageSlice(String value) {
+    setProperty('mask-box-image-slice', value, '');
+  }
+
+  /** Gets the value of "mask-box-image-source" */
+  String get maskBoxImageSource => getPropertyValue('mask-box-image-source');
+
+  /** Sets the value of "mask-box-image-source" */
+  set maskBoxImageSource(String value) {
+    setProperty('mask-box-image-source', value, '');
+  }
+
+  /** Gets the value of "mask-box-image-width" */
+  String get maskBoxImageWidth => getPropertyValue('mask-box-image-width');
+
+  /** Sets the value of "mask-box-image-width" */
+  set maskBoxImageWidth(String value) {
+    setProperty('mask-box-image-width', value, '');
+  }
+
+  /** Gets the value of "mask-clip" */
+  String get maskClip => getPropertyValue('mask-clip');
+
+  /** Sets the value of "mask-clip" */
+  set maskClip(String value) {
+    setProperty('mask-clip', value, '');
+  }
+
+  /** Gets the value of "mask-composite" */
+  String get maskComposite => getPropertyValue('mask-composite');
+
+  /** Sets the value of "mask-composite" */
+  set maskComposite(String value) {
+    setProperty('mask-composite', value, '');
+  }
+
+  /** Gets the value of "mask-image" */
+  String get maskImage => getPropertyValue('mask-image');
+
+  /** Sets the value of "mask-image" */
+  set maskImage(String value) {
+    setProperty('mask-image', value, '');
+  }
+
+  /** Gets the value of "mask-origin" */
+  String get maskOrigin => getPropertyValue('mask-origin');
+
+  /** Sets the value of "mask-origin" */
+  set maskOrigin(String value) {
+    setProperty('mask-origin', value, '');
+  }
+
+  /** Gets the value of "mask-position" */
+  String get maskPosition => getPropertyValue('mask-position');
+
+  /** Sets the value of "mask-position" */
+  set maskPosition(String value) {
+    setProperty('mask-position', value, '');
+  }
+
+  /** Gets the value of "mask-position-x" */
+  String get maskPositionX => getPropertyValue('mask-position-x');
+
+  /** Sets the value of "mask-position-x" */
+  set maskPositionX(String value) {
+    setProperty('mask-position-x', value, '');
+  }
+
+  /** Gets the value of "mask-position-y" */
+  String get maskPositionY => getPropertyValue('mask-position-y');
+
+  /** Sets the value of "mask-position-y" */
+  set maskPositionY(String value) {
+    setProperty('mask-position-y', value, '');
+  }
+
+  /** Gets the value of "mask-repeat" */
+  String get maskRepeat => getPropertyValue('mask-repeat');
+
+  /** Sets the value of "mask-repeat" */
+  set maskRepeat(String value) {
+    setProperty('mask-repeat', value, '');
+  }
+
+  /** Gets the value of "mask-repeat-x" */
+  String get maskRepeatX => getPropertyValue('mask-repeat-x');
+
+  /** Sets the value of "mask-repeat-x" */
+  set maskRepeatX(String value) {
+    setProperty('mask-repeat-x', value, '');
+  }
+
+  /** Gets the value of "mask-repeat-y" */
+  String get maskRepeatY => getPropertyValue('mask-repeat-y');
+
+  /** Sets the value of "mask-repeat-y" */
+  set maskRepeatY(String value) {
+    setProperty('mask-repeat-y', value, '');
+  }
+
+  /** Gets the value of "mask-size" */
+  String get maskSize => getPropertyValue('mask-size');
+
+  /** Sets the value of "mask-size" */
+  set maskSize(String value) {
+    setProperty('mask-size', value, '');
+  }
+
+  /** Gets the value of "mask-source-type" */
+  String get maskSourceType => getPropertyValue('mask-source-type');
+
+  /** Sets the value of "mask-source-type" */
+  set maskSourceType(String value) {
+    setProperty('mask-source-type', value, '');
+  }
+
+  /** Gets the value of "max-height" */
+  String get maxHeight => getPropertyValue('max-height');
+
+  /** Sets the value of "max-height" */
+  set maxHeight(String value) {
+    setProperty('max-height', value, '');
+  }
+
+  /** Gets the value of "max-logical-height" */
+  String get maxLogicalHeight => getPropertyValue('max-logical-height');
+
+  /** Sets the value of "max-logical-height" */
+  set maxLogicalHeight(String value) {
+    setProperty('max-logical-height', value, '');
+  }
+
+  /** Gets the value of "max-logical-width" */
+  String get maxLogicalWidth => getPropertyValue('max-logical-width');
+
+  /** Sets the value of "max-logical-width" */
+  set maxLogicalWidth(String value) {
+    setProperty('max-logical-width', value, '');
+  }
+
+  /** Gets the value of "max-width" */
+  String get maxWidth => getPropertyValue('max-width');
+
+  /** Sets the value of "max-width" */
+  set maxWidth(String value) {
+    setProperty('max-width', value, '');
+  }
+
+  /** Gets the value of "max-zoom" */
+  String get maxZoom => getPropertyValue('max-zoom');
+
+  /** Sets the value of "max-zoom" */
+  set maxZoom(String value) {
+    setProperty('max-zoom', value, '');
+  }
+
+  /** Gets the value of "min-height" */
+  String get minHeight => getPropertyValue('min-height');
+
+  /** Sets the value of "min-height" */
+  set minHeight(String value) {
+    setProperty('min-height', value, '');
+  }
+
+  /** Gets the value of "min-logical-height" */
+  String get minLogicalHeight => getPropertyValue('min-logical-height');
+
+  /** Sets the value of "min-logical-height" */
+  set minLogicalHeight(String value) {
+    setProperty('min-logical-height', value, '');
+  }
+
+  /** Gets the value of "min-logical-width" */
+  String get minLogicalWidth => getPropertyValue('min-logical-width');
+
+  /** Sets the value of "min-logical-width" */
+  set minLogicalWidth(String value) {
+    setProperty('min-logical-width', value, '');
+  }
+
+  /** Gets the value of "min-width" */
+  String get minWidth => getPropertyValue('min-width');
+
+  /** Sets the value of "min-width" */
+  set minWidth(String value) {
+    setProperty('min-width', value, '');
+  }
+
+  /** Gets the value of "min-zoom" */
+  String get minZoom => getPropertyValue('min-zoom');
+
+  /** Sets the value of "min-zoom" */
+  set minZoom(String value) {
+    setProperty('min-zoom', value, '');
+  }
+
+  /** Gets the value of "mix-blend-mode" */
+  String get mixBlendMode => getPropertyValue('mix-blend-mode');
+
+  /** Sets the value of "mix-blend-mode" */
+  set mixBlendMode(String value) {
+    setProperty('mix-blend-mode', value, '');
+  }
+
+  /** Gets the value of "object-fit" */
+  String get objectFit => getPropertyValue('object-fit');
+
+  /** Sets the value of "object-fit" */
+  set objectFit(String value) {
+    setProperty('object-fit', value, '');
+  }
+
+  /** Gets the value of "object-position" */
+  String get objectPosition => getPropertyValue('object-position');
+
+  /** Sets the value of "object-position" */
+  set objectPosition(String value) {
+    setProperty('object-position', value, '');
+  }
+
+  /** Gets the value of "opacity" */
+  String get opacity => getPropertyValue('opacity');
+
+  /** Sets the value of "opacity" */
+  set opacity(String value) {
+    setProperty('opacity', value, '');
+  }
+
+  /** Gets the value of "order" */
+  String get order => getPropertyValue('order');
+
+  /** Sets the value of "order" */
+  set order(String value) {
+    setProperty('order', value, '');
+  }
+
+  /** Gets the value of "orientation" */
+  String get orientation => getPropertyValue('orientation');
+
+  /** Sets the value of "orientation" */
+  set orientation(String value) {
+    setProperty('orientation', value, '');
+  }
+
+  /** Gets the value of "orphans" */
+  String get orphans => getPropertyValue('orphans');
+
+  /** Sets the value of "orphans" */
+  set orphans(String value) {
+    setProperty('orphans', value, '');
+  }
+
+  /** Gets the value of "outline" */
+  String get outline => getPropertyValue('outline');
+
+  /** Sets the value of "outline" */
+  set outline(String value) {
+    setProperty('outline', value, '');
+  }
+
+  /** Gets the value of "outline-color" */
+  String get outlineColor => getPropertyValue('outline-color');
+
+  /** Sets the value of "outline-color" */
+  set outlineColor(String value) {
+    setProperty('outline-color', value, '');
+  }
+
+  /** Gets the value of "outline-offset" */
+  String get outlineOffset => getPropertyValue('outline-offset');
+
+  /** Sets the value of "outline-offset" */
+  set outlineOffset(String value) {
+    setProperty('outline-offset', value, '');
+  }
+
+  /** Gets the value of "outline-style" */
+  String get outlineStyle => getPropertyValue('outline-style');
+
+  /** Sets the value of "outline-style" */
+  set outlineStyle(String value) {
+    setProperty('outline-style', value, '');
+  }
+
+  /** Gets the value of "outline-width" */
+  String get outlineWidth => getPropertyValue('outline-width');
+
+  /** Sets the value of "outline-width" */
+  set outlineWidth(String value) {
+    setProperty('outline-width', value, '');
+  }
+
+  /** Gets the value of "overflow" */
+  String get overflow => getPropertyValue('overflow');
+
+  /** Sets the value of "overflow" */
+  set overflow(String value) {
+    setProperty('overflow', value, '');
+  }
+
+  /** Gets the value of "overflow-wrap" */
+  String get overflowWrap => getPropertyValue('overflow-wrap');
+
+  /** Sets the value of "overflow-wrap" */
+  set overflowWrap(String value) {
+    setProperty('overflow-wrap', value, '');
+  }
+
+  /** Gets the value of "overflow-x" */
+  String get overflowX => getPropertyValue('overflow-x');
+
+  /** Sets the value of "overflow-x" */
+  set overflowX(String value) {
+    setProperty('overflow-x', value, '');
+  }
+
+  /** Gets the value of "overflow-y" */
+  String get overflowY => getPropertyValue('overflow-y');
+
+  /** Sets the value of "overflow-y" */
+  set overflowY(String value) {
+    setProperty('overflow-y', value, '');
+  }
+
+  /** Gets the value of "padding" */
+  String get padding => getPropertyValue('padding');
+
+  /** Sets the value of "padding" */
+  set padding(String value) {
+    setProperty('padding', value, '');
+  }
+
+  /** Gets the value of "padding-after" */
+  String get paddingAfter => getPropertyValue('padding-after');
+
+  /** Sets the value of "padding-after" */
+  set paddingAfter(String value) {
+    setProperty('padding-after', value, '');
+  }
+
+  /** Gets the value of "padding-before" */
+  String get paddingBefore => getPropertyValue('padding-before');
+
+  /** Sets the value of "padding-before" */
+  set paddingBefore(String value) {
+    setProperty('padding-before', value, '');
+  }
+
+  /** Gets the value of "padding-bottom" */
+  String get paddingBottom => getPropertyValue('padding-bottom');
+
+  /** Sets the value of "padding-bottom" */
+  set paddingBottom(String value) {
+    setProperty('padding-bottom', value, '');
+  }
+
+  /** Gets the value of "padding-end" */
+  String get paddingEnd => getPropertyValue('padding-end');
+
+  /** Sets the value of "padding-end" */
+  set paddingEnd(String value) {
+    setProperty('padding-end', value, '');
+  }
+
+  /** Gets the value of "padding-left" */
+  String get paddingLeft => getPropertyValue('padding-left');
+
+  /** Sets the value of "padding-left" */
+  set paddingLeft(String value) {
+    setProperty('padding-left', value, '');
+  }
+
+  /** Gets the value of "padding-right" */
+  String get paddingRight => getPropertyValue('padding-right');
+
+  /** Sets the value of "padding-right" */
+  set paddingRight(String value) {
+    setProperty('padding-right', value, '');
+  }
+
+  /** Gets the value of "padding-start" */
+  String get paddingStart => getPropertyValue('padding-start');
+
+  /** Sets the value of "padding-start" */
+  set paddingStart(String value) {
+    setProperty('padding-start', value, '');
+  }
+
+  /** Gets the value of "padding-top" */
+  String get paddingTop => getPropertyValue('padding-top');
+
+  /** Sets the value of "padding-top" */
+  set paddingTop(String value) {
+    setProperty('padding-top', value, '');
+  }
+
+  /** Gets the value of "page" */
+  String get page => getPropertyValue('page');
+
+  /** Sets the value of "page" */
+  set page(String value) {
+    setProperty('page', value, '');
+  }
+
+  /** Gets the value of "page-break-after" */
+  String get pageBreakAfter => getPropertyValue('page-break-after');
+
+  /** Sets the value of "page-break-after" */
+  set pageBreakAfter(String value) {
+    setProperty('page-break-after', value, '');
+  }
+
+  /** Gets the value of "page-break-before" */
+  String get pageBreakBefore => getPropertyValue('page-break-before');
+
+  /** Sets the value of "page-break-before" */
+  set pageBreakBefore(String value) {
+    setProperty('page-break-before', value, '');
+  }
+
+  /** Gets the value of "page-break-inside" */
+  String get pageBreakInside => getPropertyValue('page-break-inside');
+
+  /** Sets the value of "page-break-inside" */
+  set pageBreakInside(String value) {
+    setProperty('page-break-inside', value, '');
+  }
+
+  /** Gets the value of "perspective" */
+  String get perspective => getPropertyValue('perspective');
+
+  /** Sets the value of "perspective" */
+  set perspective(String value) {
+    setProperty('perspective', value, '');
+  }
+
+  /** Gets the value of "perspective-origin" */
+  String get perspectiveOrigin => getPropertyValue('perspective-origin');
+
+  /** Sets the value of "perspective-origin" */
+  set perspectiveOrigin(String value) {
+    setProperty('perspective-origin', value, '');
+  }
+
+  /** Gets the value of "perspective-origin-x" */
+  String get perspectiveOriginX => getPropertyValue('perspective-origin-x');
+
+  /** Sets the value of "perspective-origin-x" */
+  set perspectiveOriginX(String value) {
+    setProperty('perspective-origin-x', value, '');
+  }
+
+  /** Gets the value of "perspective-origin-y" */
+  String get perspectiveOriginY => getPropertyValue('perspective-origin-y');
+
+  /** Sets the value of "perspective-origin-y" */
+  set perspectiveOriginY(String value) {
+    setProperty('perspective-origin-y', value, '');
+  }
+
+  /** Gets the value of "pointer-events" */
+  String get pointerEvents => getPropertyValue('pointer-events');
+
+  /** Sets the value of "pointer-events" */
+  set pointerEvents(String value) {
+    setProperty('pointer-events', value, '');
+  }
+
+  /** Gets the value of "position" */
+  String get position => getPropertyValue('position');
+
+  /** Sets the value of "position" */
+  set position(String value) {
+    setProperty('position', value, '');
+  }
+
+  /** Gets the value of "print-color-adjust" */
+  String get printColorAdjust => getPropertyValue('print-color-adjust');
+
+  /** Sets the value of "print-color-adjust" */
+  set printColorAdjust(String value) {
+    setProperty('print-color-adjust', value, '');
+  }
+
+  /** Gets the value of "quotes" */
+  String get quotes => getPropertyValue('quotes');
+
+  /** Sets the value of "quotes" */
+  set quotes(String value) {
+    setProperty('quotes', value, '');
+  }
+
+  /** Gets the value of "resize" */
+  String get resize => getPropertyValue('resize');
+
+  /** Sets the value of "resize" */
+  set resize(String value) {
+    setProperty('resize', value, '');
+  }
+
+  /** Gets the value of "right" */
+  String get right => getPropertyValue('right');
+
+  /** Sets the value of "right" */
+  set right(String value) {
+    setProperty('right', value, '');
+  }
+
+  /** Gets the value of "rtl-ordering" */
+  String get rtlOrdering => getPropertyValue('rtl-ordering');
+
+  /** Sets the value of "rtl-ordering" */
+  set rtlOrdering(String value) {
+    setProperty('rtl-ordering', value, '');
+  }
+
+  /** Gets the value of "ruby-position" */
+  String get rubyPosition => getPropertyValue('ruby-position');
+
+  /** Sets the value of "ruby-position" */
+  set rubyPosition(String value) {
+    setProperty('ruby-position', value, '');
+  }
+
+  /** Gets the value of "scroll-behavior" */
+  String get scrollBehavior => getPropertyValue('scroll-behavior');
+
+  /** Sets the value of "scroll-behavior" */
+  set scrollBehavior(String value) {
+    setProperty('scroll-behavior', value, '');
+  }
+
+  /** Gets the value of "shape-image-threshold" */
+  String get shapeImageThreshold => getPropertyValue('shape-image-threshold');
+
+  /** Sets the value of "shape-image-threshold" */
+  set shapeImageThreshold(String value) {
+    setProperty('shape-image-threshold', value, '');
+  }
+
+  /** Gets the value of "shape-margin" */
+  String get shapeMargin => getPropertyValue('shape-margin');
+
+  /** Sets the value of "shape-margin" */
+  set shapeMargin(String value) {
+    setProperty('shape-margin', value, '');
+  }
+
+  /** Gets the value of "shape-outside" */
+  String get shapeOutside => getPropertyValue('shape-outside');
+
+  /** Sets the value of "shape-outside" */
+  set shapeOutside(String value) {
+    setProperty('shape-outside', value, '');
+  }
+
+  /** Gets the value of "size" */
+  String get size => getPropertyValue('size');
+
+  /** Sets the value of "size" */
+  set size(String value) {
+    setProperty('size', value, '');
+  }
+
+  /** Gets the value of "speak" */
+  String get speak => getPropertyValue('speak');
+
+  /** Sets the value of "speak" */
+  set speak(String value) {
+    setProperty('speak', value, '');
+  }
+
+  /** Gets the value of "src" */
+  String get src => getPropertyValue('src');
+
+  /** Sets the value of "src" */
+  set src(String value) {
+    setProperty('src', value, '');
+  }
+
+  /** Gets the value of "tab-size" */
+  String get tabSize => getPropertyValue('tab-size');
+
+  /** Sets the value of "tab-size" */
+  set tabSize(String value) {
+    setProperty('tab-size', value, '');
+  }
+
+  /** Gets the value of "table-layout" */
+  String get tableLayout => getPropertyValue('table-layout');
+
+  /** Sets the value of "table-layout" */
+  set tableLayout(String value) {
+    setProperty('table-layout', value, '');
+  }
+
+  /** Gets the value of "tap-highlight-color" */
+  String get tapHighlightColor => getPropertyValue('tap-highlight-color');
+
+  /** Sets the value of "tap-highlight-color" */
+  set tapHighlightColor(String value) {
+    setProperty('tap-highlight-color', value, '');
+  }
+
+  /** Gets the value of "text-align" */
+  String get textAlign => getPropertyValue('text-align');
+
+  /** Sets the value of "text-align" */
+  set textAlign(String value) {
+    setProperty('text-align', value, '');
+  }
+
+  /** Gets the value of "text-align-last" */
+  String get textAlignLast => getPropertyValue('text-align-last');
+
+  /** Sets the value of "text-align-last" */
+  set textAlignLast(String value) {
+    setProperty('text-align-last', value, '');
+  }
+
+  /** Gets the value of "text-combine" */
+  String get textCombine => getPropertyValue('text-combine');
+
+  /** Sets the value of "text-combine" */
+  set textCombine(String value) {
+    setProperty('text-combine', value, '');
+  }
+
+  /** Gets the value of "text-decoration" */
+  String get textDecoration => getPropertyValue('text-decoration');
+
+  /** Sets the value of "text-decoration" */
+  set textDecoration(String value) {
+    setProperty('text-decoration', value, '');
+  }
+
+  /** Gets the value of "text-decoration-color" */
+  String get textDecorationColor => getPropertyValue('text-decoration-color');
+
+  /** Sets the value of "text-decoration-color" */
+  set textDecorationColor(String value) {
+    setProperty('text-decoration-color', value, '');
+  }
+
+  /** Gets the value of "text-decoration-line" */
+  String get textDecorationLine => getPropertyValue('text-decoration-line');
+
+  /** Sets the value of "text-decoration-line" */
+  set textDecorationLine(String value) {
+    setProperty('text-decoration-line', value, '');
+  }
+
+  /** Gets the value of "text-decoration-style" */
+  String get textDecorationStyle => getPropertyValue('text-decoration-style');
+
+  /** Sets the value of "text-decoration-style" */
+  set textDecorationStyle(String value) {
+    setProperty('text-decoration-style', value, '');
+  }
+
+  /** Gets the value of "text-decorations-in-effect" */
+  String get textDecorationsInEffect =>
+      getPropertyValue('text-decorations-in-effect');
+
+  /** Sets the value of "text-decorations-in-effect" */
+  set textDecorationsInEffect(String value) {
+    setProperty('text-decorations-in-effect', value, '');
+  }
+
+  /** Gets the value of "text-emphasis" */
+  String get textEmphasis => getPropertyValue('text-emphasis');
+
+  /** Sets the value of "text-emphasis" */
+  set textEmphasis(String value) {
+    setProperty('text-emphasis', value, '');
+  }
+
+  /** Gets the value of "text-emphasis-color" */
+  String get textEmphasisColor => getPropertyValue('text-emphasis-color');
+
+  /** Sets the value of "text-emphasis-color" */
+  set textEmphasisColor(String value) {
+    setProperty('text-emphasis-color', value, '');
+  }
+
+  /** Gets the value of "text-emphasis-position" */
+  String get textEmphasisPosition => getPropertyValue('text-emphasis-position');
+
+  /** Sets the value of "text-emphasis-position" */
+  set textEmphasisPosition(String value) {
+    setProperty('text-emphasis-position', value, '');
+  }
+
+  /** Gets the value of "text-emphasis-style" */
+  String get textEmphasisStyle => getPropertyValue('text-emphasis-style');
+
+  /** Sets the value of "text-emphasis-style" */
+  set textEmphasisStyle(String value) {
+    setProperty('text-emphasis-style', value, '');
+  }
+
+  /** Gets the value of "text-fill-color" */
+  String get textFillColor => getPropertyValue('text-fill-color');
+
+  /** Sets the value of "text-fill-color" */
+  set textFillColor(String value) {
+    setProperty('text-fill-color', value, '');
+  }
+
+  /** Gets the value of "text-indent" */
+  String get textIndent => getPropertyValue('text-indent');
+
+  /** Sets the value of "text-indent" */
+  set textIndent(String value) {
+    setProperty('text-indent', value, '');
+  }
+
+  /** Gets the value of "text-justify" */
+  String get textJustify => getPropertyValue('text-justify');
+
+  /** Sets the value of "text-justify" */
+  set textJustify(String value) {
+    setProperty('text-justify', value, '');
+  }
+
+  /** Gets the value of "text-line-through-color" */
+  String get textLineThroughColor =>
+      getPropertyValue('text-line-through-color');
+
+  /** Sets the value of "text-line-through-color" */
+  set textLineThroughColor(String value) {
+    setProperty('text-line-through-color', value, '');
+  }
+
+  /** Gets the value of "text-line-through-mode" */
+  String get textLineThroughMode => getPropertyValue('text-line-through-mode');
+
+  /** Sets the value of "text-line-through-mode" */
+  set textLineThroughMode(String value) {
+    setProperty('text-line-through-mode', value, '');
+  }
+
+  /** Gets the value of "text-line-through-style" */
+  String get textLineThroughStyle =>
+      getPropertyValue('text-line-through-style');
+
+  /** Sets the value of "text-line-through-style" */
+  set textLineThroughStyle(String value) {
+    setProperty('text-line-through-style', value, '');
+  }
+
+  /** Gets the value of "text-line-through-width" */
+  String get textLineThroughWidth =>
+      getPropertyValue('text-line-through-width');
+
+  /** Sets the value of "text-line-through-width" */
+  set textLineThroughWidth(String value) {
+    setProperty('text-line-through-width', value, '');
+  }
+
+  /** Gets the value of "text-orientation" */
+  String get textOrientation => getPropertyValue('text-orientation');
+
+  /** Sets the value of "text-orientation" */
+  set textOrientation(String value) {
+    setProperty('text-orientation', value, '');
+  }
+
+  /** Gets the value of "text-overflow" */
+  String get textOverflow => getPropertyValue('text-overflow');
+
+  /** Sets the value of "text-overflow" */
+  set textOverflow(String value) {
+    setProperty('text-overflow', value, '');
+  }
+
+  /** Gets the value of "text-overline-color" */
+  String get textOverlineColor => getPropertyValue('text-overline-color');
+
+  /** Sets the value of "text-overline-color" */
+  set textOverlineColor(String value) {
+    setProperty('text-overline-color', value, '');
+  }
+
+  /** Gets the value of "text-overline-mode" */
+  String get textOverlineMode => getPropertyValue('text-overline-mode');
+
+  /** Sets the value of "text-overline-mode" */
+  set textOverlineMode(String value) {
+    setProperty('text-overline-mode', value, '');
+  }
+
+  /** Gets the value of "text-overline-style" */
+  String get textOverlineStyle => getPropertyValue('text-overline-style');
+
+  /** Sets the value of "text-overline-style" */
+  set textOverlineStyle(String value) {
+    setProperty('text-overline-style', value, '');
+  }
+
+  /** Gets the value of "text-overline-width" */
+  String get textOverlineWidth => getPropertyValue('text-overline-width');
+
+  /** Sets the value of "text-overline-width" */
+  set textOverlineWidth(String value) {
+    setProperty('text-overline-width', value, '');
+  }
+
+  /** Gets the value of "text-rendering" */
+  String get textRendering => getPropertyValue('text-rendering');
+
+  /** Sets the value of "text-rendering" */
+  set textRendering(String value) {
+    setProperty('text-rendering', value, '');
+  }
+
+  /** Gets the value of "text-security" */
+  String get textSecurity => getPropertyValue('text-security');
+
+  /** Sets the value of "text-security" */
+  set textSecurity(String value) {
+    setProperty('text-security', value, '');
+  }
+
+  /** Gets the value of "text-shadow" */
+  String get textShadow => getPropertyValue('text-shadow');
+
+  /** Sets the value of "text-shadow" */
+  set textShadow(String value) {
+    setProperty('text-shadow', value, '');
+  }
+
+  /** Gets the value of "text-stroke" */
+  String get textStroke => getPropertyValue('text-stroke');
+
+  /** Sets the value of "text-stroke" */
+  set textStroke(String value) {
+    setProperty('text-stroke', value, '');
+  }
+
+  /** Gets the value of "text-stroke-color" */
+  String get textStrokeColor => getPropertyValue('text-stroke-color');
+
+  /** Sets the value of "text-stroke-color" */
+  set textStrokeColor(String value) {
+    setProperty('text-stroke-color', value, '');
+  }
+
+  /** Gets the value of "text-stroke-width" */
+  String get textStrokeWidth => getPropertyValue('text-stroke-width');
+
+  /** Sets the value of "text-stroke-width" */
+  set textStrokeWidth(String value) {
+    setProperty('text-stroke-width', value, '');
+  }
+
+  /** Gets the value of "text-transform" */
+  String get textTransform => getPropertyValue('text-transform');
+
+  /** Sets the value of "text-transform" */
+  set textTransform(String value) {
+    setProperty('text-transform', value, '');
+  }
+
+  /** Gets the value of "text-underline-color" */
+  String get textUnderlineColor => getPropertyValue('text-underline-color');
+
+  /** Sets the value of "text-underline-color" */
+  set textUnderlineColor(String value) {
+    setProperty('text-underline-color', value, '');
+  }
+
+  /** Gets the value of "text-underline-mode" */
+  String get textUnderlineMode => getPropertyValue('text-underline-mode');
+
+  /** Sets the value of "text-underline-mode" */
+  set textUnderlineMode(String value) {
+    setProperty('text-underline-mode', value, '');
+  }
+
+  /** Gets the value of "text-underline-position" */
+  String get textUnderlinePosition =>
+      getPropertyValue('text-underline-position');
+
+  /** Sets the value of "text-underline-position" */
+  set textUnderlinePosition(String value) {
+    setProperty('text-underline-position', value, '');
+  }
+
+  /** Gets the value of "text-underline-style" */
+  String get textUnderlineStyle => getPropertyValue('text-underline-style');
+
+  /** Sets the value of "text-underline-style" */
+  set textUnderlineStyle(String value) {
+    setProperty('text-underline-style', value, '');
+  }
+
+  /** Gets the value of "text-underline-width" */
+  String get textUnderlineWidth => getPropertyValue('text-underline-width');
+
+  /** Sets the value of "text-underline-width" */
+  set textUnderlineWidth(String value) {
+    setProperty('text-underline-width', value, '');
+  }
+
+  /** Gets the value of "top" */
+  String get top => getPropertyValue('top');
+
+  /** Sets the value of "top" */
+  set top(String value) {
+    setProperty('top', value, '');
+  }
+
+  /** Gets the value of "touch-action" */
+  String get touchAction => getPropertyValue('touch-action');
+
+  /** Sets the value of "touch-action" */
+  set touchAction(String value) {
+    setProperty('touch-action', value, '');
+  }
+
+  /** Gets the value of "touch-action-delay" */
+  String get touchActionDelay => getPropertyValue('touch-action-delay');
+
+  /** Sets the value of "touch-action-delay" */
+  set touchActionDelay(String value) {
+    setProperty('touch-action-delay', value, '');
+  }
+
+  /** Gets the value of "transform" */
+  String get transform => getPropertyValue('transform');
+
+  /** Sets the value of "transform" */
+  set transform(String value) {
+    setProperty('transform', value, '');
+  }
+
+  /** Gets the value of "transform-origin" */
+  String get transformOrigin => getPropertyValue('transform-origin');
+
+  /** Sets the value of "transform-origin" */
+  set transformOrigin(String value) {
+    setProperty('transform-origin', value, '');
+  }
+
+  /** Gets the value of "transform-origin-x" */
+  String get transformOriginX => getPropertyValue('transform-origin-x');
+
+  /** Sets the value of "transform-origin-x" */
+  set transformOriginX(String value) {
+    setProperty('transform-origin-x', value, '');
+  }
+
+  /** Gets the value of "transform-origin-y" */
+  String get transformOriginY => getPropertyValue('transform-origin-y');
+
+  /** Sets the value of "transform-origin-y" */
+  set transformOriginY(String value) {
+    setProperty('transform-origin-y', value, '');
+  }
+
+  /** Gets the value of "transform-origin-z" */
+  String get transformOriginZ => getPropertyValue('transform-origin-z');
+
+  /** Sets the value of "transform-origin-z" */
+  set transformOriginZ(String value) {
+    setProperty('transform-origin-z', value, '');
+  }
+
+  /** Gets the value of "transform-style" */
+  String get transformStyle => getPropertyValue('transform-style');
+
+  /** Sets the value of "transform-style" */
+  set transformStyle(String value) {
+    setProperty('transform-style', value, '');
+  }
+
+  /** Gets the value of "transition" */ @SupportedBrowser(
+      SupportedBrowser.CHROME)
+  @SupportedBrowser(SupportedBrowser.FIREFOX)
+  @SupportedBrowser(SupportedBrowser.IE, '10')
+  @SupportedBrowser(SupportedBrowser.SAFARI)
+  String get transition => getPropertyValue('transition');
+
+  /** Sets the value of "transition" */ @SupportedBrowser(
+      SupportedBrowser.CHROME)
+  @SupportedBrowser(SupportedBrowser.FIREFOX)
+  @SupportedBrowser(SupportedBrowser.IE, '10')
+  @SupportedBrowser(SupportedBrowser.SAFARI)
+  set transition(String value) {
+    setProperty('transition', value, '');
+  }
+
+  /** Gets the value of "transition-delay" */
+  String get transitionDelay => getPropertyValue('transition-delay');
+
+  /** Sets the value of "transition-delay" */
+  set transitionDelay(String value) {
+    setProperty('transition-delay', value, '');
+  }
+
+  /** Gets the value of "transition-duration" */
+  String get transitionDuration => getPropertyValue('transition-duration');
+
+  /** Sets the value of "transition-duration" */
+  set transitionDuration(String value) {
+    setProperty('transition-duration', value, '');
+  }
+
+  /** Gets the value of "transition-property" */
+  String get transitionProperty => getPropertyValue('transition-property');
+
+  /** Sets the value of "transition-property" */
+  set transitionProperty(String value) {
+    setProperty('transition-property', value, '');
+  }
+
+  /** Gets the value of "transition-timing-function" */
+  String get transitionTimingFunction =>
+      getPropertyValue('transition-timing-function');
+
+  /** Sets the value of "transition-timing-function" */
+  set transitionTimingFunction(String value) {
+    setProperty('transition-timing-function', value, '');
+  }
+
+  /** Gets the value of "unicode-bidi" */
+  String get unicodeBidi => getPropertyValue('unicode-bidi');
+
+  /** Sets the value of "unicode-bidi" */
+  set unicodeBidi(String value) {
+    setProperty('unicode-bidi', value, '');
+  }
+
+  /** Gets the value of "unicode-range" */
+  String get unicodeRange => getPropertyValue('unicode-range');
+
+  /** Sets the value of "unicode-range" */
+  set unicodeRange(String value) {
+    setProperty('unicode-range', value, '');
+  }
+
+  /** Gets the value of "user-drag" */
+  String get userDrag => getPropertyValue('user-drag');
+
+  /** Sets the value of "user-drag" */
+  set userDrag(String value) {
+    setProperty('user-drag', value, '');
+  }
+
+  /** Gets the value of "user-modify" */
+  String get userModify => getPropertyValue('user-modify');
+
+  /** Sets the value of "user-modify" */
+  set userModify(String value) {
+    setProperty('user-modify', value, '');
+  }
+
+  /** Gets the value of "user-select" */
+  String get userSelect => getPropertyValue('user-select');
+
+  /** Sets the value of "user-select" */
+  set userSelect(String value) {
+    setProperty('user-select', value, '');
+  }
+
+  /** Gets the value of "user-zoom" */
+  String get userZoom => getPropertyValue('user-zoom');
+
+  /** Sets the value of "user-zoom" */
+  set userZoom(String value) {
+    setProperty('user-zoom', value, '');
+  }
+
+  /** Gets the value of "vertical-align" */
+  String get verticalAlign => getPropertyValue('vertical-align');
+
+  /** Sets the value of "vertical-align" */
+  set verticalAlign(String value) {
+    setProperty('vertical-align', value, '');
+  }
+
+  /** Gets the value of "visibility" */
+  String get visibility => getPropertyValue('visibility');
+
+  /** Sets the value of "visibility" */
+  set visibility(String value) {
+    setProperty('visibility', value, '');
+  }
+
+  /** Gets the value of "white-space" */
+  String get whiteSpace => getPropertyValue('white-space');
+
+  /** Sets the value of "white-space" */
+  set whiteSpace(String value) {
+    setProperty('white-space', value, '');
+  }
+
+  /** Gets the value of "widows" */
+  String get widows => getPropertyValue('widows');
+
+  /** Sets the value of "widows" */
+  set widows(String value) {
+    setProperty('widows', value, '');
+  }
+
+  /** Gets the value of "width" */
+  String get width => getPropertyValue('width');
+
+  /** Sets the value of "width" */
+  set width(String value) {
+    setProperty('width', value, '');
+  }
+
+  /** Gets the value of "will-change" */
+  String get willChange => getPropertyValue('will-change');
+
+  /** Sets the value of "will-change" */
+  set willChange(String value) {
+    setProperty('will-change', value, '');
+  }
+
+  /** Gets the value of "word-break" */
+  String get wordBreak => getPropertyValue('word-break');
+
+  /** Sets the value of "word-break" */
+  set wordBreak(String value) {
+    setProperty('word-break', value, '');
+  }
+
+  /** Gets the value of "word-spacing" */
+  String get wordSpacing => getPropertyValue('word-spacing');
+
+  /** Sets the value of "word-spacing" */
+  set wordSpacing(String value) {
+    setProperty('word-spacing', value, '');
+  }
+
+  /** Gets the value of "word-wrap" */
+  String get wordWrap => getPropertyValue('word-wrap');
+
+  /** Sets the value of "word-wrap" */
+  set wordWrap(String value) {
+    setProperty('word-wrap', value, '');
+  }
+
+  /** Gets the value of "wrap-flow" */
+  String get wrapFlow => getPropertyValue('wrap-flow');
+
+  /** Sets the value of "wrap-flow" */
+  set wrapFlow(String value) {
+    setProperty('wrap-flow', value, '');
+  }
+
+  /** Gets the value of "wrap-through" */
+  String get wrapThrough => getPropertyValue('wrap-through');
+
+  /** Sets the value of "wrap-through" */
+  set wrapThrough(String value) {
+    setProperty('wrap-through', value, '');
+  }
+
+  /** Gets the value of "writing-mode" */
+  String get writingMode => getPropertyValue('writing-mode');
+
+  /** Sets the value of "writing-mode" */
+  set writingMode(String value) {
+    setProperty('writing-mode', value, '');
+  }
+
+  /** Gets the value of "z-index" */
+  String get zIndex => getPropertyValue('z-index');
+
+  /** Sets the value of "z-index" */
+  set zIndex(String value) {
+    setProperty('z-index', value, '');
+  }
+
+  /** Gets the value of "zoom" */
+  String get zoom => getPropertyValue('zoom');
+
+  /** Sets the value of "zoom" */
+  set zoom(String value) {
+    setProperty('zoom', value, '');
+  }
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("CSSStyleRule")
+class CssStyleRule extends CssRule {
+  // To suppress missing implicit constructor warnings.
+  factory CssStyleRule._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  String selectorText;
+
+  final CssStyleDeclaration style;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("CSSStyleSheet")
+class CssStyleSheet extends StyleSheet {
+  // To suppress missing implicit constructor warnings.
+  factory CssStyleSheet._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  @Returns('_CssRuleList|Null')
+  @Creates('_CssRuleList')
+  final List<CssRule> cssRules;
+
+  final CssRule ownerRule;
+
+  @Returns('_CssRuleList|Null')
+  @Creates('_CssRuleList')
+  final List<CssRule> rules;
+
+  int addRule(String selector, String style, [int index]) native;
+
+  void deleteRule(int index) native;
+
+  int insertRule(String rule, [int index]) native;
+
+  void removeRule(int index) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("CSSStyleValue")
+class CssStyleValue extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory CssStyleValue._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  static Object parse(String property, String cssText) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("CSSSupportsRule")
+class CssSupportsRule extends CssConditionRule {
+  // To suppress missing implicit constructor warnings.
+  factory CssSupportsRule._() {
+    throw new UnsupportedError("Not supported");
+  }
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("CSSTransformComponent")
+class CssTransformComponent extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory CssTransformComponent._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  bool is2D;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("CSSTransformValue")
+class CssTransformValue extends CssStyleValue {
+  // To suppress missing implicit constructor warnings.
+  factory CssTransformValue._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory CssTransformValue([List<CssTransformComponent> transformComponents]) {
+    if (transformComponents == null) {
+      return CssTransformValue._create_1();
+    }
+    if ((transformComponents is List<CssTransformComponent>)) {
+      return CssTransformValue._create_2(transformComponents);
+    }
+    throw new ArgumentError("Incorrect number or type of arguments");
+  }
+  static CssTransformValue _create_1() =>
+      JS('CssTransformValue', 'new CSSTransformValue()');
+  static CssTransformValue _create_2(transformComponents) =>
+      JS('CssTransformValue', 'new CSSTransformValue(#)', transformComponents);
+
+  final bool is2D;
+
+  final int length;
+
+  CssTransformComponent componentAtIndex(int index) native;
+
+  DomMatrix toMatrix() native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("CSSTranslation")
+class CssTranslation extends CssTransformComponent {
+  // To suppress missing implicit constructor warnings.
+  factory CssTranslation._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory CssTranslation(CssNumericValue x, CssNumericValue y,
+      [CssNumericValue z]) {
+    if ((y is CssNumericValue) && (x is CssNumericValue) && z == null) {
+      return CssTranslation._create_1(x, y);
+    }
+    if ((z is CssNumericValue) &&
+        (y is CssNumericValue) &&
+        (x is CssNumericValue)) {
+      return CssTranslation._create_2(x, y, z);
+    }
+    throw new ArgumentError("Incorrect number or type of arguments");
+  }
+  static CssTranslation _create_1(x, y) =>
+      JS('CssTranslation', 'new CSSTranslation(#,#)', x, y);
+  static CssTranslation _create_2(x, y, z) =>
+      JS('CssTranslation', 'new CSSTranslation(#,#,#)', x, y, z);
+
+  CssNumericValue x;
+
+  CssNumericValue y;
+
+  CssNumericValue z;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("CSSUnitValue")
+class CssUnitValue extends CssNumericValue {
+  // To suppress missing implicit constructor warnings.
+  factory CssUnitValue._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory CssUnitValue(num value, String unit) {
+    return CssUnitValue._create_1(value, unit);
+  }
+  static CssUnitValue _create_1(value, unit) =>
+      JS('CssUnitValue', 'new CSSUnitValue(#,#)', value, unit);
+
+  final String type;
+
+  String unit;
+
+  num value;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("CSSUnparsedValue")
+class CssUnparsedValue extends CssStyleValue {
+  // To suppress missing implicit constructor warnings.
+  factory CssUnparsedValue._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final int length;
+
+  Object fragmentAtIndex(int index) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("CSSVariableReferenceValue")
+class CssVariableReferenceValue extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory CssVariableReferenceValue._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final CssUnparsedValue fallback;
+
+  final String variable;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("CSSViewportRule")
+class CssViewportRule extends CssRule {
+  // To suppress missing implicit constructor warnings.
+  factory CssViewportRule._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final CssStyleDeclaration style;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("CSSURLImageValue")
+class CssurlImageValue extends CssImageValue {
+  // To suppress missing implicit constructor warnings.
+  factory CssurlImageValue._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory CssurlImageValue(String url) {
+    return CssurlImageValue._create_1(url);
+  }
+  static CssurlImageValue _create_1(url) =>
+      JS('CssurlImageValue', 'new CSSURLImageValue(#)', url);
+
+  final String url;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+// https://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/custom/index.html#dfn-custom-element-constructor-generation
+@deprecated // experimental
+typedef void CustomElementConstructor();
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("CustomElementRegistry")
+class CustomElementRegistry extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory CustomElementRegistry._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  void define(String name, Object constructor, [Map options]) {
+    if (options != null) {
+      var options_1 = convertDartToNative_Dictionary(options);
+      _define_1(name, constructor, options_1);
+      return;
+    }
+    _define_2(name, constructor);
+    return;
+  }
+
+  @JSName('define')
+  void _define_1(name, constructor, options) native;
+  @JSName('define')
+  void _define_2(name, constructor) native;
+
+  Object get(String name) native;
+
+  Future whenDefined(String name) =>
+      promiseToFuture(JS("", "#.whenDefined(#)", this, name));
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+@Native("CustomEvent")
+class CustomEvent extends Event {
+  @Creates('Null') // Set from Dart code; does not instantiate a native type.
+  var _dartDetail;
+
+  factory CustomEvent(String type,
+      {bool canBubble: true, bool cancelable: true, Object detail}) {
+    final CustomEvent e = document._createEvent('CustomEvent');
+
+    e._dartDetail = detail;
+
+    // Only try setting the detail if it's one of these types to avoid
+    // first-chance exceptions. Can expand this list in the future as needed.
+    if (detail is List || detail is Map || detail is String || detail is num) {
+      try {
+        detail = convertDartToNative_SerializedScriptValue(detail);
+        e._initCustomEvent(type, canBubble, cancelable, detail);
+      } catch (_) {
+        e._initCustomEvent(type, canBubble, cancelable, null);
+      }
+    } else {
+      e._initCustomEvent(type, canBubble, cancelable, null);
+    }
+
+    return e;
+  }
+
+  get detail {
+    if (_dartDetail != null) {
+      return _dartDetail;
+    }
+    return _detail;
+  }
+
+  factory CustomEvent._(String type, [Map eventInitDict]) {
+    if (eventInitDict != null) {
+      var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+      return CustomEvent._create_1(type, eventInitDict_1);
+    }
+    return CustomEvent._create_2(type);
+  }
+  static CustomEvent _create_1(type, eventInitDict) =>
+      JS('CustomEvent', 'new CustomEvent(#,#)', type, eventInitDict);
+  static CustomEvent _create_2(type) =>
+      JS('CustomEvent', 'new CustomEvent(#)', type);
+
+  dynamic get _detail =>
+      convertNativeToDart_SerializedScriptValue(this._get__detail);
+  @JSName('detail')
+  @Creates('Null')
+  final dynamic _get__detail;
+
+  @JSName('initCustomEvent')
+  void _initCustomEvent(String type,
+      [bool bubbles, bool cancelable, Object detail]) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("HTMLDListElement")
+class DListElement extends HtmlElement {
+  // To suppress missing implicit constructor warnings.
+  factory DListElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory DListElement() => JS(
+      'returns:DListElement;creates:DListElement;new:true',
+      '#.createElement(#)',
+      document,
+      "dl");
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  DListElement.created() : super.created();
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("HTMLDataElement")
+class DataElement extends HtmlElement {
+  // To suppress missing implicit constructor warnings.
+  factory DataElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  DataElement.created() : super.created();
+
+  String value;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.FIREFOX)
+@SupportedBrowser(SupportedBrowser.IE, '10')
+@SupportedBrowser(SupportedBrowser.SAFARI)
+@Native("HTMLDataListElement")
+class DataListElement extends HtmlElement {
+  // To suppress missing implicit constructor warnings.
+  factory DataListElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory DataListElement() => document.createElement("datalist");
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  DataListElement.created() : super.created();
+
+  /// Checks if this type is supported on the current platform.
+  static bool get supported => Element.isTagSupported('datalist');
+
+  @Returns('HtmlCollection|Null')
+  @Creates('HtmlCollection')
+  final List<Node> options;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("DataTransfer")
+class DataTransfer extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory DataTransfer._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory DataTransfer() {
+    return DataTransfer._create_1();
+  }
+  static DataTransfer _create_1() => JS('DataTransfer', 'new DataTransfer()');
+
+  String dropEffect;
+
+  String effectAllowed;
+
+  @Returns('FileList|Null')
+  @Creates('FileList')
+  final List<File> files;
+
+  final DataTransferItemList items;
+
+  final List<String> types;
+
+  void clearData([String format]) native;
+
+  String getData(String format) native;
+
+  void setData(String format, String data) native;
+
+  void setDragImage(Element image, int x, int y) native;
+}
+// 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.
+
+@Native("DataTransferItem")
+class DataTransferItem extends Interceptor {
+  Entry getAsEntry() {
+    Entry entry = _webkitGetAsEntry();
+
+    if (entry.isFile)
+      applyExtension('FileEntry', entry);
+    else if (entry.isDirectory)
+      applyExtension('DirectoryEntry', entry);
+    else
+      applyExtension('Entry', entry);
+
+    return entry;
+  }
+
+  // To suppress missing implicit constructor warnings.
+  factory DataTransferItem._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final String kind;
+
+  final String type;
+
+  File getAsFile() native;
+
+  @JSName('webkitGetAsEntry')
+  @SupportedBrowser(SupportedBrowser.CHROME)
+  @SupportedBrowser(SupportedBrowser.SAFARI)
+  Entry _webkitGetAsEntry() native;
+}
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("DataTransferItemList")
+class DataTransferItemList extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory DataTransferItemList._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final int length;
+
+  DataTransferItem add(data_OR_file, [String type]) native;
+
+  @JSName('add')
+  DataTransferItem addData(String data, String type) native;
+
+  @JSName('add')
+  DataTransferItem addFile(File file) native;
+
+  void clear() native;
+
+  DataTransferItem item(int index) native;
+
+  void remove(int index) native;
+
+  DataTransferItem operator [](int index) {
+    return JS('DataTransferItem', '#[#]', this, index);
+  }
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+typedef void DatabaseCallback(SqlDatabase database);
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+typedef void DecodeErrorCallback(DomException error);
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+typedef void DecodeSuccessCallback(AudioBuffer decodedData);
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("DedicatedWorkerGlobalScope")
+class DedicatedWorkerGlobalScope extends WorkerGlobalScope {
+  // To suppress missing implicit constructor warnings.
+  factory DedicatedWorkerGlobalScope._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  /**
+   * Static factory designed to expose `message` events to event
+   * handlers that are not necessarily instances of [DedicatedWorkerGlobalScope].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<MessageEvent> messageEvent =
+      const EventStreamProvider<MessageEvent>('message');
+
+  static const int PERSISTENT = 1;
+
+  static const int TEMPORARY = 0;
+
+  void close() native;
+
+  void postMessage(/*any*/ message, [List<Object> transfer]) {
+    if (transfer != null) {
+      var message_1 = convertDartToNative_SerializedScriptValue(message);
+      _postMessage_1(message_1, transfer);
+      return;
+    }
+    var message_1 = convertDartToNative_SerializedScriptValue(message);
+    _postMessage_2(message_1);
+    return;
+  }
+
+  @JSName('postMessage')
+  void _postMessage_1(message, List<Object> transfer) native;
+  @JSName('postMessage')
+  void _postMessage_2(message) native;
+
+  @JSName('webkitRequestFileSystem')
+  @SupportedBrowser(SupportedBrowser.CHROME)
+  @SupportedBrowser(SupportedBrowser.SAFARI)
+  void _webkitRequestFileSystem(int type, int size,
+      [_FileSystemCallback successCallback,
+      _ErrorCallback errorCallback]) native;
+
+  @JSName('webkitRequestFileSystemSync')
+  @SupportedBrowser(SupportedBrowser.CHROME)
+  @SupportedBrowser(SupportedBrowser.SAFARI)
+  _DOMFileSystemSync requestFileSystemSync(int type, int size) native;
+
+  @JSName('webkitResolveLocalFileSystemSyncURL')
+  @SupportedBrowser(SupportedBrowser.CHROME)
+  @SupportedBrowser(SupportedBrowser.SAFARI)
+  _EntrySync resolveLocalFileSystemSyncUrl(String url) native;
+
+  @JSName('webkitResolveLocalFileSystemURL')
+  @SupportedBrowser(SupportedBrowser.CHROME)
+  @SupportedBrowser(SupportedBrowser.SAFARI)
+  void _webkitResolveLocalFileSystemUrl(
+      String url, _EntryCallback successCallback,
+      [_ErrorCallback errorCallback]) native;
+
+  /// Stream of `message` events handled by this [DedicatedWorkerGlobalScope].
+  Stream<MessageEvent> get onMessage => messageEvent.forTarget(this);
+
+  static DedicatedWorkerGlobalScope get instance {
+    return _workerSelf as DedicatedWorkerGlobalScope;
+  }
+}
+
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("DeprecatedStorageInfo")
+class DeprecatedStorageInfo extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory DeprecatedStorageInfo._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  static const int PERSISTENT = 1;
+
+  static const int TEMPORARY = 0;
+
+  void queryUsageAndQuota(int storageType,
+      [StorageUsageCallback usageCallback,
+      StorageErrorCallback errorCallback]) native;
+
+  void requestQuota(int storageType, int newQuotaInBytes,
+      [StorageQuotaCallback quotaCallback,
+      StorageErrorCallback errorCallback]) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("DeprecatedStorageQuota")
+class DeprecatedStorageQuota extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory DeprecatedStorageQuota._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  void queryUsageAndQuota(StorageUsageCallback usageCallback,
+      [StorageErrorCallback errorCallback]) native;
+
+  void requestQuota(int newQuotaInBytes,
+      [StorageQuotaCallback quotaCallback,
+      StorageErrorCallback errorCallback]) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("DeprecationReport")
+class DeprecationReport extends ReportBody {
+  // To suppress missing implicit constructor warnings.
+  factory DeprecationReport._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final int lineNumber;
+
+  final String message;
+
+  final String sourceFile;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.SAFARI)
+@Native("HTMLDetailsElement")
+class DetailsElement extends HtmlElement {
+  // To suppress missing implicit constructor warnings.
+  factory DetailsElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory DetailsElement() => document.createElement("details");
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  DetailsElement.created() : super.created();
+
+  /// Checks if this type is supported on the current platform.
+  static bool get supported => Element.isTagSupported('details');
+
+  bool open;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("DetectedBarcode")
+class DetectedBarcode extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory DetectedBarcode._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory DetectedBarcode() {
+    return DetectedBarcode._create_1();
+  }
+  static DetectedBarcode _create_1() =>
+      JS('DetectedBarcode', 'new DetectedBarcode()');
+
+  final Rectangle boundingBox;
+
+  final List cornerPoints;
+
+  final String rawValue;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("DetectedFace")
+class DetectedFace extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory DetectedFace._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory DetectedFace() {
+    return DetectedFace._create_1();
+  }
+  static DetectedFace _create_1() => JS('DetectedFace', 'new DetectedFace()');
+
+  final Rectangle boundingBox;
+
+  final List landmarks;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("DetectedText")
+class DetectedText extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory DetectedText._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory DetectedText() {
+    return DetectedText._create_1();
+  }
+  static DetectedText _create_1() => JS('DetectedText', 'new DetectedText()');
+
+  final Rectangle boundingBox;
+
+  final List cornerPoints;
+
+  final String rawValue;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("DeviceAcceleration")
+class DeviceAcceleration extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory DeviceAcceleration._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final num x;
+
+  final num y;
+
+  final num z;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("DeviceMotionEvent")
+class DeviceMotionEvent extends Event {
+  // To suppress missing implicit constructor warnings.
+  factory DeviceMotionEvent._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory DeviceMotionEvent(String type, [Map eventInitDict]) {
+    if (eventInitDict != null) {
+      var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+      return DeviceMotionEvent._create_1(type, eventInitDict_1);
+    }
+    return DeviceMotionEvent._create_2(type);
+  }
+  static DeviceMotionEvent _create_1(type, eventInitDict) => JS(
+      'DeviceMotionEvent', 'new DeviceMotionEvent(#,#)', type, eventInitDict);
+  static DeviceMotionEvent _create_2(type) =>
+      JS('DeviceMotionEvent', 'new DeviceMotionEvent(#)', type);
+
+  final DeviceAcceleration acceleration;
+
+  final DeviceAcceleration accelerationIncludingGravity;
+
+  final num interval;
+
+  final DeviceRotationRate rotationRate;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("DeviceOrientationEvent")
+class DeviceOrientationEvent extends Event {
+  // To suppress missing implicit constructor warnings.
+  factory DeviceOrientationEvent._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory DeviceOrientationEvent(String type, [Map eventInitDict]) {
+    if (eventInitDict != null) {
+      var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+      return DeviceOrientationEvent._create_1(type, eventInitDict_1);
+    }
+    return DeviceOrientationEvent._create_2(type);
+  }
+  static DeviceOrientationEvent _create_1(type, eventInitDict) => JS(
+      'DeviceOrientationEvent',
+      'new DeviceOrientationEvent(#,#)',
+      type,
+      eventInitDict);
+  static DeviceOrientationEvent _create_2(type) =>
+      JS('DeviceOrientationEvent', 'new DeviceOrientationEvent(#)', type);
+
+  final bool absolute;
+
+  final num alpha;
+
+  final num beta;
+
+  final num gamma;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("DeviceRotationRate")
+class DeviceRotationRate extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory DeviceRotationRate._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final num alpha;
+
+  final num beta;
+
+  final num gamma;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("HTMLDialogElement")
+class DialogElement extends HtmlElement {
+  // To suppress missing implicit constructor warnings.
+  factory DialogElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  DialogElement.created() : super.created();
+
+  bool open;
+
+  String returnValue;
+
+  void close([String returnValue]) native;
+
+  void show() native;
+
+  void showModal() native;
+}
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("DirectoryEntry")
+class DirectoryEntry extends Entry {
+  /**
+   * Create a new directory with the specified `path`. If `exclusive` is true,
+   * the returned Future will complete with an error if a directory already
+   * exists with the specified `path`.
+   */
+  Future<Entry> createDirectory(String path, {bool exclusive: false}) {
+    return _getDirectory(path,
+        options: {'create': true, 'exclusive': exclusive});
+  }
+
+  DirectoryReader createReader() {
+    DirectoryReader reader = _createReader();
+    applyExtension('DirectoryReader', reader);
+    return reader;
+  }
+
+  /**
+   * Retrieve an already existing directory entry. The returned future will
+   * result in an error if a directory at `path` does not exist or if the item
+   * at `path` is not a directory.
+   */
+  Future<Entry> getDirectory(String path) {
+    return _getDirectory(path);
+  }
+
+  /**
+   * Create a new file with the specified `path`. If `exclusive` is true,
+   * the returned Future will complete with an error if a file already
+   * exists at the specified `path`.
+   */
+  Future<Entry> createFile(String path, {bool exclusive: false}) {
+    return _getFile(path, options: {'create': true, 'exclusive': exclusive});
+  }
+
+  /**
+   * Retrieve an already existing file entry. The returned future will
+   * result in an error if a file at `path` does not exist or if the item at
+   * `path` is not a file.
+   */
+  Future<Entry> getFile(String path) {
+    return _getFile(path);
+  }
+
+  // To suppress missing implicit constructor warnings.
+  factory DirectoryEntry._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  @JSName('createReader')
+  DirectoryReader _createReader() native;
+
+  void __getDirectory(String path,
+      [Map options,
+      _EntryCallback successCallback,
+      _ErrorCallback errorCallback]) {
+    if (errorCallback != null) {
+      var options_1 = convertDartToNative_Dictionary(options);
+      __getDirectory_1(path, options_1, successCallback, errorCallback);
+      return;
+    }
+    if (successCallback != null) {
+      var options_1 = convertDartToNative_Dictionary(options);
+      __getDirectory_2(path, options_1, successCallback);
+      return;
+    }
+    if (options != null) {
+      var options_1 = convertDartToNative_Dictionary(options);
+      __getDirectory_3(path, options_1);
+      return;
+    }
+    __getDirectory_4(path);
+    return;
+  }
+
+  @JSName('getDirectory')
+  void __getDirectory_1(path, options, _EntryCallback successCallback,
+      _ErrorCallback errorCallback) native;
+  @JSName('getDirectory')
+  void __getDirectory_2(path, options, _EntryCallback successCallback) native;
+  @JSName('getDirectory')
+  void __getDirectory_3(path, options) native;
+  @JSName('getDirectory')
+  void __getDirectory_4(path) native;
+
+  @JSName('getDirectory')
+  Future<Entry> _getDirectory(String path, {Map options}) {
+    var completer = new Completer<Entry>();
+    __getDirectory(path, options, (value) {
+      completer.complete(value);
+    }, (error) {
+      completer.completeError(error);
+    });
+    return completer.future;
+  }
+
+  void __getFile(String path,
+      [Map options,
+      _EntryCallback successCallback,
+      _ErrorCallback errorCallback]) {
+    if (errorCallback != null) {
+      var options_1 = convertDartToNative_Dictionary(options);
+      __getFile_1(path, options_1, successCallback, errorCallback);
+      return;
+    }
+    if (successCallback != null) {
+      var options_1 = convertDartToNative_Dictionary(options);
+      __getFile_2(path, options_1, successCallback);
+      return;
+    }
+    if (options != null) {
+      var options_1 = convertDartToNative_Dictionary(options);
+      __getFile_3(path, options_1);
+      return;
+    }
+    __getFile_4(path);
+    return;
+  }
+
+  @JSName('getFile')
+  void __getFile_1(path, options, _EntryCallback successCallback,
+      _ErrorCallback errorCallback) native;
+  @JSName('getFile')
+  void __getFile_2(path, options, _EntryCallback successCallback) native;
+  @JSName('getFile')
+  void __getFile_3(path, options) native;
+  @JSName('getFile')
+  void __getFile_4(path) native;
+
+  @JSName('getFile')
+  Future<Entry> _getFile(String path, {Map options}) {
+    var completer = new Completer<Entry>();
+    __getFile(path, options, (value) {
+      applyExtension('FileEntry', value);
+      completer.complete(value);
+    }, (error) {
+      completer.completeError(error);
+    });
+    return completer.future;
+  }
+
+  @JSName('removeRecursively')
+  void _removeRecursively(VoidCallback successCallback,
+      [_ErrorCallback errorCallback]) native;
+
+  @JSName('removeRecursively')
+  Future removeRecursively() {
+    var completer = new Completer();
+    _removeRecursively(() {
+      completer.complete();
+    }, (error) {
+      completer.completeError(error);
+    });
+    return completer.future;
+  }
+}
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("DirectoryReader")
+class DirectoryReader extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory DirectoryReader._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  @JSName('readEntries')
+  void _readEntries(_EntriesCallback successCallback,
+      [_ErrorCallback errorCallback]) native;
+
+  Future<List<Entry>> readEntries() {
+    var completer = new Completer<List<Entry>>();
+    _readEntries((values) {
+      values.forEach((value) {
+        applyExtension('Entry', value);
+        Entry entry = value as Entry;
+        if (entry.isFile)
+          applyExtension('FileEntry', entry);
+        else if (entry.isDirectory) applyExtension('DirectoryEntry', entry);
+      });
+      completer.complete(new List<Entry>.from(values));
+    }, (error) {
+      completer.completeError(error);
+    });
+
+    return completer.future;
+  }
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/**
+ * A generic container for content on an HTML page;
+ * corresponds to the &lt;div&gt; tag.
+ *
+ * The [DivElement] is a generic container and does not have any semantic
+ * significance. It is functionally similar to [SpanElement].
+ *
+ * The [DivElement] is a block-level element, as opposed to [SpanElement],
+ * which is an inline-level element.
+ *
+ * Example usage:
+ *
+ *     DivElement div = new DivElement();
+ *     div.text = 'Here's my new DivElem
+ *     document.body.elements.add(elem);
+ *
+ * See also:
+ *
+ * * [HTML `<div>` element](http://www.w3.org/TR/html-markup/div.html) from W3C.
+ * * [Block-level element](http://www.w3.org/TR/CSS2/visuren.html#block-boxes) from W3C.
+ * * [Inline-level element](http://www.w3.org/TR/CSS2/visuren.html#inline-boxes) from W3C.
+ */
+@Native("HTMLDivElement")
+class DivElement extends HtmlElement {
+  // To suppress missing implicit constructor warnings.
+  factory DivElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory DivElement() => JS('returns:DivElement;creates:DivElement;new:true',
+      '#.createElement(#)', document, "div");
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  DivElement.created() : super.created();
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/**
+ * The base class for all documents.
+ *
+ * Each web page loaded in the browser has its own [Document] object, which is
+ * typically an [HtmlDocument].
+ *
+ * If you aren't comfortable with DOM concepts, see the Dart tutorial
+ * [Target 2: Connect Dart & HTML](http://www.dartlang.org/docs/tutorials/connect-dart-html/).
+ */
+@Native("Document")
+class Document extends Node {
+  // To suppress missing implicit constructor warnings.
+  factory Document._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  static const EventStreamProvider<Event> pointerLockChangeEvent =
+      const EventStreamProvider<Event>('pointerlockchange');
+
+  static const EventStreamProvider<Event> pointerLockErrorEvent =
+      const EventStreamProvider<Event>('pointerlockerror');
+
+  /**
+   * Static factory designed to expose `readystatechange` events to event
+   * handlers that are not necessarily instances of [Document].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<Event> readyStateChangeEvent =
+      const EventStreamProvider<Event>('readystatechange');
+
+  /**
+   * Static factory designed to expose `securitypolicyviolation` events to event
+   * handlers that are not necessarily instances of [Document].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<SecurityPolicyViolationEvent>
+      securityPolicyViolationEvent =
+      const EventStreamProvider<SecurityPolicyViolationEvent>(
+          'securitypolicyviolation');
+
+  /**
+   * Static factory designed to expose `selectionchange` events to event
+   * handlers that are not necessarily instances of [Document].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<Event> selectionChangeEvent =
+      const EventStreamProvider<Event>('selectionchange');
+
+  factory Document() {
+    return Document._create_1();
+  }
+  static Document _create_1() => JS('Document', 'new Document()');
+
+  final String addressSpace;
+
+  @JSName('body')
+  HtmlElement _body;
+
+  final String contentType;
+
+  String cookie;
+
+  final ScriptElement currentScript;
+
+  WindowBase get window => _convertNativeToDart_Window(this._get_window);
+  @JSName('defaultView')
+  @Creates('Window|=Object')
+  @Returns('Window|=Object')
+  @Creates('Window|=Object|Null')
+  @Returns('Window|=Object|Null')
+  final dynamic _get_window;
+
+  final Element documentElement;
+
+  final String domain;
+
+  final bool fullscreenEnabled;
+
+  @JSName('head')
+  final HeadElement _head;
+
+  final bool hidden;
+
+  final DomImplementation implementation;
+
+  @JSName('lastModified')
+  final String _lastModified;
+
+  final String origin;
+
+  @JSName('preferredStylesheetSet')
+  final String _preferredStylesheetSet;
+
+  final String readyState;
+
+  @JSName('referrer')
+  final String _referrer;
+
+  final SvgSvgElement rootElement;
+
+  Element rootScroller;
+
+  final Element scrollingElement;
+
+  @JSName('selectedStylesheetSet')
+  String _selectedStylesheetSet;
+
+  final String suborigin;
+
+  final DocumentTimeline timeline;
+
+  @JSName('title')
+  String _title;
+
+  @JSName('visibilityState')
+  final String _visibilityState;
+
+  @JSName('webkitFullscreenElement')
+  @SupportedBrowser(SupportedBrowser.CHROME)
+  @SupportedBrowser(SupportedBrowser.SAFARI)
+  final Element _webkitFullscreenElement;
+
+  @JSName('webkitFullscreenEnabled')
+  @SupportedBrowser(SupportedBrowser.CHROME)
+  @SupportedBrowser(SupportedBrowser.SAFARI)
+  final bool _webkitFullscreenEnabled;
+
+  @JSName('webkitHidden')
+  @SupportedBrowser(SupportedBrowser.CHROME)
+  @SupportedBrowser(SupportedBrowser.SAFARI)
+  final bool _webkitHidden;
+
+  @JSName('webkitVisibilityState')
+  @SupportedBrowser(SupportedBrowser.CHROME)
+  @SupportedBrowser(SupportedBrowser.SAFARI)
+  final String _webkitVisibilityState;
+
+  Node adoptNode(Node node) native;
+
+  @JSName('caretRangeFromPoint')
+  Range _caretRangeFromPoint(int x, int y) native;
+
+  DocumentFragment createDocumentFragment() native;
+
+  @JSName('createElement')
+  Element _createElement(String localName_OR_tagName,
+      [options_OR_typeExtension]) native;
+
+  @JSName('createElementNS')
+  Element _createElementNS(String namespaceURI, String qualifiedName,
+      [options_OR_typeExtension]) native;
+
+  @JSName('createEvent')
+  Event _createEvent(String eventType) native;
+
+  Range createRange() native;
+
+  @JSName('createTextNode')
+  Text _createTextNode(String data) native;
+
+  Touch _createTouch(Window view, EventTarget target, int identifier, num pageX,
+      num pageY, num screenX, num screenY,
+      [num radiusX, num radiusY, num rotationAngle, num force]) {
+    if (force != null) {
+      var target_1 = _convertDartToNative_EventTarget(target);
+      return _createTouch_1(view, target_1, identifier, pageX, pageY, screenX,
+          screenY, radiusX, radiusY, rotationAngle, force);
+    }
+    if (rotationAngle != null) {
+      var target_1 = _convertDartToNative_EventTarget(target);
+      return _createTouch_2(view, target_1, identifier, pageX, pageY, screenX,
+          screenY, radiusX, radiusY, rotationAngle);
+    }
+    if (radiusY != null) {
+      var target_1 = _convertDartToNative_EventTarget(target);
+      return _createTouch_3(view, target_1, identifier, pageX, pageY, screenX,
+          screenY, radiusX, radiusY);
+    }
+    if (radiusX != null) {
+      var target_1 = _convertDartToNative_EventTarget(target);
+      return _createTouch_4(
+          view, target_1, identifier, pageX, pageY, screenX, screenY, radiusX);
+    }
+    var target_1 = _convertDartToNative_EventTarget(target);
+    return _createTouch_5(
+        view, target_1, identifier, pageX, pageY, screenX, screenY);
+  }
+
+  @JSName('createTouch')
+  Touch _createTouch_1(Window view, target, identifier, pageX, pageY, screenX,
+      screenY, radiusX, radiusY, rotationAngle, force) native;
+  @JSName('createTouch')
+  Touch _createTouch_2(Window view, target, identifier, pageX, pageY, screenX,
+      screenY, radiusX, radiusY, rotationAngle) native;
+  @JSName('createTouch')
+  Touch _createTouch_3(Window view, target, identifier, pageX, pageY, screenX,
+      screenY, radiusX, radiusY) native;
+  @JSName('createTouch')
+  Touch _createTouch_4(Window view, target, identifier, pageX, pageY, screenX,
+      screenY, radiusX) native;
+  @JSName('createTouch')
+  Touch _createTouch_5(
+      Window view, target, identifier, pageX, pageY, screenX, screenY) native;
+
+  @JSName('createTouchList')
+  TouchList _createTouchList(Touch touches) native;
+
+  bool execCommand(String commandId, [bool showUI, String value]) native;
+
+  void exitFullscreen() native;
+
+  void exitPointerLock() native;
+
+  List<Animation> getAnimations() native;
+
+  @Creates('NodeList|HtmlCollection')
+  @Returns('NodeList|HtmlCollection')
+  List<Node> getElementsByClassName(String classNames) native;
+
+  @Creates('NodeList|HtmlCollection')
+  @Returns('NodeList|HtmlCollection')
+  List<Node> getElementsByName(String elementName) native;
+
+  @Creates('NodeList|HtmlCollection')
+  @Returns('NodeList|HtmlCollection')
+  List<Node> getElementsByTagName(String localName) native;
+
+  Node importNode(Node node, [bool deep]) native;
+
+  bool queryCommandEnabled(String commandId) native;
+
+  bool queryCommandIndeterm(String commandId) native;
+
+  bool queryCommandState(String commandId) native;
+
+  bool queryCommandSupported(String commandId) native;
+
+  String queryCommandValue(String commandId) native;
+
+  Function registerElement2(String type, [Map options]) {
+    if (options != null) {
+      var options_1 = convertDartToNative_Dictionary(options);
+      return _registerElement2_1(type, options_1);
+    }
+    return _registerElement2_2(type);
+  }
+
+  @JSName('registerElement')
+  Function _registerElement2_1(type, options) native;
+  @JSName('registerElement')
+  Function _registerElement2_2(type) native;
+
+  @JSName('webkitExitFullscreen')
+  @SupportedBrowser(SupportedBrowser.CHROME)
+  @SupportedBrowser(SupportedBrowser.SAFARI)
+  void _webkitExitFullscreen() native;
+
+  // From NonElementParentNode
+
+  Element getElementById(String elementId) native;
+
+  // From DocumentOrShadowRoot
+
+  final Element activeElement;
+
+  final Element fullscreenElement;
+
+  final Element pointerLockElement;
+
+  @JSName('styleSheets')
+  @Returns('_StyleSheetList|Null')
+  @Creates('_StyleSheetList')
+  final List<StyleSheet> _styleSheets;
+
+  @JSName('elementFromPoint')
+  Element _elementFromPoint(int x, int y) native;
+
+  List<Element> elementsFromPoint(int x, int y) native;
+
+  // From FontFaceSource
+
+  final FontFaceSet fonts;
+
+  // From ParentNode
+
+  @JSName('childElementCount')
+  final int _childElementCount;
+
+  @JSName('children')
+  @Returns('HtmlCollection|Null')
+  @Creates('HtmlCollection')
+  final List<Node> _children;
+
+  @JSName('firstElementChild')
+  final Element _firstElementChild;
+
+  @JSName('lastElementChild')
+  final Element _lastElementChild;
+
+  /**
+   * Finds the first descendant element of this document that matches the
+   * specified group of selectors.
+   *
+   * Unless your webpage contains multiple documents, the top-level
+   * [querySelector]
+   * method behaves the same as this method, so you should use it instead to
+   * save typing a few characters.
+   *
+   * [selectors] should be a string using CSS selector syntax.
+   *
+   *     var element1 = document.querySelector('.className');
+   *     var element2 = document.querySelector('#id');
+   *
+   * For details about CSS selector syntax, see the
+   * [CSS selector specification](http://www.w3.org/TR/css3-selectors/).
+   */
+  Element querySelector(String selectors) native;
+
+  @JSName('querySelectorAll')
+  @Creates('NodeList')
+  @Returns('NodeList')
+  List<Node> _querySelectorAll(String selectors) native;
+
+  /// Stream of `abort` events handled by this [Document].
+  Stream<Event> get onAbort => Element.abortEvent.forTarget(this);
+
+  /// Stream of `beforecopy` events handled by this [Document].
+  Stream<Event> get onBeforeCopy => Element.beforeCopyEvent.forTarget(this);
+
+  /// Stream of `beforecut` events handled by this [Document].
+  Stream<Event> get onBeforeCut => Element.beforeCutEvent.forTarget(this);
+
+  /// Stream of `beforepaste` events handled by this [Document].
+  Stream<Event> get onBeforePaste => Element.beforePasteEvent.forTarget(this);
+
+  /// Stream of `blur` events handled by this [Document].
+  Stream<Event> get onBlur => Element.blurEvent.forTarget(this);
+
+  Stream<Event> get onCanPlay => Element.canPlayEvent.forTarget(this);
+
+  Stream<Event> get onCanPlayThrough =>
+      Element.canPlayThroughEvent.forTarget(this);
+
+  /// Stream of `change` events handled by this [Document].
+  Stream<Event> get onChange => Element.changeEvent.forTarget(this);
+
+  /// Stream of `click` events handled by this [Document].
+  Stream<MouseEvent> get onClick => Element.clickEvent.forTarget(this);
+
+  /// Stream of `contextmenu` events handled by this [Document].
+  Stream<MouseEvent> get onContextMenu =>
+      Element.contextMenuEvent.forTarget(this);
+
+  /// Stream of `copy` events handled by this [Document].
+  Stream<ClipboardEvent> get onCopy => Element.copyEvent.forTarget(this);
+
+  /// Stream of `cut` events handled by this [Document].
+  Stream<ClipboardEvent> get onCut => Element.cutEvent.forTarget(this);
+
+  /// Stream of `doubleclick` events handled by this [Document].
+  @DomName('Document.ondblclick')
+  Stream<Event> get onDoubleClick => Element.doubleClickEvent.forTarget(this);
+
+  /// Stream of `drag` events handled by this [Document].
+  Stream<MouseEvent> get onDrag => Element.dragEvent.forTarget(this);
+
+  /// Stream of `dragend` events handled by this [Document].
+  Stream<MouseEvent> get onDragEnd => Element.dragEndEvent.forTarget(this);
+
+  /// Stream of `dragenter` events handled by this [Document].
+  Stream<MouseEvent> get onDragEnter => Element.dragEnterEvent.forTarget(this);
+
+  /// Stream of `dragleave` events handled by this [Document].
+  Stream<MouseEvent> get onDragLeave => Element.dragLeaveEvent.forTarget(this);
+
+  /// Stream of `dragover` events handled by this [Document].
+  Stream<MouseEvent> get onDragOver => Element.dragOverEvent.forTarget(this);
+
+  /// Stream of `dragstart` events handled by this [Document].
+  Stream<MouseEvent> get onDragStart => Element.dragStartEvent.forTarget(this);
+
+  /// Stream of `drop` events handled by this [Document].
+  Stream<MouseEvent> get onDrop => Element.dropEvent.forTarget(this);
+
+  Stream<Event> get onDurationChange =>
+      Element.durationChangeEvent.forTarget(this);
+
+  Stream<Event> get onEmptied => Element.emptiedEvent.forTarget(this);
+
+  Stream<Event> get onEnded => Element.endedEvent.forTarget(this);
+
+  /// Stream of `error` events handled by this [Document].
+  Stream<Event> get onError => Element.errorEvent.forTarget(this);
+
+  /// Stream of `focus` events handled by this [Document].
+  Stream<Event> get onFocus => Element.focusEvent.forTarget(this);
+
+  /// Stream of `input` events handled by this [Document].
+  Stream<Event> get onInput => Element.inputEvent.forTarget(this);
+
+  /// Stream of `invalid` events handled by this [Document].
+  Stream<Event> get onInvalid => Element.invalidEvent.forTarget(this);
+
+  /// Stream of `keydown` events handled by this [Document].
+  Stream<KeyboardEvent> get onKeyDown => Element.keyDownEvent.forTarget(this);
+
+  /// Stream of `keypress` events handled by this [Document].
+  Stream<KeyboardEvent> get onKeyPress => Element.keyPressEvent.forTarget(this);
+
+  /// Stream of `keyup` events handled by this [Document].
+  Stream<KeyboardEvent> get onKeyUp => Element.keyUpEvent.forTarget(this);
+
+  /// Stream of `load` events handled by this [Document].
+  Stream<Event> get onLoad => Element.loadEvent.forTarget(this);
+
+  Stream<Event> get onLoadedData => Element.loadedDataEvent.forTarget(this);
+
+  Stream<Event> get onLoadedMetadata =>
+      Element.loadedMetadataEvent.forTarget(this);
+
+  /// Stream of `mousedown` events handled by this [Document].
+  Stream<MouseEvent> get onMouseDown => Element.mouseDownEvent.forTarget(this);
+
+  /// Stream of `mouseenter` events handled by this [Document].
+  Stream<MouseEvent> get onMouseEnter =>
+      Element.mouseEnterEvent.forTarget(this);
+
+  /// Stream of `mouseleave` events handled by this [Document].
+  Stream<MouseEvent> get onMouseLeave =>
+      Element.mouseLeaveEvent.forTarget(this);
+
+  /// Stream of `mousemove` events handled by this [Document].
+  Stream<MouseEvent> get onMouseMove => Element.mouseMoveEvent.forTarget(this);
+
+  /// Stream of `mouseout` events handled by this [Document].
+  Stream<MouseEvent> get onMouseOut => Element.mouseOutEvent.forTarget(this);
+
+  /// Stream of `mouseover` events handled by this [Document].
+  Stream<MouseEvent> get onMouseOver => Element.mouseOverEvent.forTarget(this);
+
+  /// Stream of `mouseup` events handled by this [Document].
+  Stream<MouseEvent> get onMouseUp => Element.mouseUpEvent.forTarget(this);
+
+  /// Stream of `mousewheel` events handled by this [Document].
+  Stream<WheelEvent> get onMouseWheel =>
+      Element.mouseWheelEvent.forTarget(this);
+
+  /// Stream of `paste` events handled by this [Document].
+  Stream<ClipboardEvent> get onPaste => Element.pasteEvent.forTarget(this);
+
+  Stream<Event> get onPause => Element.pauseEvent.forTarget(this);
+
+  Stream<Event> get onPlay => Element.playEvent.forTarget(this);
+
+  Stream<Event> get onPlaying => Element.playingEvent.forTarget(this);
+
+  Stream<Event> get onPointerLockChange =>
+      pointerLockChangeEvent.forTarget(this);
+
+  Stream<Event> get onPointerLockError => pointerLockErrorEvent.forTarget(this);
+
+  Stream<Event> get onRateChange => Element.rateChangeEvent.forTarget(this);
+
+  /// Stream of `readystatechange` events handled by this [Document].
+  Stream<Event> get onReadyStateChange => readyStateChangeEvent.forTarget(this);
+
+  /// Stream of `reset` events handled by this [Document].
+  Stream<Event> get onReset => Element.resetEvent.forTarget(this);
+
+  Stream<Event> get onResize => Element.resizeEvent.forTarget(this);
+
+  /// Stream of `scroll` events handled by this [Document].
+  Stream<Event> get onScroll => Element.scrollEvent.forTarget(this);
+
+  /// Stream of `search` events handled by this [Document].
+  Stream<Event> get onSearch => Element.searchEvent.forTarget(this);
+
+  /// Stream of `securitypolicyviolation` events handled by this [Document].
+  Stream<SecurityPolicyViolationEvent> get onSecurityPolicyViolation =>
+      securityPolicyViolationEvent.forTarget(this);
+
+  Stream<Event> get onSeeked => Element.seekedEvent.forTarget(this);
+
+  Stream<Event> get onSeeking => Element.seekingEvent.forTarget(this);
+
+  /// Stream of `select` events handled by this [Document].
+  Stream<Event> get onSelect => Element.selectEvent.forTarget(this);
+
+  /// Stream of `selectionchange` events handled by this [Document].
+  Stream<Event> get onSelectionChange => selectionChangeEvent.forTarget(this);
+
+  /// Stream of `selectstart` events handled by this [Document].
+  Stream<Event> get onSelectStart => Element.selectStartEvent.forTarget(this);
+
+  Stream<Event> get onStalled => Element.stalledEvent.forTarget(this);
+
+  /// Stream of `submit` events handled by this [Document].
+  Stream<Event> get onSubmit => Element.submitEvent.forTarget(this);
+
+  Stream<Event> get onSuspend => Element.suspendEvent.forTarget(this);
+
+  Stream<Event> get onTimeUpdate => Element.timeUpdateEvent.forTarget(this);
+
+  /// Stream of `touchcancel` events handled by this [Document].
+  Stream<TouchEvent> get onTouchCancel =>
+      Element.touchCancelEvent.forTarget(this);
+
+  /// Stream of `touchend` events handled by this [Document].
+  Stream<TouchEvent> get onTouchEnd => Element.touchEndEvent.forTarget(this);
+
+  /// Stream of `touchmove` events handled by this [Document].
+  Stream<TouchEvent> get onTouchMove => Element.touchMoveEvent.forTarget(this);
+
+  /// Stream of `touchstart` events handled by this [Document].
+  Stream<TouchEvent> get onTouchStart =>
+      Element.touchStartEvent.forTarget(this);
+
+  Stream<Event> get onVolumeChange => Element.volumeChangeEvent.forTarget(this);
+
+  Stream<Event> get onWaiting => Element.waitingEvent.forTarget(this);
+
+  /// Stream of `fullscreenchange` events handled by this [Document].
+  Stream<Event> get onFullscreenChange =>
+      Element.fullscreenChangeEvent.forTarget(this);
+
+  /// Stream of `fullscreenerror` events handled by this [Document].
+  Stream<Event> get onFullscreenError =>
+      Element.fullscreenErrorEvent.forTarget(this);
+
+  /**
+   * Finds all descendant elements of this document that match the specified
+   * group of selectors.
+   *
+   * Unless your webpage contains multiple documents, the top-level
+   * [querySelectorAll]
+   * method behaves the same as this method, so you should use it instead to
+   * save typing a few characters.
+   *
+   * [selectors] should be a string using CSS selector syntax.
+   *
+   *     var items = document.querySelectorAll('.itemClassName');
+   *
+   * For details about CSS selector syntax, see the
+   * [CSS selector specification](http://www.w3.org/TR/css3-selectors/).
+   */
+  ElementList<T> querySelectorAll<T extends Element>(String selectors) =>
+      new _FrozenElementList<T>._wrap(_querySelectorAll(selectors));
+
+  /// Checks if [registerElement] is supported on the current platform.
+  bool get supportsRegisterElement {
+    return JS('bool', '("registerElement" in #)', this);
+  }
+
+  /// *Deprecated*: use [supportsRegisterElement] instead.
+  @deprecated
+  bool get supportsRegister => supportsRegisterElement;
+
+  void registerElement(String tag, Type customElementClass,
+      {String extendsTag}) {
+    registerElement2(
+        tag, {'prototype': customElementClass, 'extends': extendsTag});
+  }
+
+  @pragma('dart2js:tryInline') // Almost all call sites have one argument.
+  Element createElement(String tagName, [String typeExtension]) {
+    return (typeExtension == null)
+        ? _createElement_2(tagName)
+        : _createElement(tagName, typeExtension);
+  }
+
+  // The two-argument version of this is automatically generated, but we need to
+  // omit the typeExtension if it's null on Firefox or we get an is="null" attribute.
+  _createElement_2(String tagName) =>
+      JS('Element', '#.createElement(#)', this, tagName);
+
+  // The three-argument version of this is automatically generated, but we need to
+  // omit the typeExtension if it's null on Firefox or we get an is="null" attribute.
+  _createElementNS_2(String namespaceURI, String qualifiedName) => JS(
+      'Element', '#.createElementNS(#, #)', this, namespaceURI, qualifiedName);
+
+  Element createElementNS(String namespaceURI, String qualifiedName,
+      [String typeExtension]) {
+    return (typeExtension == null)
+        ? _createElementNS_2(namespaceURI, qualifiedName)
+        : _createElementNS(namespaceURI, qualifiedName, typeExtension);
+  }
+
+  NodeIterator _createNodeIterator(Node root,
+          [int whatToShow, NodeFilter filter]) =>
+      JS('NodeIterator', '#.createNodeIterator(#, #, #, false)', this, root,
+          whatToShow, filter);
+
+  TreeWalker _createTreeWalker(Node root,
+          [int whatToShow, NodeFilter filter]) =>
+      JS('TreeWalker', '#.createTreeWalker(#, #, #, false)', this, root,
+          whatToShow, filter);
+
+  @SupportedBrowser(SupportedBrowser.CHROME)
+  @SupportedBrowser(SupportedBrowser.FIREFOX)
+  @SupportedBrowser(SupportedBrowser.IE, '10')
+  String get visibilityState => JS(
+      'String',
+      '(#.visibilityState || #.mozVisibilityState || #.msVisibilityState ||'
+          '#.webkitVisibilityState)',
+      this,
+      this,
+      this,
+      this);
+}
+// Copyright (c) 2011, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("DocumentFragment")
+class DocumentFragment extends Node
+    implements NonElementParentNode, ParentNode {
+  factory DocumentFragment() => document.createDocumentFragment();
+
+  factory DocumentFragment.html(String html,
+      {NodeValidator validator, NodeTreeSanitizer treeSanitizer}) {
+    return document.body.createFragment(html,
+        validator: validator, treeSanitizer: treeSanitizer);
+  }
+
+  factory DocumentFragment.svg(String svgContent,
+      {NodeValidator validator, NodeTreeSanitizer treeSanitizer}) {
+    return new svg.SvgSvgElement().createFragment(svgContent,
+        validator: validator, treeSanitizer: treeSanitizer);
+  }
+
+  HtmlCollection get _children =>
+      throw new UnimplementedError('Use _docChildren instead');
+
+  // Native field is used only by Dart code so does not lead to instantiation
+  // of native classes
+  @Creates('Null')
+  List<Element> _docChildren;
+
+  List<Element> get children {
+    if (_docChildren == null) {
+      _docChildren = new FilteredElementList(this);
+    }
+    return _docChildren;
+  }
+
+  set children(List<Element> value) {
+    // Copy list first since we don't want liveness during iteration.
+    var copy = value.toList();
+    var children = this.children;
+    children.clear();
+    children.addAll(copy);
+  }
+
+  /**
+   * Finds all descendant elements of this document fragment that match the
+   * specified group of selectors.
+   *
+   * [selectors] should be a string using CSS selector syntax.
+   *
+   *     var items = document.querySelectorAll('.itemClassName');
+   *
+   * For details about CSS selector syntax, see the
+   * [CSS selector specification](http://www.w3.org/TR/css3-selectors/).
+   */
+  ElementList<T> querySelectorAll<T extends Element>(String selectors) =>
+      new _FrozenElementList<T>._wrap(_querySelectorAll(selectors));
+
+  String get innerHtml {
+    final e = new DivElement();
+    e.append(this.clone(true));
+    return e.innerHtml;
+  }
+
+  set innerHtml(String value) {
+    this.setInnerHtml(value);
+  }
+
+  void setInnerHtml(String html,
+      {NodeValidator validator, NodeTreeSanitizer treeSanitizer}) {
+    this.nodes.clear();
+    append(document.body.createFragment(html,
+        validator: validator, treeSanitizer: treeSanitizer));
+  }
+
+  /**
+   * Adds the specified text as a text node after the last child of this
+   * document fragment.
+   */
+  void appendText(String text) {
+    this.append(new Text(text));
+  }
+
+  /**
+   * Parses the specified text as HTML and adds the resulting node after the
+   * last child of this document fragment.
+   */
+  void appendHtml(String text,
+      {NodeValidator validator, NodeTreeSanitizer treeSanitizer}) {
+    this.append(new DocumentFragment.html(text,
+        validator: validator, treeSanitizer: treeSanitizer));
+  }
+
+  // To suppress missing implicit constructor warnings.
+  factory DocumentFragment._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  // From NonElementParentNode
+
+  Element getElementById(String elementId) native;
+
+  // From ParentNode
+
+  @JSName('childElementCount')
+  final int _childElementCount;
+
+  @JSName('firstElementChild')
+  final Element _firstElementChild;
+
+  @JSName('lastElementChild')
+  final Element _lastElementChild;
+
+  /**
+   * Finds the first descendant element of this document fragment that matches
+   * the specified group of selectors.
+   *
+   * [selectors] should be a string using CSS selector syntax.
+   *
+   *     var element1 = fragment.querySelector('.className');
+   *     var element2 = fragment.querySelector('#id');
+   *
+   * For details about CSS selector syntax, see the
+   * [CSS selector specification](http://www.w3.org/TR/css3-selectors/).
+   */
+  Element querySelector(String selectors) native;
+
+  @JSName('querySelectorAll')
+  @Creates('NodeList')
+  @Returns('NodeList')
+  List<Node> _querySelectorAll(String selectors) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("DocumentOrShadowRoot")
+class DocumentOrShadowRoot extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory DocumentOrShadowRoot._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final Element activeElement;
+
+  final Element fullscreenElement;
+
+  final Element pointerLockElement;
+
+  @Returns('_StyleSheetList|Null')
+  @Creates('_StyleSheetList')
+  final List<StyleSheet> styleSheets;
+
+  Element elementFromPoint(int x, int y) native;
+
+  List<Element> elementsFromPoint(int x, int y) native;
+
+  Selection getSelection() native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("DocumentTimeline")
+class DocumentTimeline extends AnimationTimeline {
+  // To suppress missing implicit constructor warnings.
+  factory DocumentTimeline._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory DocumentTimeline([Map options]) {
+    if (options != null) {
+      var options_1 = convertDartToNative_Dictionary(options);
+      return DocumentTimeline._create_1(options_1);
+    }
+    return DocumentTimeline._create_2();
+  }
+  static DocumentTimeline _create_1(options) =>
+      JS('DocumentTimeline', 'new DocumentTimeline(#)', options);
+  static DocumentTimeline _create_2() =>
+      JS('DocumentTimeline', 'new DocumentTimeline()');
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("DOMError")
+class DomError extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory DomError._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory DomError(String name, [String message]) {
+    if (message != null) {
+      return DomError._create_1(name, message);
+    }
+    return DomError._create_2(name);
+  }
+  static DomError _create_1(name, message) =>
+      JS('DomError', 'new DOMError(#,#)', name, message);
+  static DomError _create_2(name) => JS('DomError', 'new DOMError(#)', name);
+
+  final String message;
+
+  final String name;
+}
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("DOMException")
+class DomException extends Interceptor {
+  static const String INDEX_SIZE = 'IndexSizeError';
+  static const String HIERARCHY_REQUEST = 'HierarchyRequestError';
+  static const String WRONG_DOCUMENT = 'WrongDocumentError';
+  static const String INVALID_CHARACTER = 'InvalidCharacterError';
+  static const String NO_MODIFICATION_ALLOWED = 'NoModificationAllowedError';
+  static const String NOT_FOUND = 'NotFoundError';
+  static const String NOT_SUPPORTED = 'NotSupportedError';
+  static const String INVALID_STATE = 'InvalidStateError';
+  static const String SYNTAX = 'SyntaxError';
+  static const String INVALID_MODIFICATION = 'InvalidModificationError';
+  static const String NAMESPACE = 'NamespaceError';
+  static const String INVALID_ACCESS = 'InvalidAccessError';
+  static const String TYPE_MISMATCH = 'TypeMismatchError';
+  static const String SECURITY = 'SecurityError';
+  static const String NETWORK = 'NetworkError';
+  static const String ABORT = 'AbortError';
+  static const String URL_MISMATCH = 'URLMismatchError';
+  static const String QUOTA_EXCEEDED = 'QuotaExceededError';
+  static const String TIMEOUT = 'TimeoutError';
+  static const String INVALID_NODE_TYPE = 'InvalidNodeTypeError';
+  static const String DATA_CLONE = 'DataCloneError';
+  static const String ENCODING = 'EncodingError';
+  static const String NOT_READABLE = 'NotReadableError';
+  static const String UNKNOWN = 'UnknownError';
+  static const String CONSTRAINT = 'ConstraintError';
+  static const String TRANSACTION_INACTIVE = 'TransactionInactiveError';
+  static const String READ_ONLY = 'ReadOnlyError';
+  static const String VERSION = 'VersionError';
+  static const String OPERATION = 'OperationError';
+  static const String NOT_ALLOWED = 'NotAllowedError';
+  // Is TypeError class derived from DomException but name is 'TypeError'
+  static const String TYPE_ERROR = 'TypeError';
+
+  String get name {
+    var errorName = JS('String', '#.name', this);
+    // Although Safari nightly has updated the name to SecurityError, Safari 5
+    // and 6 still return SECURITY_ERR.
+    if (Device.isWebKit && errorName == 'SECURITY_ERR') return 'SecurityError';
+    // Chrome release still uses old string, remove this line when Chrome stable
+    // also prints out SyntaxError.
+    if (Device.isWebKit && errorName == 'SYNTAX_ERR') return 'SyntaxError';
+    return errorName;
+  }
+
+  // To suppress missing implicit constructor warnings.
+  factory DomException._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final String message;
+
+  String toString() => JS('String', 'String(#)', this);
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("DOMImplementation")
+class DomImplementation extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory DomImplementation._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  XmlDocument createDocument(
+      String namespaceURI, String qualifiedName, _DocumentType doctype) native;
+
+  _DocumentType createDocumentType(
+      String qualifiedName, String publicId, String systemId) native;
+
+  @JSName('createHTMLDocument')
+  HtmlDocument createHtmlDocument([String title]) native;
+
+  bool hasFeature() native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("Iterator")
+class DomIterator extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory DomIterator._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  Object next([Object value]) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("DOMMatrix")
+class DomMatrix extends DomMatrixReadOnly {
+  // To suppress missing implicit constructor warnings.
+  factory DomMatrix._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory DomMatrix([Object init]) {
+    if (init != null) {
+      return DomMatrix._create_1(init);
+    }
+    return DomMatrix._create_2();
+  }
+  static DomMatrix _create_1(init) => JS('DomMatrix', 'new DOMMatrix(#)', init);
+  static DomMatrix _create_2() => JS('DomMatrix', 'new DOMMatrix()');
+
+  // Shadowing definition.
+  num get a => JS("num", "#.a", this);
+
+  set a(num value) {
+    JS("void", "#.a = #", this, value);
+  }
+
+  // Shadowing definition.
+  num get b => JS("num", "#.b", this);
+
+  set b(num value) {
+    JS("void", "#.b = #", this, value);
+  }
+
+  // Shadowing definition.
+  num get c => JS("num", "#.c", this);
+
+  set c(num value) {
+    JS("void", "#.c = #", this, value);
+  }
+
+  // Shadowing definition.
+  num get d => JS("num", "#.d", this);
+
+  set d(num value) {
+    JS("void", "#.d = #", this, value);
+  }
+
+  // Shadowing definition.
+  num get e => JS("num", "#.e", this);
+
+  set e(num value) {
+    JS("void", "#.e = #", this, value);
+  }
+
+  // Shadowing definition.
+  num get f => JS("num", "#.f", this);
+
+  set f(num value) {
+    JS("void", "#.f = #", this, value);
+  }
+
+  // Shadowing definition.
+  num get m11 => JS("num", "#.m11", this);
+
+  set m11(num value) {
+    JS("void", "#.m11 = #", this, value);
+  }
+
+  // Shadowing definition.
+  num get m12 => JS("num", "#.m12", this);
+
+  set m12(num value) {
+    JS("void", "#.m12 = #", this, value);
+  }
+
+  // Shadowing definition.
+  num get m13 => JS("num", "#.m13", this);
+
+  set m13(num value) {
+    JS("void", "#.m13 = #", this, value);
+  }
+
+  // Shadowing definition.
+  num get m14 => JS("num", "#.m14", this);
+
+  set m14(num value) {
+    JS("void", "#.m14 = #", this, value);
+  }
+
+  // Shadowing definition.
+  num get m21 => JS("num", "#.m21", this);
+
+  set m21(num value) {
+    JS("void", "#.m21 = #", this, value);
+  }
+
+  // Shadowing definition.
+  num get m22 => JS("num", "#.m22", this);
+
+  set m22(num value) {
+    JS("void", "#.m22 = #", this, value);
+  }
+
+  // Shadowing definition.
+  num get m23 => JS("num", "#.m23", this);
+
+  set m23(num value) {
+    JS("void", "#.m23 = #", this, value);
+  }
+
+  // Shadowing definition.
+  num get m24 => JS("num", "#.m24", this);
+
+  set m24(num value) {
+    JS("void", "#.m24 = #", this, value);
+  }
+
+  // Shadowing definition.
+  num get m31 => JS("num", "#.m31", this);
+
+  set m31(num value) {
+    JS("void", "#.m31 = #", this, value);
+  }
+
+  // Shadowing definition.
+  num get m32 => JS("num", "#.m32", this);
+
+  set m32(num value) {
+    JS("void", "#.m32 = #", this, value);
+  }
+
+  // Shadowing definition.
+  num get m33 => JS("num", "#.m33", this);
+
+  set m33(num value) {
+    JS("void", "#.m33 = #", this, value);
+  }
+
+  // Shadowing definition.
+  num get m34 => JS("num", "#.m34", this);
+
+  set m34(num value) {
+    JS("void", "#.m34 = #", this, value);
+  }
+
+  // Shadowing definition.
+  num get m41 => JS("num", "#.m41", this);
+
+  set m41(num value) {
+    JS("void", "#.m41 = #", this, value);
+  }
+
+  // Shadowing definition.
+  num get m42 => JS("num", "#.m42", this);
+
+  set m42(num value) {
+    JS("void", "#.m42 = #", this, value);
+  }
+
+  // Shadowing definition.
+  num get m43 => JS("num", "#.m43", this);
+
+  set m43(num value) {
+    JS("void", "#.m43 = #", this, value);
+  }
+
+  // Shadowing definition.
+  num get m44 => JS("num", "#.m44", this);
+
+  set m44(num value) {
+    JS("void", "#.m44 = #", this, value);
+  }
+
+  static DomMatrix fromFloat32Array(Float32List array32) native;
+
+  static DomMatrix fromFloat64Array(Float64List array64) native;
+
+  static DomMatrix fromMatrix([Map other]) {
+    if (other != null) {
+      var other_1 = convertDartToNative_Dictionary(other);
+      return _fromMatrix_1(other_1);
+    }
+    return _fromMatrix_2();
+  }
+
+  @JSName('fromMatrix')
+  static DomMatrix _fromMatrix_1(other) native;
+  @JSName('fromMatrix')
+  static DomMatrix _fromMatrix_2() native;
+
+  DomMatrix invertSelf() native;
+
+  DomMatrix multiplySelf([Map other]) {
+    if (other != null) {
+      var other_1 = convertDartToNative_Dictionary(other);
+      return _multiplySelf_1(other_1);
+    }
+    return _multiplySelf_2();
+  }
+
+  @JSName('multiplySelf')
+  DomMatrix _multiplySelf_1(other) native;
+  @JSName('multiplySelf')
+  DomMatrix _multiplySelf_2() native;
+
+  DomMatrix preMultiplySelf([Map other]) {
+    if (other != null) {
+      var other_1 = convertDartToNative_Dictionary(other);
+      return _preMultiplySelf_1(other_1);
+    }
+    return _preMultiplySelf_2();
+  }
+
+  @JSName('preMultiplySelf')
+  DomMatrix _preMultiplySelf_1(other) native;
+  @JSName('preMultiplySelf')
+  DomMatrix _preMultiplySelf_2() native;
+
+  DomMatrix rotateAxisAngleSelf([num x, num y, num z, num angle]) native;
+
+  DomMatrix rotateFromVectorSelf([num x, num y]) native;
+
+  DomMatrix rotateSelf([num rotX, num rotY, num rotZ]) native;
+
+  DomMatrix scale3dSelf([num scale, num originX, num originY, num originZ])
+      native;
+
+  DomMatrix scaleSelf(
+      [num scaleX,
+      num scaleY,
+      num scaleZ,
+      num originX,
+      num originY,
+      num originZ]) native;
+
+  DomMatrix setMatrixValue(String transformList) native;
+
+  DomMatrix skewXSelf([num sx]) native;
+
+  DomMatrix skewYSelf([num sy]) native;
+
+  DomMatrix translateSelf([num tx, num ty, num tz]) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("DOMMatrixReadOnly")
+class DomMatrixReadOnly extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory DomMatrixReadOnly._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory DomMatrixReadOnly([Object init]) {
+    if (init != null) {
+      return DomMatrixReadOnly._create_1(init);
+    }
+    return DomMatrixReadOnly._create_2();
+  }
+  static DomMatrixReadOnly _create_1(init) =>
+      JS('DomMatrixReadOnly', 'new DOMMatrixReadOnly(#)', init);
+  static DomMatrixReadOnly _create_2() =>
+      JS('DomMatrixReadOnly', 'new DOMMatrixReadOnly()');
+
+  num get a => JS("num", "#.a", this);
+
+  num get b => JS("num", "#.b", this);
+
+  num get c => JS("num", "#.c", this);
+
+  num get d => JS("num", "#.d", this);
+
+  num get e => JS("num", "#.e", this);
+
+  num get f => JS("num", "#.f", this);
+
+  bool get is2D => JS("bool", "#.is2D", this);
+
+  bool get isIdentity => JS("bool", "#.isIdentity", this);
+
+  num get m11 => JS("num", "#.m11", this);
+
+  num get m12 => JS("num", "#.m12", this);
+
+  num get m13 => JS("num", "#.m13", this);
+
+  num get m14 => JS("num", "#.m14", this);
+
+  num get m21 => JS("num", "#.m21", this);
+
+  num get m22 => JS("num", "#.m22", this);
+
+  num get m23 => JS("num", "#.m23", this);
+
+  num get m24 => JS("num", "#.m24", this);
+
+  num get m31 => JS("num", "#.m31", this);
+
+  num get m32 => JS("num", "#.m32", this);
+
+  num get m33 => JS("num", "#.m33", this);
+
+  num get m34 => JS("num", "#.m34", this);
+
+  num get m41 => JS("num", "#.m41", this);
+
+  num get m42 => JS("num", "#.m42", this);
+
+  num get m43 => JS("num", "#.m43", this);
+
+  num get m44 => JS("num", "#.m44", this);
+
+  DomMatrix flipX() native;
+
+  DomMatrix flipY() native;
+
+  static DomMatrixReadOnly fromFloat32Array(Float32List array32) native;
+
+  static DomMatrixReadOnly fromFloat64Array(Float64List array64) native;
+
+  static DomMatrixReadOnly fromMatrix([Map other]) {
+    if (other != null) {
+      var other_1 = convertDartToNative_Dictionary(other);
+      return _fromMatrix_1(other_1);
+    }
+    return _fromMatrix_2();
+  }
+
+  @JSName('fromMatrix')
+  static DomMatrixReadOnly _fromMatrix_1(other) native;
+  @JSName('fromMatrix')
+  static DomMatrixReadOnly _fromMatrix_2() native;
+
+  DomMatrix inverse() native;
+
+  DomMatrix multiply([Map other]) {
+    if (other != null) {
+      var other_1 = convertDartToNative_Dictionary(other);
+      return _multiply_1(other_1);
+    }
+    return _multiply_2();
+  }
+
+  @JSName('multiply')
+  DomMatrix _multiply_1(other) native;
+  @JSName('multiply')
+  DomMatrix _multiply_2() native;
+
+  DomMatrix rotate([num rotX, num rotY, num rotZ]) native;
+
+  DomMatrix rotateAxisAngle([num x, num y, num z, num angle]) native;
+
+  DomMatrix rotateFromVector([num x, num y]) native;
+
+  DomMatrix scale(
+      [num scaleX,
+      num scaleY,
+      num scaleZ,
+      num originX,
+      num originY,
+      num originZ]) native;
+
+  DomMatrix scale3d([num scale, num originX, num originY, num originZ]) native;
+
+  DomMatrix skewX([num sx]) native;
+
+  DomMatrix skewY([num sy]) native;
+
+  Float32List toFloat32Array() native;
+
+  Float64List toFloat64Array() native;
+
+  DomPoint transformPoint([Map point]) {
+    if (point != null) {
+      var point_1 = convertDartToNative_Dictionary(point);
+      return _transformPoint_1(point_1);
+    }
+    return _transformPoint_2();
+  }
+
+  @JSName('transformPoint')
+  DomPoint _transformPoint_1(point) native;
+  @JSName('transformPoint')
+  DomPoint _transformPoint_2() native;
+
+  DomMatrix translate([num tx, num ty, num tz]) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("DOMParser")
+class DomParser extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory DomParser._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory DomParser() {
+    return DomParser._create_1();
+  }
+  static DomParser _create_1() => JS('DomParser', 'new DOMParser()');
+
+  Document parseFromString(String str, String type) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("DOMPoint")
+class DomPoint extends DomPointReadOnly {
+  // To suppress missing implicit constructor warnings.
+  factory DomPoint._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory DomPoint([num x, num y, num z, num w]) {
+    if (w != null) {
+      return DomPoint._create_1(x, y, z, w);
+    }
+    if (z != null) {
+      return DomPoint._create_2(x, y, z);
+    }
+    if (y != null) {
+      return DomPoint._create_3(x, y);
+    }
+    if (x != null) {
+      return DomPoint._create_4(x);
+    }
+    return DomPoint._create_5();
+  }
+  static DomPoint _create_1(x, y, z, w) =>
+      JS('DomPoint', 'new DOMPoint(#,#,#,#)', x, y, z, w);
+  static DomPoint _create_2(x, y, z) =>
+      JS('DomPoint', 'new DOMPoint(#,#,#)', x, y, z);
+  static DomPoint _create_3(x, y) => JS('DomPoint', 'new DOMPoint(#,#)', x, y);
+  static DomPoint _create_4(x) => JS('DomPoint', 'new DOMPoint(#)', x);
+  static DomPoint _create_5() => JS('DomPoint', 'new DOMPoint()');
+
+  /// Checks if this type is supported on the current platform.
+  static bool get supported =>
+      JS('bool', '!!(window.DOMPoint) || !!(window.WebKitPoint)');
+
+  // Shadowing definition.
+  num get w => JS("num", "#.w", this);
+
+  set w(num value) {
+    JS("void", "#.w = #", this, value);
+  }
+
+  // Shadowing definition.
+  num get x => JS("num", "#.x", this);
+
+  set x(num value) {
+    JS("void", "#.x = #", this, value);
+  }
+
+  // Shadowing definition.
+  num get y => JS("num", "#.y", this);
+
+  set y(num value) {
+    JS("void", "#.y = #", this, value);
+  }
+
+  // Shadowing definition.
+  num get z => JS("num", "#.z", this);
+
+  set z(num value) {
+    JS("void", "#.z = #", this, value);
+  }
+
+  static DomPoint fromPoint([Map other]) {
+    if (other != null) {
+      var other_1 = convertDartToNative_Dictionary(other);
+      return _fromPoint_1(other_1);
+    }
+    return _fromPoint_2();
+  }
+
+  @JSName('fromPoint')
+  static DomPoint _fromPoint_1(other) native;
+  @JSName('fromPoint')
+  static DomPoint _fromPoint_2() native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("DOMPointReadOnly")
+class DomPointReadOnly extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory DomPointReadOnly._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory DomPointReadOnly([num x, num y, num z, num w]) {
+    if (w != null) {
+      return DomPointReadOnly._create_1(x, y, z, w);
+    }
+    if (z != null) {
+      return DomPointReadOnly._create_2(x, y, z);
+    }
+    if (y != null) {
+      return DomPointReadOnly._create_3(x, y);
+    }
+    if (x != null) {
+      return DomPointReadOnly._create_4(x);
+    }
+    return DomPointReadOnly._create_5();
+  }
+  static DomPointReadOnly _create_1(x, y, z, w) =>
+      JS('DomPointReadOnly', 'new DOMPointReadOnly(#,#,#,#)', x, y, z, w);
+  static DomPointReadOnly _create_2(x, y, z) =>
+      JS('DomPointReadOnly', 'new DOMPointReadOnly(#,#,#)', x, y, z);
+  static DomPointReadOnly _create_3(x, y) =>
+      JS('DomPointReadOnly', 'new DOMPointReadOnly(#,#)', x, y);
+  static DomPointReadOnly _create_4(x) =>
+      JS('DomPointReadOnly', 'new DOMPointReadOnly(#)', x);
+  static DomPointReadOnly _create_5() =>
+      JS('DomPointReadOnly', 'new DOMPointReadOnly()');
+
+  num get w => JS("num", "#.w", this);
+
+  num get x => JS("num", "#.x", this);
+
+  num get y => JS("num", "#.y", this);
+
+  num get z => JS("num", "#.z", this);
+
+  static DomPointReadOnly fromPoint([Map other]) {
+    if (other != null) {
+      var other_1 = convertDartToNative_Dictionary(other);
+      return _fromPoint_1(other_1);
+    }
+    return _fromPoint_2();
+  }
+
+  @JSName('fromPoint')
+  static DomPointReadOnly _fromPoint_1(other) native;
+  @JSName('fromPoint')
+  static DomPointReadOnly _fromPoint_2() native;
+
+  DomPoint matrixTransform([Map matrix]) {
+    if (matrix != null) {
+      var matrix_1 = convertDartToNative_Dictionary(matrix);
+      return _matrixTransform_1(matrix_1);
+    }
+    return _matrixTransform_2();
+  }
+
+  @JSName('matrixTransform')
+  DomPoint _matrixTransform_1(matrix) native;
+  @JSName('matrixTransform')
+  DomPoint _matrixTransform_2() native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("DOMQuad")
+class DomQuad extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory DomQuad._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory DomQuad([Map p1, Map p2, Map p3, Map p4]) {
+    if (p4 != null) {
+      var p1_1 = convertDartToNative_Dictionary(p1);
+      var p2_2 = convertDartToNative_Dictionary(p2);
+      var p3_3 = convertDartToNative_Dictionary(p3);
+      var p4_4 = convertDartToNative_Dictionary(p4);
+      return DomQuad._create_1(p1_1, p2_2, p3_3, p4_4);
+    }
+    if (p3 != null) {
+      var p1_1 = convertDartToNative_Dictionary(p1);
+      var p2_2 = convertDartToNative_Dictionary(p2);
+      var p3_3 = convertDartToNative_Dictionary(p3);
+      return DomQuad._create_2(p1_1, p2_2, p3_3);
+    }
+    if (p2 != null) {
+      var p1_1 = convertDartToNative_Dictionary(p1);
+      var p2_2 = convertDartToNative_Dictionary(p2);
+      return DomQuad._create_3(p1_1, p2_2);
+    }
+    if (p1 != null) {
+      var p1_1 = convertDartToNative_Dictionary(p1);
+      return DomQuad._create_4(p1_1);
+    }
+    return DomQuad._create_5();
+  }
+  static DomQuad _create_1(p1, p2, p3, p4) =>
+      JS('DomQuad', 'new DOMQuad(#,#,#,#)', p1, p2, p3, p4);
+  static DomQuad _create_2(p1, p2, p3) =>
+      JS('DomQuad', 'new DOMQuad(#,#,#)', p1, p2, p3);
+  static DomQuad _create_3(p1, p2) => JS('DomQuad', 'new DOMQuad(#,#)', p1, p2);
+  static DomQuad _create_4(p1) => JS('DomQuad', 'new DOMQuad(#)', p1);
+  static DomQuad _create_5() => JS('DomQuad', 'new DOMQuad()');
+
+  final DomPoint p1;
+
+  final DomPoint p2;
+
+  final DomPoint p3;
+
+  final DomPoint p4;
+
+  static DomQuad fromQuad([Map other]) {
+    if (other != null) {
+      var other_1 = convertDartToNative_Dictionary(other);
+      return _fromQuad_1(other_1);
+    }
+    return _fromQuad_2();
+  }
+
+  @JSName('fromQuad')
+  static DomQuad _fromQuad_1(other) native;
+  @JSName('fromQuad')
+  static DomQuad _fromQuad_2() native;
+
+  static DomQuad fromRect([Map other]) {
+    if (other != null) {
+      var other_1 = convertDartToNative_Dictionary(other);
+      return _fromRect_1(other_1);
+    }
+    return _fromRect_2();
+  }
+
+  @JSName('fromRect')
+  static DomQuad _fromRect_1(other) native;
+  @JSName('fromRect')
+  static DomQuad _fromRect_2() native;
+
+  Rectangle getBounds() native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("ClientRectList,DOMRectList")
+class DomRectList extends Interceptor
+    with ListMixin<Rectangle>, ImmutableListMixin<Rectangle>
+    implements List<Rectangle>, JavaScriptIndexingBehavior<Rectangle> {
+  // To suppress missing implicit constructor warnings.
+  factory DomRectList._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  int get length => JS("int", "#.length", this);
+
+  Rectangle operator [](int index) {
+    if (JS("bool", "# >>> 0 !== # || # >= #", index, index, index, length))
+      throw new RangeError.index(index, this);
+    return JS("Rectangle", "#[#]", this, index);
+  }
+
+  void operator []=(int index, Rectangle value) {
+    throw new UnsupportedError("Cannot assign element of immutable List.");
+  }
+  // -- start List<Rectangle> mixins.
+  // Rectangle is the element type.
+
+  set length(int value) {
+    throw new UnsupportedError("Cannot resize immutable List.");
+  }
+
+  Rectangle get first {
+    if (this.length > 0) {
+      return JS('Rectangle', '#[0]', this);
+    }
+    throw new StateError("No elements");
+  }
+
+  Rectangle get last {
+    int len = this.length;
+    if (len > 0) {
+      return JS('Rectangle', '#[#]', this, len - 1);
+    }
+    throw new StateError("No elements");
+  }
+
+  Rectangle get single {
+    int len = this.length;
+    if (len == 1) {
+      return JS('Rectangle', '#[0]', this);
+    }
+    if (len == 0) throw new StateError("No elements");
+    throw new StateError("More than one element");
+  }
+
+  Rectangle elementAt(int index) => this[index];
+  // -- end List<Rectangle> mixins.
+
+  Rectangle item(int index) native;
+}
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("DOMRectReadOnly")
+class DomRectReadOnly extends Interceptor implements Rectangle {
+  // NOTE! All code below should be common with RectangleBase.
+  String toString() {
+    return 'Rectangle ($left, $top) $width x $height';
+  }
+
+  bool operator ==(other) {
+    if (other is! Rectangle) return false;
+    return left == other.left &&
+        top == other.top &&
+        width == other.width &&
+        height == other.height;
+  }
+
+  int get hashCode => _JenkinsSmiHash.hash4(
+      left.hashCode, top.hashCode, width.hashCode, height.hashCode);
+
+  /**
+   * Computes the intersection of `this` and [other].
+   *
+   * The intersection of two axis-aligned rectangles, if any, is always another
+   * axis-aligned rectangle.
+   *
+   * Returns the intersection of this and `other`, or null if they don't
+   * intersect.
+   */
+  Rectangle intersection(Rectangle other) {
+    var x0 = max(left, other.left);
+    var x1 = min(left + width, other.left + other.width);
+
+    if (x0 <= x1) {
+      var y0 = max(top, other.top);
+      var y1 = min(top + height, other.top + other.height);
+
+      if (y0 <= y1) {
+        return new Rectangle(x0, y0, x1 - x0, y1 - y0);
+      }
+    }
+    return null;
+  }
+
+  /**
+   * Returns true if `this` intersects [other].
+   */
+  bool intersects(Rectangle<num> other) {
+    return (left <= other.left + other.width &&
+        other.left <= left + width &&
+        top <= other.top + other.height &&
+        other.top <= top + height);
+  }
+
+  /**
+   * Returns a new rectangle which completely contains `this` and [other].
+   */
+  Rectangle boundingBox(Rectangle other) {
+    var right = max(this.left + this.width, other.left + other.width);
+    var bottom = max(this.top + this.height, other.top + other.height);
+
+    var left = min(this.left, other.left);
+    var top = min(this.top, other.top);
+
+    return new Rectangle(left, top, right - left, bottom - top);
+  }
+
+  /**
+   * Tests whether `this` entirely contains [another].
+   */
+  bool containsRectangle(Rectangle<num> another) {
+    return left <= another.left &&
+        left + width >= another.left + another.width &&
+        top <= another.top &&
+        top + height >= another.top + another.height;
+  }
+
+  /**
+   * Tests whether [another] is inside or along the edges of `this`.
+   */
+  bool containsPoint(Point<num> another) {
+    return another.x >= left &&
+        another.x <= left + width &&
+        another.y >= top &&
+        another.y <= top + height;
+  }
+
+  Point get topLeft => new Point(this.left, this.top);
+  Point get topRight => new Point(this.left + this.width, this.top);
+  Point get bottomRight =>
+      new Point(this.left + this.width, this.top + this.height);
+  Point get bottomLeft => new Point(this.left, this.top + this.height);
+
+  // To suppress missing implicit constructor warnings.
+  factory DomRectReadOnly._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory DomRectReadOnly([num x, num y, num width, num height]) {
+    if (height != null) {
+      return DomRectReadOnly._create_1(x, y, width, height);
+    }
+    if (width != null) {
+      return DomRectReadOnly._create_2(x, y, width);
+    }
+    if (y != null) {
+      return DomRectReadOnly._create_3(x, y);
+    }
+    if (x != null) {
+      return DomRectReadOnly._create_4(x);
+    }
+    return DomRectReadOnly._create_5();
+  }
+  static DomRectReadOnly _create_1(x, y, width, height) => JS(
+      'DomRectReadOnly', 'new DOMRectReadOnly(#,#,#,#)', x, y, width, height);
+  static DomRectReadOnly _create_2(x, y, width) =>
+      JS('DomRectReadOnly', 'new DOMRectReadOnly(#,#,#)', x, y, width);
+  static DomRectReadOnly _create_3(x, y) =>
+      JS('DomRectReadOnly', 'new DOMRectReadOnly(#,#)', x, y);
+  static DomRectReadOnly _create_4(x) =>
+      JS('DomRectReadOnly', 'new DOMRectReadOnly(#)', x);
+  static DomRectReadOnly _create_5() =>
+      JS('DomRectReadOnly', 'new DOMRectReadOnly()');
+
+  num get bottom => JS("num", "#.bottom", this);
+
+  num get height => JS("num", "#.height", this);
+
+  num get left => JS("num", "#.left", this);
+
+  num get right => JS("num", "#.right", this);
+
+  num get top => JS("num", "#.top", this);
+
+  num get width => JS("num", "#.width", this);
+
+  num get x => JS("num", "#.x", this);
+
+  num get y => JS("num", "#.y", this);
+
+  static DomRectReadOnly fromRect([Map other]) {
+    if (other != null) {
+      var other_1 = convertDartToNative_Dictionary(other);
+      return _fromRect_1(other_1);
+    }
+    return _fromRect_2();
+  }
+
+  @JSName('fromRect')
+  static DomRectReadOnly _fromRect_1(other) native;
+  @JSName('fromRect')
+  static DomRectReadOnly _fromRect_2() native;
+}
+
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("DOMStringList")
+class DomStringList extends Interceptor
+    with ListMixin<String>, ImmutableListMixin<String>
+    implements JavaScriptIndexingBehavior<String>, List<String> {
+  // To suppress missing implicit constructor warnings.
+  factory DomStringList._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  int get length => JS("int", "#.length", this);
+
+  String operator [](int index) {
+    if (JS("bool", "# >>> 0 !== # || # >= #", index, index, index, length))
+      throw new RangeError.index(index, this);
+    return JS("String", "#[#]", this, index);
+  }
+
+  void operator []=(int index, String value) {
+    throw new UnsupportedError("Cannot assign element of immutable List.");
+  }
+  // -- start List<String> mixins.
+  // String is the element type.
+
+  set length(int value) {
+    throw new UnsupportedError("Cannot resize immutable List.");
+  }
+
+  String get first {
+    if (this.length > 0) {
+      return JS('String', '#[0]', this);
+    }
+    throw new StateError("No elements");
+  }
+
+  String get last {
+    int len = this.length;
+    if (len > 0) {
+      return JS('String', '#[#]', this, len - 1);
+    }
+    throw new StateError("No elements");
+  }
+
+  String get single {
+    int len = this.length;
+    if (len == 1) {
+      return JS('String', '#[0]', this);
+    }
+    if (len == 0) throw new StateError("No elements");
+    throw new StateError("More than one element");
+  }
+
+  String elementAt(int index) => this[index];
+  // -- end List<String> mixins.
+
+  String item(int index) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("DOMStringMap")
+class DomStringMap extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory DomStringMap._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  void __delete__(String name) native;
+
+  void __setter__(String name, String value) native;
+
+  String item(String name) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("DOMTokenList")
+class DomTokenList extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory DomTokenList._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final int length;
+
+  String value;
+
+  void add(String tokens) native;
+
+  bool contains(String token) native;
+
+  String item(int index) native;
+
+  void remove(String tokens) native;
+
+  void replace(String token, String newToken) native;
+
+  bool supports(String token) native;
+
+  bool toggle(String token, [bool force]) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+class _ChildrenElementList extends ListBase<Element>
+    implements NodeListWrapper {
+  // Raw Element.
+  final Element _element;
+  final HtmlCollection _childElements;
+
+  _ChildrenElementList._wrap(Element element)
+      : _childElements = element._children,
+        _element = element;
+
+  bool contains(Object element) => _childElements.contains(element);
+
+  bool get isEmpty {
+    return _element._firstElementChild == null;
+  }
+
+  int get length {
+    return _childElements.length;
+  }
+
+  Element operator [](int index) {
+    return _childElements[index];
+  }
+
+  void operator []=(int index, Element value) {
+    _element._replaceChild(value, _childElements[index]);
+  }
+
+  set length(int newLength) {
+    // TODO(jacobr): remove children when length is reduced.
+    throw new UnsupportedError('Cannot resize element lists');
+  }
+
+  Element add(Element value) {
+    _element.append(value);
+    return value;
+  }
+
+  Iterator<Element> get iterator => toList().iterator;
+
+  void addAll(Iterable<Element> iterable) {
+    if (iterable is _ChildNodeListLazy) {
+      iterable = new List.from(iterable);
+    }
+
+    for (Element element in iterable) {
+      _element.append(element);
+    }
+  }
+
+  void sort([int compare(Element a, Element b)]) {
+    throw new UnsupportedError('Cannot sort element lists');
+  }
+
+  void shuffle([Random random]) {
+    throw new UnsupportedError('Cannot shuffle element lists');
+  }
+
+  void removeWhere(bool test(Element element)) {
+    _filter(test, false);
+  }
+
+  void retainWhere(bool test(Element element)) {
+    _filter(test, true);
+  }
+
+  void _filter(bool test(Element element), bool retainMatching) {
+    var removed;
+    if (retainMatching) {
+      removed = _element.children.where((e) => !test(e));
+    } else {
+      removed = _element.children.where(test);
+    }
+    for (var e in removed) e.remove();
+  }
+
+  void fillRange(int start, int end, [Element fillValue]) {
+    throw new UnimplementedError();
+  }
+
+  void replaceRange(int start, int end, Iterable<Element> iterable) {
+    throw new UnimplementedError();
+  }
+
+  void removeRange(int start, int end) {
+    throw new UnimplementedError();
+  }
+
+  void setRange(int start, int end, Iterable<Element> iterable,
+      [int skipCount = 0]) {
+    throw new UnimplementedError();
+  }
+
+  bool remove(Object object) {
+    if (object is Element) {
+      Element element = object;
+      if (identical(element.parentNode, _element)) {
+        _element._removeChild(element);
+        return true;
+      }
+    }
+    return false;
+  }
+
+  void insert(int index, Element element) {
+    if (index < 0 || index > length) {
+      throw new RangeError.range(index, 0, length);
+    }
+    if (index == length) {
+      _element.append(element);
+    } else {
+      _element.insertBefore(element, this[index]);
+    }
+  }
+
+  void setAll(int index, Iterable<Element> iterable) {
+    throw new UnimplementedError();
+  }
+
+  void clear() {
+    _element._clearChildren();
+  }
+
+  Element removeAt(int index) {
+    final result = this[index];
+    if (result != null) {
+      _element._removeChild(result);
+    }
+    return result;
+  }
+
+  Element removeLast() {
+    final result = this.last;
+    if (result != null) {
+      _element._removeChild(result);
+    }
+    return result;
+  }
+
+  Element get first {
+    Element result = _element._firstElementChild;
+    if (result == null) throw new StateError("No elements");
+    return result;
+  }
+
+  Element get last {
+    Element result = _element._lastElementChild;
+    if (result == null) throw new StateError("No elements");
+    return result;
+  }
+
+  Element get single {
+    if (length > 1) throw new StateError("More than one element");
+    return first;
+  }
+
+  List<Node> get rawList => _childElements;
+}
+
+/**
+ * An immutable list containing HTML elements. This list contains some
+ * additional methods when compared to regular lists for ease of CSS
+ * manipulation on a group of elements.
+ */
+abstract class ElementList<T extends Element> extends ListBase<T> {
+  /**
+   * The union of all CSS classes applied to the elements in this list.
+   *
+   * This set makes it easy to add, remove or toggle (add if not present, remove
+   * if present) the classes applied to a collection of elements.
+   *
+   *     htmlList.classes.add('selected');
+   *     htmlList.classes.toggle('isOnline');
+   *     htmlList.classes.remove('selected');
+   */
+  CssClassSet get classes;
+
+  /** Replace the classes with `value` for every element in this list. */
+  set classes(Iterable<String> value);
+
+  /**
+   * Access the union of all [CssStyleDeclaration]s that are associated with an
+   * [ElementList].
+   *
+   * Grouping the style objects all together provides easy editing of specific
+   * properties of a collection of elements. Setting a specific property value
+   * will set that property in all [Element]s in the [ElementList]. Getting a
+   * specific property value will return the value of the property of the first
+   * element in the [ElementList].
+   */
+  CssStyleDeclarationBase get style;
+
+  /**
+   * Access dimensions and position of the Elements in this list.
+   *
+   * Setting the height or width properties will set the height or width
+   * property for all elements in the list. This returns a rectangle with the
+   * dimensions actually available for content
+   * in this element, in pixels, regardless of this element's box-sizing
+   * property. Getting the height or width returns the height or width of the
+   * first Element in this list.
+   *
+   * Unlike [getBoundingClientRect], the dimensions of this rectangle
+   * will return the same numerical height if the element is hidden or not.
+   */
+  CssRect get contentEdge;
+
+  /**
+   * Access dimensions and position of the first Element's content + padding box
+   * in this list.
+   *
+   * This returns a rectangle with the dimensions actually available for content
+   * in this element, in pixels, regardless of this element's box-sizing
+   * property. Unlike [getBoundingClientRect], the dimensions of this rectangle
+   * will return the same numerical height if the element is hidden or not. This
+   * can be used to retrieve jQuery's `innerHeight` value for an element. This
+   * is also a rectangle equalling the dimensions of clientHeight and
+   * clientWidth.
+   */
+  CssRect get paddingEdge;
+
+  /**
+   * Access dimensions and position of the first Element's content + padding +
+   * border box in this list.
+   *
+   * This returns a rectangle with the dimensions actually available for content
+   * in this element, in pixels, regardless of this element's box-sizing
+   * property. Unlike [getBoundingClientRect], the dimensions of this rectangle
+   * will return the same numerical height if the element is hidden or not. This
+   * can be used to retrieve jQuery's `outerHeight` value for an element.
+   */
+  CssRect get borderEdge;
+
+  /**
+   * Access dimensions and position of the first Element's content + padding +
+   * border + margin box in this list.
+   *
+   * This returns a rectangle with the dimensions actually available for content
+   * in this element, in pixels, regardless of this element's box-sizing
+   * property. Unlike [getBoundingClientRect], the dimensions of this rectangle
+   * will return the same numerical height if the element is hidden or not. This
+   * can be used to retrieve jQuery's `outerHeight` value for an element.
+   */
+  CssRect get marginEdge;
+
+  /// Stream of `abort` events handled by this [Element].
+  ElementStream<Event> get onAbort;
+
+  /// Stream of `beforecopy` events handled by this [Element].
+  ElementStream<Event> get onBeforeCopy;
+
+  /// Stream of `beforecut` events handled by this [Element].
+  ElementStream<Event> get onBeforeCut;
+
+  /// Stream of `beforepaste` events handled by this [Element].
+  ElementStream<Event> get onBeforePaste;
+
+  /// Stream of `blur` events handled by this [Element].
+  ElementStream<Event> get onBlur;
+
+  ElementStream<Event> get onCanPlay;
+
+  ElementStream<Event> get onCanPlayThrough;
+
+  /// Stream of `change` events handled by this [Element].
+  ElementStream<Event> get onChange;
+
+  /// Stream of `click` events handled by this [Element].
+  ElementStream<MouseEvent> get onClick;
+
+  /// Stream of `contextmenu` events handled by this [Element].
+  ElementStream<MouseEvent> get onContextMenu;
+
+  /// Stream of `copy` events handled by this [Element].
+  ElementStream<ClipboardEvent> get onCopy;
+
+  /// Stream of `cut` events handled by this [Element].
+  ElementStream<ClipboardEvent> get onCut;
+
+  /// Stream of `doubleclick` events handled by this [Element].
+  @DomName('Element.ondblclick')
+  ElementStream<Event> get onDoubleClick;
+
+  /**
+   * A stream of `drag` events fired when this element currently being dragged.
+   *
+   * A `drag` event is added to this stream as soon as the drag begins.
+   * A `drag` event is also added to this stream at intervals while the drag
+   * operation is still ongoing.
+   *
+   * ## Other resources
+   *
+   * * [Drag and drop
+   *   sample](https://github.com/dart-lang/dart-samples/tree/master/html5/web/dnd/basics)
+   *   based on [the tutorial](http://www.html5rocks.com/en/tutorials/dnd/basics/)
+   *   from HTML5Rocks.
+   * * [Drag and drop
+   *   specification](https://html.spec.whatwg.org/multipage/interaction.html#dnd)
+   *   from WHATWG.
+   */
+  ElementStream<MouseEvent> get onDrag;
+
+  /**
+   * A stream of `dragend` events fired when this element completes a drag
+   * operation.
+   *
+   * ## Other resources
+   *
+   * * [Drag and drop
+   *   sample](https://github.com/dart-lang/dart-samples/tree/master/html5/web/dnd/basics)
+   *   based on [the tutorial](http://www.html5rocks.com/en/tutorials/dnd/basics/)
+   *   from HTML5Rocks.
+   * * [Drag and drop
+   *   specification](https://html.spec.whatwg.org/multipage/interaction.html#dnd)
+   *   from WHATWG.
+   */
+  ElementStream<MouseEvent> get onDragEnd;
+
+  /**
+   * A stream of `dragenter` events fired when a dragged object is first dragged
+   * over this element.
+   *
+   * ## Other resources
+   *
+   * * [Drag and drop
+   *   sample](https://github.com/dart-lang/dart-samples/tree/master/html5/web/dnd/basics)
+   *   based on [the tutorial](http://www.html5rocks.com/en/tutorials/dnd/basics/)
+   *   from HTML5Rocks.
+   * * [Drag and drop
+   *   specification](https://html.spec.whatwg.org/multipage/interaction.html#dnd)
+   *   from WHATWG.
+   */
+  ElementStream<MouseEvent> get onDragEnter;
+
+  /**
+   * A stream of `dragleave` events fired when an object being dragged over this
+   * element leaves this element's target area.
+   *
+   * ## Other resources
+   *
+   * * [Drag and drop
+   *   sample](https://github.com/dart-lang/dart-samples/tree/master/html5/web/dnd/basics)
+   *   based on [the tutorial](http://www.html5rocks.com/en/tutorials/dnd/basics/)
+   *   from HTML5Rocks.
+   * * [Drag and drop
+   *   specification](https://html.spec.whatwg.org/multipage/interaction.html#dnd)
+   *   from WHATWG.
+   */
+  ElementStream<MouseEvent> get onDragLeave;
+
+  /**
+   * A stream of `dragover` events fired when a dragged object is currently
+   * being dragged over this element.
+   *
+   * ## Other resources
+   *
+   * * [Drag and drop
+   *   sample](https://github.com/dart-lang/dart-samples/tree/master/html5/web/dnd/basics)
+   *   based on [the tutorial](http://www.html5rocks.com/en/tutorials/dnd/basics/)
+   *   from HTML5Rocks.
+   * * [Drag and drop
+   *   specification](https://html.spec.whatwg.org/multipage/interaction.html#dnd)
+   *   from WHATWG.
+   */
+  ElementStream<MouseEvent> get onDragOver;
+
+  /**
+   * A stream of `dragstart` events fired when this element starts being
+   * dragged.
+   *
+   * ## Other resources
+   *
+   * * [Drag and drop
+   *   sample](https://github.com/dart-lang/dart-samples/tree/master/html5/web/dnd/basics)
+   *   based on [the tutorial](http://www.html5rocks.com/en/tutorials/dnd/basics/)
+   *   from HTML5Rocks.
+   * * [Drag and drop
+   *   specification](https://html.spec.whatwg.org/multipage/interaction.html#dnd)
+   *   from WHATWG.
+   */
+  ElementStream<MouseEvent> get onDragStart;
+
+  /**
+   * A stream of `drop` events fired when a dragged object is dropped on this
+   * element.
+   *
+   * ## Other resources
+   *
+   * * [Drag and drop
+   *   sample](https://github.com/dart-lang/dart-samples/tree/master/html5/web/dnd/basics)
+   *   based on [the tutorial](http://www.html5rocks.com/en/tutorials/dnd/basics/)
+   *   from HTML5Rocks.
+   * * [Drag and drop
+   *   specification](https://html.spec.whatwg.org/multipage/interaction.html#dnd)
+   *   from WHATWG.
+   */
+  ElementStream<MouseEvent> get onDrop;
+
+  ElementStream<Event> get onDurationChange;
+
+  ElementStream<Event> get onEmptied;
+
+  ElementStream<Event> get onEnded;
+
+  /// Stream of `error` events handled by this [Element].
+  ElementStream<Event> get onError;
+
+  /// Stream of `focus` events handled by this [Element].
+  ElementStream<Event> get onFocus;
+
+  /// Stream of `input` events handled by this [Element].
+  ElementStream<Event> get onInput;
+
+  /// Stream of `invalid` events handled by this [Element].
+  ElementStream<Event> get onInvalid;
+
+  /// Stream of `keydown` events handled by this [Element].
+  ElementStream<KeyboardEvent> get onKeyDown;
+
+  /// Stream of `keypress` events handled by this [Element].
+  ElementStream<KeyboardEvent> get onKeyPress;
+
+  /// Stream of `keyup` events handled by this [Element].
+  ElementStream<KeyboardEvent> get onKeyUp;
+
+  /// Stream of `load` events handled by this [Element].
+  ElementStream<Event> get onLoad;
+
+  ElementStream<Event> get onLoadedData;
+
+  ElementStream<Event> get onLoadedMetadata;
+
+  /// Stream of `mousedown` events handled by this [Element].
+  ElementStream<MouseEvent> get onMouseDown;
+
+  /// Stream of `mouseenter` events handled by this [Element].
+  ElementStream<MouseEvent> get onMouseEnter;
+
+  /// Stream of `mouseleave` events handled by this [Element].
+  ElementStream<MouseEvent> get onMouseLeave;
+
+  /// Stream of `mousemove` events handled by this [Element].
+  ElementStream<MouseEvent> get onMouseMove;
+
+  /// Stream of `mouseout` events handled by this [Element].
+  ElementStream<MouseEvent> get onMouseOut;
+
+  /// Stream of `mouseover` events handled by this [Element].
+  ElementStream<MouseEvent> get onMouseOver;
+
+  /// Stream of `mouseup` events handled by this [Element].
+  ElementStream<MouseEvent> get onMouseUp;
+
+  /// Stream of `mousewheel` events handled by this [Element].
+  ElementStream<WheelEvent> get onMouseWheel;
+
+  /// Stream of `paste` events handled by this [Element].
+  ElementStream<ClipboardEvent> get onPaste;
+
+  ElementStream<Event> get onPause;
+
+  ElementStream<Event> get onPlay;
+
+  ElementStream<Event> get onPlaying;
+
+  ElementStream<Event> get onRateChange;
+
+  /// Stream of `reset` events handled by this [Element].
+  ElementStream<Event> get onReset;
+
+  ElementStream<Event> get onResize;
+
+  /// Stream of `scroll` events handled by this [Element].
+  ElementStream<Event> get onScroll;
+
+  /// Stream of `search` events handled by this [Element].
+  ElementStream<Event> get onSearch;
+
+  ElementStream<Event> get onSeeked;
+
+  ElementStream<Event> get onSeeking;
+
+  /// Stream of `select` events handled by this [Element].
+  ElementStream<Event> get onSelect;
+
+  /// Stream of `selectstart` events handled by this [Element].
+  ElementStream<Event> get onSelectStart;
+
+  ElementStream<Event> get onStalled;
+
+  /// Stream of `submit` events handled by this [Element].
+  ElementStream<Event> get onSubmit;
+
+  ElementStream<Event> get onSuspend;
+
+  ElementStream<Event> get onTimeUpdate;
+
+  /// Stream of `touchcancel` events handled by this [Element].
+  ElementStream<TouchEvent> get onTouchCancel;
+
+  /// Stream of `touchend` events handled by this [Element].
+  ElementStream<TouchEvent> get onTouchEnd;
+
+  /// Stream of `touchenter` events handled by this [Element].
+  ElementStream<TouchEvent> get onTouchEnter;
+
+  /// Stream of `touchleave` events handled by this [Element].
+  ElementStream<TouchEvent> get onTouchLeave;
+
+  /// Stream of `touchmove` events handled by this [Element].
+  ElementStream<TouchEvent> get onTouchMove;
+
+  /// Stream of `touchstart` events handled by this [Element].
+  ElementStream<TouchEvent> get onTouchStart;
+
+  /// Stream of `transitionend` events handled by this [Element].
+  @SupportedBrowser(SupportedBrowser.CHROME)
+  @SupportedBrowser(SupportedBrowser.FIREFOX)
+  @SupportedBrowser(SupportedBrowser.IE, '10')
+  @SupportedBrowser(SupportedBrowser.SAFARI)
+  ElementStream<TransitionEvent> get onTransitionEnd;
+
+  ElementStream<Event> get onVolumeChange;
+
+  ElementStream<Event> get onWaiting;
+
+  /// Stream of `fullscreenchange` events handled by this [Element].
+  ElementStream<Event> get onFullscreenChange;
+
+  /// Stream of `fullscreenerror` events handled by this [Element].
+  ElementStream<Event> get onFullscreenError;
+
+  ElementStream<WheelEvent> get onWheel;
+}
+
+// Wrapper over an immutable NodeList to make it implement ElementList.
+//
+// Clients are {`Document`, `DocumentFragment`}.`querySelectorAll` which are
+// declared to return `ElementList`.  This provides all the static analysis
+// benefit so there is no need for this class have a constrained type parameter.
+//
+class _FrozenElementList<E extends Element> extends ListBase<E>
+    implements ElementList<E>, NodeListWrapper {
+  final List<Node> _nodeList;
+
+  _FrozenElementList._wrap(this._nodeList) {
+    assert(this._nodeList.every((element) => element is E),
+        "Query expects only HTML elements of type $E but found ${this._nodeList.firstWhere((e) => e is! E)}");
+  }
+
+  int get length => _nodeList.length;
+
+  E operator [](int index) => _nodeList[index];
+
+  void operator []=(int index, E value) {
+    throw new UnsupportedError('Cannot modify list');
+  }
+
+  set length(int newLength) {
+    throw new UnsupportedError('Cannot modify list');
+  }
+
+  void sort([Comparator<E> compare]) {
+    throw new UnsupportedError('Cannot sort list');
+  }
+
+  void shuffle([Random random]) {
+    throw new UnsupportedError('Cannot shuffle list');
+  }
+
+  E get first => _nodeList.first;
+
+  E get last => _nodeList.last;
+
+  E get single => _nodeList.single;
+
+  CssClassSet get classes => new _MultiElementCssClassSet(this);
+
+  CssStyleDeclarationBase get style => new _CssStyleDeclarationSet(this);
+
+  set classes(Iterable<String> value) {
+    // TODO(sra): This might be faster for Sets:
+    //
+    //     new _MultiElementCssClassSet(this).writeClasses(value)
+    //
+    // as the code below converts the Iterable[value] to a string multiple
+    // times.  Maybe compute the string and set className here.
+    forEach((e) => e.classes = value);
+  }
+
+  CssRect get contentEdge => new _ContentCssListRect(this);
+
+  CssRect get paddingEdge => this.first.paddingEdge;
+
+  CssRect get borderEdge => this.first.borderEdge;
+
+  CssRect get marginEdge => this.first.marginEdge;
+
+  List<Node> get rawList => _nodeList;
+
+  /// Stream of `abort` events handled by this [Element].
+  ElementStream<Event> get onAbort => Element.abortEvent._forElementList(this);
+
+  /// Stream of `beforecopy` events handled by this [Element].
+  ElementStream<Event> get onBeforeCopy =>
+      Element.beforeCopyEvent._forElementList(this);
+
+  /// Stream of `beforecut` events handled by this [Element].
+  ElementStream<Event> get onBeforeCut =>
+      Element.beforeCutEvent._forElementList(this);
+
+  /// Stream of `beforepaste` events handled by this [Element].
+  ElementStream<Event> get onBeforePaste =>
+      Element.beforePasteEvent._forElementList(this);
+
+  /// Stream of `blur` events handled by this [Element].
+  ElementStream<Event> get onBlur => Element.blurEvent._forElementList(this);
+
+  ElementStream<Event> get onCanPlay =>
+      Element.canPlayEvent._forElementList(this);
+
+  ElementStream<Event> get onCanPlayThrough =>
+      Element.canPlayThroughEvent._forElementList(this);
+
+  /// Stream of `change` events handled by this [Element].
+  ElementStream<Event> get onChange =>
+      Element.changeEvent._forElementList(this);
+
+  /// Stream of `click` events handled by this [Element].
+  ElementStream<MouseEvent> get onClick =>
+      Element.clickEvent._forElementList(this);
+
+  /// Stream of `contextmenu` events handled by this [Element].
+  ElementStream<MouseEvent> get onContextMenu =>
+      Element.contextMenuEvent._forElementList(this);
+
+  /// Stream of `copy` events handled by this [Element].
+  ElementStream<ClipboardEvent> get onCopy =>
+      Element.copyEvent._forElementList(this);
+
+  /// Stream of `cut` events handled by this [Element].
+  ElementStream<ClipboardEvent> get onCut =>
+      Element.cutEvent._forElementList(this);
+
+  /// Stream of `doubleclick` events handled by this [Element].
+  @DomName('Element.ondblclick')
+  ElementStream<Event> get onDoubleClick =>
+      Element.doubleClickEvent._forElementList(this);
+
+  /**
+   * A stream of `drag` events fired when this element currently being dragged.
+   *
+   * A `drag` event is added to this stream as soon as the drag begins.
+   * A `drag` event is also added to this stream at intervals while the drag
+   * operation is still ongoing.
+   *
+   * ## Other resources
+   *
+   * * [Drag and drop
+   *   sample](https://github.com/dart-lang/dart-samples/tree/master/html5/web/dnd/basics)
+   *   based on [the tutorial](http://www.html5rocks.com/en/tutorials/dnd/basics/)
+   *   from HTML5Rocks.
+   * * [Drag and drop
+   *   specification](https://html.spec.whatwg.org/multipage/interaction.html#dnd)
+   *   from WHATWG.
+   */
+  ElementStream<MouseEvent> get onDrag =>
+      Element.dragEvent._forElementList(this);
+
+  /**
+   * A stream of `dragend` events fired when this element completes a drag
+   * operation.
+   *
+   * ## Other resources
+   *
+   * * [Drag and drop
+   *   sample](https://github.com/dart-lang/dart-samples/tree/master/html5/web/dnd/basics)
+   *   based on [the tutorial](http://www.html5rocks.com/en/tutorials/dnd/basics/)
+   *   from HTML5Rocks.
+   * * [Drag and drop
+   *   specification](https://html.spec.whatwg.org/multipage/interaction.html#dnd)
+   *   from WHATWG.
+   */
+  ElementStream<MouseEvent> get onDragEnd =>
+      Element.dragEndEvent._forElementList(this);
+
+  /**
+   * A stream of `dragenter` events fired when a dragged object is first dragged
+   * over this element.
+   *
+   * ## Other resources
+   *
+   * * [Drag and drop
+   *   sample](https://github.com/dart-lang/dart-samples/tree/master/html5/web/dnd/basics)
+   *   based on [the tutorial](http://www.html5rocks.com/en/tutorials/dnd/basics/)
+   *   from HTML5Rocks.
+   * * [Drag and drop
+   *   specification](https://html.spec.whatwg.org/multipage/interaction.html#dnd)
+   *   from WHATWG.
+   */
+  ElementStream<MouseEvent> get onDragEnter =>
+      Element.dragEnterEvent._forElementList(this);
+
+  /**
+   * A stream of `dragleave` events fired when an object being dragged over this
+   * element leaves this element's target area.
+   *
+   * ## Other resources
+   *
+   * * [Drag and drop
+   *   sample](https://github.com/dart-lang/dart-samples/tree/master/html5/web/dnd/basics)
+   *   based on [the tutorial](http://www.html5rocks.com/en/tutorials/dnd/basics/)
+   *   from HTML5Rocks.
+   * * [Drag and drop
+   *   specification](https://html.spec.whatwg.org/multipage/interaction.html#dnd)
+   *   from WHATWG.
+   */
+  ElementStream<MouseEvent> get onDragLeave =>
+      Element.dragLeaveEvent._forElementList(this);
+
+  /**
+   * A stream of `dragover` events fired when a dragged object is currently
+   * being dragged over this element.
+   *
+   * ## Other resources
+   *
+   * * [Drag and drop
+   *   sample](https://github.com/dart-lang/dart-samples/tree/master/html5/web/dnd/basics)
+   *   based on [the tutorial](http://www.html5rocks.com/en/tutorials/dnd/basics/)
+   *   from HTML5Rocks.
+   * * [Drag and drop
+   *   specification](https://html.spec.whatwg.org/multipage/interaction.html#dnd)
+   *   from WHATWG.
+   */
+  ElementStream<MouseEvent> get onDragOver =>
+      Element.dragOverEvent._forElementList(this);
+
+  /**
+   * A stream of `dragstart` events fired when this element starts being
+   * dragged.
+   *
+   * ## Other resources
+   *
+   * * [Drag and drop
+   *   sample](https://github.com/dart-lang/dart-samples/tree/master/html5/web/dnd/basics)
+   *   based on [the tutorial](http://www.html5rocks.com/en/tutorials/dnd/basics/)
+   *   from HTML5Rocks.
+   * * [Drag and drop
+   *   specification](https://html.spec.whatwg.org/multipage/interaction.html#dnd)
+   *   from WHATWG.
+   */
+  ElementStream<MouseEvent> get onDragStart =>
+      Element.dragStartEvent._forElementList(this);
+
+  /**
+   * A stream of `drop` events fired when a dragged object is dropped on this
+   * element.
+   *
+   * ## Other resources
+   *
+   * * [Drag and drop
+   *   sample](https://github.com/dart-lang/dart-samples/tree/master/html5/web/dnd/basics)
+   *   based on [the tutorial](http://www.html5rocks.com/en/tutorials/dnd/basics/)
+   *   from HTML5Rocks.
+   * * [Drag and drop
+   *   specification](https://html.spec.whatwg.org/multipage/interaction.html#dnd)
+   *   from WHATWG.
+   */
+  ElementStream<MouseEvent> get onDrop =>
+      Element.dropEvent._forElementList(this);
+
+  ElementStream<Event> get onDurationChange =>
+      Element.durationChangeEvent._forElementList(this);
+
+  ElementStream<Event> get onEmptied =>
+      Element.emptiedEvent._forElementList(this);
+
+  ElementStream<Event> get onEnded => Element.endedEvent._forElementList(this);
+
+  /// Stream of `error` events handled by this [Element].
+  ElementStream<Event> get onError => Element.errorEvent._forElementList(this);
+
+  /// Stream of `focus` events handled by this [Element].
+  ElementStream<Event> get onFocus => Element.focusEvent._forElementList(this);
+
+  /// Stream of `input` events handled by this [Element].
+  ElementStream<Event> get onInput => Element.inputEvent._forElementList(this);
+
+  /// Stream of `invalid` events handled by this [Element].
+  ElementStream<Event> get onInvalid =>
+      Element.invalidEvent._forElementList(this);
+
+  /// Stream of `keydown` events handled by this [Element].
+  ElementStream<KeyboardEvent> get onKeyDown =>
+      Element.keyDownEvent._forElementList(this);
+
+  /// Stream of `keypress` events handled by this [Element].
+  ElementStream<KeyboardEvent> get onKeyPress =>
+      Element.keyPressEvent._forElementList(this);
+
+  /// Stream of `keyup` events handled by this [Element].
+  ElementStream<KeyboardEvent> get onKeyUp =>
+      Element.keyUpEvent._forElementList(this);
+
+  /// Stream of `load` events handled by this [Element].
+  ElementStream<Event> get onLoad => Element.loadEvent._forElementList(this);
+
+  ElementStream<Event> get onLoadedData =>
+      Element.loadedDataEvent._forElementList(this);
+
+  ElementStream<Event> get onLoadedMetadata =>
+      Element.loadedMetadataEvent._forElementList(this);
+
+  /// Stream of `mousedown` events handled by this [Element].
+  ElementStream<MouseEvent> get onMouseDown =>
+      Element.mouseDownEvent._forElementList(this);
+
+  /// Stream of `mouseenter` events handled by this [Element].
+  ElementStream<MouseEvent> get onMouseEnter =>
+      Element.mouseEnterEvent._forElementList(this);
+
+  /// Stream of `mouseleave` events handled by this [Element].
+  ElementStream<MouseEvent> get onMouseLeave =>
+      Element.mouseLeaveEvent._forElementList(this);
+
+  /// Stream of `mousemove` events handled by this [Element].
+  ElementStream<MouseEvent> get onMouseMove =>
+      Element.mouseMoveEvent._forElementList(this);
+
+  /// Stream of `mouseout` events handled by this [Element].
+  ElementStream<MouseEvent> get onMouseOut =>
+      Element.mouseOutEvent._forElementList(this);
+
+  /// Stream of `mouseover` events handled by this [Element].
+  ElementStream<MouseEvent> get onMouseOver =>
+      Element.mouseOverEvent._forElementList(this);
+
+  /// Stream of `mouseup` events handled by this [Element].
+  ElementStream<MouseEvent> get onMouseUp =>
+      Element.mouseUpEvent._forElementList(this);
+
+  /// Stream of `mousewheel` events handled by this [Element].
+  ElementStream<WheelEvent> get onMouseWheel =>
+      Element.mouseWheelEvent._forElementList(this);
+
+  /// Stream of `paste` events handled by this [Element].
+  ElementStream<ClipboardEvent> get onPaste =>
+      Element.pasteEvent._forElementList(this);
+
+  ElementStream<Event> get onPause => Element.pauseEvent._forElementList(this);
+
+  ElementStream<Event> get onPlay => Element.playEvent._forElementList(this);
+
+  ElementStream<Event> get onPlaying =>
+      Element.playingEvent._forElementList(this);
+
+  ElementStream<Event> get onRateChange =>
+      Element.rateChangeEvent._forElementList(this);
+
+  /// Stream of `reset` events handled by this [Element].
+  ElementStream<Event> get onReset => Element.resetEvent._forElementList(this);
+
+  ElementStream<Event> get onResize =>
+      Element.resizeEvent._forElementList(this);
+
+  /// Stream of `scroll` events handled by this [Element].
+  ElementStream<Event> get onScroll =>
+      Element.scrollEvent._forElementList(this);
+
+  /// Stream of `search` events handled by this [Element].
+  ElementStream<Event> get onSearch =>
+      Element.searchEvent._forElementList(this);
+
+  ElementStream<Event> get onSeeked =>
+      Element.seekedEvent._forElementList(this);
+
+  ElementStream<Event> get onSeeking =>
+      Element.seekingEvent._forElementList(this);
+
+  /// Stream of `select` events handled by this [Element].
+  ElementStream<Event> get onSelect =>
+      Element.selectEvent._forElementList(this);
+
+  /// Stream of `selectstart` events handled by this [Element].
+  ElementStream<Event> get onSelectStart =>
+      Element.selectStartEvent._forElementList(this);
+
+  ElementStream<Event> get onStalled =>
+      Element.stalledEvent._forElementList(this);
+
+  /// Stream of `submit` events handled by this [Element].
+  ElementStream<Event> get onSubmit =>
+      Element.submitEvent._forElementList(this);
+
+  ElementStream<Event> get onSuspend =>
+      Element.suspendEvent._forElementList(this);
+
+  ElementStream<Event> get onTimeUpdate =>
+      Element.timeUpdateEvent._forElementList(this);
+
+  /// Stream of `touchcancel` events handled by this [Element].
+  ElementStream<TouchEvent> get onTouchCancel =>
+      Element.touchCancelEvent._forElementList(this);
+
+  /// Stream of `touchend` events handled by this [Element].
+  ElementStream<TouchEvent> get onTouchEnd =>
+      Element.touchEndEvent._forElementList(this);
+
+  /// Stream of `touchenter` events handled by this [Element].
+  ElementStream<TouchEvent> get onTouchEnter =>
+      Element.touchEnterEvent._forElementList(this);
+
+  /// Stream of `touchleave` events handled by this [Element].
+  ElementStream<TouchEvent> get onTouchLeave =>
+      Element.touchLeaveEvent._forElementList(this);
+
+  /// Stream of `touchmove` events handled by this [Element].
+  ElementStream<TouchEvent> get onTouchMove =>
+      Element.touchMoveEvent._forElementList(this);
+
+  /// Stream of `touchstart` events handled by this [Element].
+  ElementStream<TouchEvent> get onTouchStart =>
+      Element.touchStartEvent._forElementList(this);
+
+  /// Stream of `transitionend` events handled by this [Element].
+  @SupportedBrowser(SupportedBrowser.CHROME)
+  @SupportedBrowser(SupportedBrowser.FIREFOX)
+  @SupportedBrowser(SupportedBrowser.IE, '10')
+  @SupportedBrowser(SupportedBrowser.SAFARI)
+  ElementStream<TransitionEvent> get onTransitionEnd =>
+      Element.transitionEndEvent._forElementList(this);
+
+  ElementStream<Event> get onVolumeChange =>
+      Element.volumeChangeEvent._forElementList(this);
+
+  ElementStream<Event> get onWaiting =>
+      Element.waitingEvent._forElementList(this);
+
+  /// Stream of `fullscreenchange` events handled by this [Element].
+  ElementStream<Event> get onFullscreenChange =>
+      Element.fullscreenChangeEvent._forElementList(this);
+
+  /// Stream of `fullscreenerror` events handled by this [Element].
+  ElementStream<Event> get onFullscreenError =>
+      Element.fullscreenErrorEvent._forElementList(this);
+
+  ElementStream<WheelEvent> get onWheel =>
+      Element.wheelEvent._forElementList(this);
+}
+
+/**
+ * An abstract class, which all HTML elements extend.
+ */
+@Native("Element")
+class Element extends Node
+    implements
+        NonDocumentTypeChildNode,
+        GlobalEventHandlers,
+        ParentNode,
+        ChildNode {
+  /**
+   * Creates an HTML element from a valid fragment of HTML.
+   *
+   *     var element = new Element.html('<div class="foo">content</div>');
+   *
+   * The HTML fragment should contain only one single root element, any
+   * leading or trailing text nodes will be removed.
+   *
+   * The HTML fragment is parsed as if it occurred within the context of a
+   * `<body>` tag, this means that special elements such as `<caption>` which
+   * must be parsed within the scope of a `<table>` element will be dropped. Use
+   * [createFragment] to parse contextual HTML fragments.
+   *
+   * Unless a validator is provided this will perform the default validation
+   * and remove all scriptable elements and attributes.
+   *
+   * See also:
+   *
+   * * [NodeValidator]
+   *
+   */
+  factory Element.html(String html,
+      {NodeValidator validator, NodeTreeSanitizer treeSanitizer}) {
+    var fragment = document.body.createFragment(html,
+        validator: validator, treeSanitizer: treeSanitizer);
+
+    return fragment.nodes.where((e) => e is Element).single;
+  }
+
+  /**
+   * Custom element creation constructor.
+   *
+   * This constructor is used by the DOM when a custom element has been
+   * created. It can only be invoked by subclasses of Element from
+   * that classes created constructor.
+   *
+   *     class CustomElement extends Element {
+   *       factory CustomElement() => new Element.tag('x-custom');
+   *
+   *       CustomElement.created() : super.created() {
+   *          // Perform any element initialization.
+   *       }
+   *     }
+   *     document.registerElement('x-custom', CustomElement);
+   */
+  Element.created() : super._created();
+
+  /**
+   * Creates the HTML element specified by the tag name.
+   *
+   * This is similar to [Document.createElement].
+   * [tag] should be a valid HTML tag name. If [tag] is an unknown tag then
+   * this will create an [UnknownElement].
+   *
+   *     var divElement = new Element.tag('div');
+   *     print(divElement is DivElement); // 'true'
+   *     var myElement = new Element.tag('unknownTag');
+   *     print(myElement is UnknownElement); // 'true'
+   *
+   * For standard elements it is better to use the element type constructors:
+   *
+   *     var element = new DivElement();
+   *
+   * It is better to use e.g `new CanvasElement()` because the type of the
+   * expression is `CanvasElement`, whereas the type of `Element.tag` is the
+   * less specific `Element`.
+   *
+   * See also:
+   *
+   * * [isTagSupported]
+   */
+  factory Element.tag(String tag, [String typeExtention]) =>
+      _ElementFactoryProvider.createElement_tag(tag, typeExtention);
+
+  /// Creates a new `<a>` element.
+  ///
+  /// This is equivalent to calling `new Element.tag('a')`.
+  factory Element.a() => new AnchorElement();
+
+  /// Creates a new `<article>` element.
+  ///
+  /// This is equivalent to calling `new Element.tag('article')`.
+  factory Element.article() => new Element.tag('article');
+
+  /// Creates a new `<aside>` element.
+  ///
+  /// This is equivalent to calling `new Element.tag('aside')`.
+  factory Element.aside() => new Element.tag('aside');
+
+  /// Creates a new `<audio>` element.
+  ///
+  /// This is equivalent to calling `new Element.tag('audio')`.
+  factory Element.audio() => new Element.tag('audio');
+
+  /// Creates a new `<br>` element.
+  ///
+  /// This is equivalent to calling `new Element.tag('br')`.
+  factory Element.br() => new BRElement();
+
+  /// Creates a new `<canvas>` element.
+  ///
+  /// This is equivalent to calling `new Element.tag('canvas')`.
+  factory Element.canvas() => new CanvasElement();
+
+  /// Creates a new `<div>` element.
+  ///
+  /// This is equivalent to calling `new Element.tag('div')`.
+  factory Element.div() => new DivElement();
+
+  /// Creates a new `<footer>` element.
+  ///
+  /// This is equivalent to calling `new Element.tag('footer')`.
+  factory Element.footer() => new Element.tag('footer');
+
+  /// Creates a new `<header>` element.
+  ///
+  /// This is equivalent to calling `new Element.tag('header')`.
+  factory Element.header() => new Element.tag('header');
+
+  /// Creates a new `<hr>` element.
+  ///
+  /// This is equivalent to calling `new Element.tag('hr')`.
+  factory Element.hr() => new Element.tag('hr');
+
+  /// Creates a new `<iframe>` element.
+  ///
+  /// This is equivalent to calling `new Element.tag('iframe')`.
+  factory Element.iframe() => new Element.tag('iframe');
+
+  /// Creates a new `<img>` element.
+  ///
+  /// This is equivalent to calling `new Element.tag('img')`.
+  factory Element.img() => new Element.tag('img');
+
+  /// Creates a new `<li>` element.
+  ///
+  /// This is equivalent to calling `new Element.tag('li')`.
+  factory Element.li() => new Element.tag('li');
+
+  /// Creates a new `<nav>` element.
+  ///
+  /// This is equivalent to calling `new Element.tag('nav')`.
+  factory Element.nav() => new Element.tag('nav');
+
+  /// Creates a new `<ol>` element.
+  ///
+  /// This is equivalent to calling `new Element.tag('ol')`.
+  factory Element.ol() => new Element.tag('ol');
+
+  /// Creates a new `<option>` element.
+  ///
+  /// This is equivalent to calling `new Element.tag('option')`.
+  factory Element.option() => new Element.tag('option');
+
+  /// Creates a new `<p>` element.
+  ///
+  /// This is equivalent to calling `new Element.tag('p')`.
+  factory Element.p() => new Element.tag('p');
+
+  /// Creates a new `<pre>` element.
+  ///
+  /// This is equivalent to calling `new Element.tag('pre')`.
+  factory Element.pre() => new Element.tag('pre');
+
+  /// Creates a new `<section>` element.
+  ///
+  /// This is equivalent to calling `new Element.tag('section')`.
+  factory Element.section() => new Element.tag('section');
+
+  /// Creates a new `<select>` element.
+  ///
+  /// This is equivalent to calling `new Element.tag('select')`.
+  factory Element.select() => new Element.tag('select');
+
+  /// Creates a new `<span>` element.
+  ///
+  /// This is equivalent to calling `new Element.tag('span')`.
+  factory Element.span() => new Element.tag('span');
+
+  /// Creates a new `<svg>` element.
+  ///
+  /// This is equivalent to calling `new Element.tag('svg')`.
+  factory Element.svg() => new Element.tag('svg');
+
+  /// Creates a new `<table>` element.
+  ///
+  /// This is equivalent to calling `new Element.tag('table')`.
+  factory Element.table() => new Element.tag('table');
+
+  /// Creates a new `<td>` element.
+  ///
+  /// This is equivalent to calling `new Element.tag('td')`.
+  factory Element.td() => new Element.tag('td');
+
+  /// Creates a new `<textarea>` element.
+  ///
+  /// This is equivalent to calling `new Element.tag('textarea')`.
+  factory Element.textarea() => new Element.tag('textarea');
+
+  /// Creates a new `<th>` element.
+  ///
+  /// This is equivalent to calling `new Element.tag('th')`.
+  factory Element.th() => new Element.tag('th');
+
+  /// Creates a new `<tr>` element.
+  ///
+  /// This is equivalent to calling `new Element.tag('tr')`.
+  factory Element.tr() => new Element.tag('tr');
+
+  /// Creates a new `<ul>` element.
+  ///
+  /// This is equivalent to calling `new Element.tag('ul')`.
+  factory Element.ul() => new Element.tag('ul');
+
+  /// Creates a new `<video>` element.
+  ///
+  /// This is equivalent to calling `new Element.tag('video')`.
+  factory Element.video() => new Element.tag('video');
+
+  /**
+   * All attributes on this element.
+   *
+   * Any modifications to the attribute map will automatically be applied to
+   * this element.
+   *
+   * This only includes attributes which are not in a namespace
+   * (such as 'xlink:href'), additional attributes can be accessed via
+   * [getNamespacedAttributes].
+   */
+  Map<String, String> get attributes => new _ElementAttributeMap(this);
+
+  set attributes(Map<String, String> value) {
+    Map<String, String> attributes = this.attributes;
+    attributes.clear();
+    for (String key in value.keys) {
+      attributes[key] = value[key];
+    }
+  }
+
+  @pragma('dart2js:tryInline')
+  String getAttribute(String name) {
+    // Protect [name] against string conversion to "null" or "undefined".
+    assert(name != null, 'Attribute name cannot be null');
+    return _getAttribute(name);
+  }
+
+  @pragma('dart2js:tryInline')
+  String getAttributeNS(String namespaceURI, String name) {
+    // Protect [name] against string conversion to "null" or "undefined".
+    // [namespaceURI] does not need protecting, both `null` and `undefined` map to `null`.
+    assert(name != null, 'Attribute name cannot be null');
+    return _getAttributeNS(namespaceURI, name);
+  }
+
+  @pragma('dart2js:tryInline')
+  bool hasAttribute(String name) {
+    // Protect [name] against string conversion to "null" or "undefined".
+    assert(name != null, 'Attribute name cannot be null');
+    return _hasAttribute(name);
+  }
+
+  @pragma('dart2js:tryInline')
+  bool hasAttributeNS(String namespaceURI, String name) {
+    // Protect [name] against string conversion to "null" or "undefined".
+    // [namespaceURI] does not need protecting, both `null` and `undefined` map to `null`.
+    assert(name != null, 'Attribute name cannot be null');
+    return _hasAttributeNS(namespaceURI, name);
+  }
+
+  @pragma('dart2js:tryInline')
+  void removeAttribute(String name) {
+    // Protect [name] against string conversion to "null" or "undefined".
+    assert(name != null, 'Attribute name cannot be null');
+    _removeAttribute(name);
+  }
+
+  @pragma('dart2js:tryInline')
+  void removeAttributeNS(String namespaceURI, String name) {
+    // Protect [name] against string conversion to "null" or "undefined".
+    assert(name != null, 'Attribute name cannot be null');
+    _removeAttributeNS(namespaceURI, name);
+  }
+
+  @pragma('dart2js:tryInline')
+  void setAttribute(String name, String value) {
+    // Protect [name] against string conversion to "null" or "undefined".
+    assert(name != null, 'Attribute name cannot be null');
+    // TODO(sra): assert(value != null, 'Attribute value cannot be null.');
+    _setAttribute(name, value);
+  }
+
+  @pragma('dart2js:tryInline')
+  void setAttributeNS(String namespaceURI, String name, String value) {
+    // Protect [name] against string conversion to "null" or "undefined".
+    assert(name != null, 'Attribute name cannot be null');
+    // TODO(sra): assert(value != null, 'Attribute value cannot be null.');
+    _setAttributeNS(namespaceURI, name, value);
+  }
+
+  /**
+   * List of the direct children of this element.
+   *
+   * This collection can be used to add and remove elements from the document.
+   *
+   *     var item = new DivElement();
+   *     item.text = 'Something';
+   *     document.body.children.add(item) // Item is now displayed on the page.
+   *     for (var element in document.body.children) {
+   *       element.style.background = 'red'; // Turns every child of body red.
+   *     }
+   */
+  List<Element> get children => new _ChildrenElementList._wrap(this);
+
+  set children(List<Element> value) {
+    // Copy list first since we don't want liveness during iteration.
+    var copy = value.toList();
+    var children = this.children;
+    children.clear();
+    children.addAll(copy);
+  }
+
+  /**
+   * Finds all descendent elements of this element that match the specified
+   * group of selectors.
+   *
+   * [selectors] should be a string using CSS selector syntax.
+   *
+   *     var items = element.querySelectorAll('.itemClassName');
+   *
+   * For details about CSS selector syntax, see the
+   * [CSS selector specification](http://www.w3.org/TR/css3-selectors/).
+   */
+  ElementList<T> querySelectorAll<T extends Element>(String selectors) =>
+      new _FrozenElementList<T>._wrap(_querySelectorAll(selectors));
+
+  @JSName('setApplyScroll')
+  void _setApplyScroll(ScrollStateCallback scrollStateCallback,
+      String nativeScrollBehavior) native;
+
+  Future<ScrollState> setApplyScroll(String nativeScrollBehavior) {
+    var completer = new Completer<ScrollState>();
+    _setApplyScroll((value) {
+      completer.complete(value);
+    }, nativeScrollBehavior);
+    return completer.future;
+  }
+
+  @JSName('setDistributeScroll')
+  void _setDistributeScroll(ScrollStateCallback scrollStateCallback,
+      String nativeScrollBehavior) native;
+
+  Future<ScrollState> setDistributeScroll(String nativeScrollBehavior) {
+    var completer = new Completer<ScrollState>();
+    _setDistributeScroll((value) {
+      completer.complete(value);
+    }, nativeScrollBehavior);
+    return completer.future;
+  }
+
+  /**
+   * The set of CSS classes applied to this element.
+   *
+   * This set makes it easy to add, remove or toggle the classes applied to
+   * this element.
+   *
+   *     element.classes.add('selected');
+   *     element.classes.toggle('isOnline');
+   *     element.classes.remove('selected');
+   */
+  CssClassSet get classes => new _ElementCssClassSet(this);
+
+  set classes(Iterable<String> value) {
+    // TODO(sra): Do this without reading the classes in clear() and addAll(),
+    // or writing the classes in clear().
+    CssClassSet classSet = classes;
+    classSet.clear();
+    classSet.addAll(value);
+  }
+
+  /**
+   * Allows access to all custom data attributes (data-*) set on this element.
+   *
+   * The keys for the map must follow these rules:
+   *
+   * * The name must not begin with 'xml'.
+   * * The name cannot contain a semi-colon (';').
+   * * The name cannot contain any capital letters.
+   *
+   * Any keys from markup will be converted to camel-cased keys in the map.
+   *
+   * For example, HTML specified as:
+   *
+   *     <div data-my-random-value='value'></div>
+   *
+   * Would be accessed in Dart as:
+   *
+   *     var value = element.dataset['myRandomValue'];
+   *
+   * See also:
+   *
+   * * [Custom data
+   *   attributes](http://dev.w3.org/html5/spec-preview/global-attributes.html#custom-data-attribute)
+   */
+  Map<String, String> get dataset => new _DataAttributeMap(attributes);
+
+  set dataset(Map<String, String> value) {
+    final data = this.dataset;
+    data.clear();
+    for (String key in value.keys) {
+      data[key] = value[key];
+    }
+  }
+
+  /**
+   * Gets a map for manipulating the attributes of a particular namespace.
+   *
+   * This is primarily useful for SVG attributes such as xref:link.
+   */
+  Map<String, String> getNamespacedAttributes(String namespace) {
+    return new _NamespacedAttributeMap(this, namespace);
+  }
+
+  /**
+   * The set of all CSS values applied to this element, including inherited
+   * and default values.
+   *
+   * The computedStyle contains values that are inherited from other
+   * sources, such as parent elements or stylesheets. This differs from the
+   * [style] property, which contains only the values specified directly on this
+   * element.
+   *
+   * PseudoElement can be values such as `::after`, `::before`, `::marker`,
+   * `::line-marker`.
+   *
+   * See also:
+   *
+   * * [Cascade and Inheritance](https://developer.mozilla.org/en-US/docs/Learn/CSS/Introduction_to_CSS/Cascade_and_inheritance)
+   *   from MDN.
+   * * [Pseudo-elements](https://developer.mozilla.org/en-US/docs/Web/CSS/Pseudo-elements)
+   *   from MDN.
+   */
+  CssStyleDeclaration getComputedStyle([String pseudoElement]) {
+    if (pseudoElement == null) {
+      pseudoElement = '';
+    }
+    // TODO(jacobr): last param should be null, see b/5045788
+    return window._getComputedStyle(this, pseudoElement);
+  }
+
+  /**
+   * Gets the position of this element relative to the client area of the page.
+   */
+  Rectangle get client =>
+      new Rectangle(clientLeft, clientTop, clientWidth, clientHeight);
+
+  /**
+   * Gets the offset of this element relative to its offsetParent.
+   */
+  Rectangle get offset =>
+      new Rectangle(offsetLeft, offsetTop, offsetWidth, offsetHeight);
+
+  /**
+   * Adds the specified text after the last child of this element.
+   */
+  void appendText(String text) {
+    this.append(new Text(text));
+  }
+
+  /**
+   * Parses the specified text as HTML and adds the resulting node after the
+   * last child of this element.
+   */
+  void appendHtml(String text,
+      {NodeValidator validator, NodeTreeSanitizer treeSanitizer}) {
+    this.insertAdjacentHtml('beforeend', text,
+        validator: validator, treeSanitizer: treeSanitizer);
+  }
+
+  /**
+   * Checks to see if the tag name is supported by the current platform.
+   *
+   * The tag should be a valid HTML tag name.
+   */
+  static bool isTagSupported(String tag) {
+    var e = _ElementFactoryProvider.createElement_tag(tag, null);
+    return e is Element && !(e is UnknownElement);
+  }
+
+  /**
+   * Called by the DOM when this element has been inserted into the live
+   * document.
+   *
+   * More information can be found in the
+   * [Custom Elements](http://w3c.github.io/webcomponents/spec/custom/#dfn-attached-callback)
+   * draft specification.
+   */
+  void attached() {
+    // For the deprecation period, call the old callback.
+    enteredView();
+  }
+
+  /**
+   * Called by the DOM when this element has been removed from the live
+   * document.
+   *
+   * More information can be found in the
+   * [Custom Elements](http://w3c.github.io/webcomponents/spec/custom/#dfn-detached-callback)
+   * draft specification.
+   */
+  void detached() {
+    // For the deprecation period, call the old callback.
+    leftView();
+  }
+
+  /** *Deprecated*: override [attached] instead. */
+  @deprecated
+  void enteredView() {}
+
+  List<Rectangle> getClientRects() {
+    var value = _getClientRects();
+
+    // If no prototype we need one for the world to hookup to the proper Dart class.
+    var jsProto = JS('', '#.prototype', value);
+    if (jsProto == null) {
+      JS('', '#.prototype = Object.create(null)', value);
+    }
+
+    applyExtension('DOMRectList', value);
+
+    return value;
+  }
+
+  /** *Deprecated*: override [detached] instead. */
+  @deprecated
+  void leftView() {}
+
+  /**
+   * Creates a new AnimationEffect object whose target element is the object
+   * on which the method is called, and calls the play() method of the
+   * AnimationTimeline object of the document timeline of the node document
+   * of the element, passing the newly created AnimationEffect as the argument
+   * to the method. Returns an Animation for the effect.
+   *
+   * Examples
+   *
+   *     var animation = elem.animate([{"opacity": 75}, {"opacity": 0}], 200);
+   *
+   *     var animation = elem.animate([
+   *       {"transform": "translate(100px, -100%)"},
+   *       {"transform" : "translate(400px, 500px)"}
+   *     ], 1500);
+   *
+   * The [frames] parameter is an Iterable<Map>, where the
+   * map entries specify CSS animation effects. The
+   * [timing] paramter can be a double, representing the number of milliseconds
+   * for the transition, or a Map with fields corresponding to those
+   * of the [Timing] object.
+  **/
+  @SupportedBrowser(SupportedBrowser.CHROME, '36')
+  Animation animate(Iterable<Map<String, dynamic>> frames, [timing]) {
+    if (frames is! Iterable || !(frames.every((x) => x is Map))) {
+      throw new ArgumentError("The frames parameter should be a List of Maps "
+          "with frame information");
+    }
+    var convertedFrames;
+    if (frames is Iterable) {
+      convertedFrames = frames.map(convertDartToNative_Dictionary).toList();
+    } else {
+      convertedFrames = frames;
+    }
+    var convertedTiming =
+        timing is Map ? convertDartToNative_Dictionary(timing) : timing;
+    return convertedTiming == null
+        ? _animate(convertedFrames)
+        : _animate(convertedFrames, convertedTiming);
+  }
+
+  @JSName('animate')
+  Animation _animate(Object effect, [timing]) native;
+  /**
+   * Called by the DOM whenever an attribute on this has been changed.
+   */
+  void attributeChanged(String name, String oldValue, String newValue) {}
+
+  @Returns('String')
+  // Non-null for Elements.
+  String get localName => JS('String', '#', _localName);
+
+  /**
+   * A URI that identifies the XML namespace of this element.
+   *
+   * `null` if no namespace URI is specified.
+   *
+   * ## Other resources
+   *
+   * * [Node.namespaceURI](http://www.w3.org/TR/DOM-Level-3-Core/core.html#ID-NodeNSname)
+   *   from W3C.
+   */
+  String get namespaceUri => _namespaceUri;
+
+  /**
+   * The string representation of this element.
+   *
+   * This is equivalent to reading the [localName] property.
+   */
+  String toString() => localName;
+
+  /**
+   * Scrolls this element into view.
+   *
+   * Only one of of the alignment options may be specified at a time.
+   *
+   * If no options are specified then this will attempt to scroll the minimum
+   * amount needed to bring the element into view.
+   *
+   * Note that alignCenter is currently only supported on WebKit platforms. If
+   * alignCenter is specified but not supported then this will fall back to
+   * alignTop.
+   *
+   * See also:
+   *
+   * * [scrollIntoView](https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView)
+   *   from MDN.
+   * * [scrollIntoViewIfNeeded](https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoViewIfNeeded)
+   *   from MDN.
+   */
+  void scrollIntoView([ScrollAlignment alignment]) {
+    var hasScrollIntoViewIfNeeded = true;
+    hasScrollIntoViewIfNeeded =
+        JS('bool', '!!(#.scrollIntoViewIfNeeded)', this);
+    if (alignment == ScrollAlignment.TOP) {
+      this._scrollIntoView(true);
+    } else if (alignment == ScrollAlignment.BOTTOM) {
+      this._scrollIntoView(false);
+    } else if (hasScrollIntoViewIfNeeded) {
+      if (alignment == ScrollAlignment.CENTER) {
+        this._scrollIntoViewIfNeeded(true);
+      } else {
+        this._scrollIntoViewIfNeeded();
+      }
+    } else {
+      this._scrollIntoView();
+    }
+  }
+
+  /**
+   * Static factory designed to expose `mousewheel` events to event
+   * handlers that are not necessarily instances of [Element].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<WheelEvent> mouseWheelEvent =
+      const _CustomEventStreamProvider<WheelEvent>(
+          Element._determineMouseWheelEventType);
+
+  static String _determineMouseWheelEventType(EventTarget e) => 'wheel';
+
+  /**
+   * Static factory designed to expose `transitionend` events to event
+   * handlers that are not necessarily instances of [Element].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<TransitionEvent> transitionEndEvent =
+      const _CustomEventStreamProvider<TransitionEvent>(
+          Element._determineTransitionEventType);
+
+  static String _determineTransitionEventType(EventTarget e) {
+    // Unfortunately the normal 'ontransitionend' style checks don't work here.
+    if (Device.isWebKit) {
+      return 'webkitTransitionEnd';
+    } else if (Device.isOpera) {
+      return 'oTransitionEnd';
+    }
+    return 'transitionend';
+  }
+
+  /**
+   * Inserts text into the DOM at the specified location.
+   *
+   * To see the possible values for [where], read the doc for
+   * [insertAdjacentHtml].
+   *
+   * See also:
+   *
+   * * [insertAdjacentHtml]
+   */
+  void insertAdjacentText(String where, String text) {
+    if (JS('bool', '!!#.insertAdjacentText', this)) {
+      _insertAdjacentText(where, text);
+    } else {
+      _insertAdjacentNode(where, new Text(text));
+    }
+  }
+
+  @JSName('insertAdjacentText')
+  void _insertAdjacentText(String where, String text) native;
+
+  /**
+   * Parses text as an HTML fragment and inserts it into the DOM at the
+   * specified location.
+   *
+   * The [where] parameter indicates where to insert the HTML fragment:
+   *
+   * * 'beforeBegin': Immediately before this element.
+   * * 'afterBegin': As the first child of this element.
+   * * 'beforeEnd': As the last child of this element.
+   * * 'afterEnd': Immediately after this element.
+   *
+   *     var html = '<div class="something">content</div>';
+   *     // Inserts as the first child
+   *     document.body.insertAdjacentHtml('afterBegin', html);
+   *     var createdElement = document.body.children[0];
+   *     print(createdElement.classes[0]); // Prints 'something'
+   *
+   * See also:
+   *
+   * * [insertAdjacentText]
+   * * [insertAdjacentElement]
+   */
+  void insertAdjacentHtml(String where, String html,
+      {NodeValidator validator, NodeTreeSanitizer treeSanitizer}) {
+    if (treeSanitizer is _TrustedHtmlTreeSanitizer) {
+      _insertAdjacentHtml(where, html);
+    } else {
+      _insertAdjacentNode(
+          where,
+          createFragment(html,
+              validator: validator, treeSanitizer: treeSanitizer));
+    }
+  }
+
+  @JSName('insertAdjacentHTML')
+  void _insertAdjacentHtml(String where, String text) native;
+
+  /**
+   * Inserts [element] into the DOM at the specified location.
+   *
+   * To see the possible values for [where], read the doc for
+   * [insertAdjacentHtml].
+   *
+   * See also:
+   *
+   * * [insertAdjacentHtml]
+   */
+  Element insertAdjacentElement(String where, Element element) {
+    if (JS('bool', '!!#.insertAdjacentElement', this)) {
+      _insertAdjacentElement(where, element);
+    } else {
+      _insertAdjacentNode(where, element);
+    }
+    return element;
+  }
+
+  @JSName('insertAdjacentElement')
+  void _insertAdjacentElement(String where, Element element) native;
+
+  void _insertAdjacentNode(String where, Node node) {
+    switch (where.toLowerCase()) {
+      case 'beforebegin':
+        this.parentNode.insertBefore(node, this);
+        break;
+      case 'afterbegin':
+        var first = this.nodes.length > 0 ? this.nodes[0] : null;
+        this.insertBefore(node, first);
+        break;
+      case 'beforeend':
+        this.append(node);
+        break;
+      case 'afterend':
+        this.parentNode.insertBefore(node, this.nextNode);
+        break;
+      default:
+        throw new ArgumentError("Invalid position ${where}");
+    }
+  }
+
+  /**
+   * Checks if this element matches the CSS selectors.
+   */
+  bool matches(String selectors) {
+    if (JS('bool', '!!#.matches', this)) {
+      return JS('bool', '#.matches(#)', this, selectors);
+    } else if (JS('bool', '!!#.webkitMatchesSelector', this)) {
+      return JS('bool', '#.webkitMatchesSelector(#)', this, selectors);
+    } else if (JS('bool', '!!#.mozMatchesSelector', this)) {
+      return JS('bool', '#.mozMatchesSelector(#)', this, selectors);
+    } else if (JS('bool', '!!#.msMatchesSelector', this)) {
+      return JS('bool', '#.msMatchesSelector(#)', this, selectors);
+    } else if (JS('bool', '!!#.oMatchesSelector', this)) {
+      return JS('bool', '#.oMatchesSelector(#)', this, selectors);
+    } else {
+      throw new UnsupportedError("Not supported on this platform");
+    }
+  }
+
+  /** Checks if this element or any of its parents match the CSS selectors. */
+  bool matchesWithAncestors(String selectors) {
+    var elem = this;
+    do {
+      if (elem.matches(selectors)) return true;
+      elem = elem.parent;
+    } while (elem != null);
+    return false;
+  }
+
+  /**
+   * Creates a new shadow root for this shadow host.
+   *
+   * ## Other resources
+   *
+   * * [Shadow DOM 101](http://www.html5rocks.com/en/tutorials/webcomponents/shadowdom/)
+   *   from HTML5Rocks.
+   * * [Shadow DOM specification](http://www.w3.org/TR/shadow-dom/) from W3C.
+   */
+  @SupportedBrowser(SupportedBrowser.CHROME, '25')
+  ShadowRoot createShadowRoot() {
+    return JS(
+        'ShadowRoot',
+        '(#.createShadowRoot || #.webkitCreateShadowRoot).call(#)',
+        this,
+        this,
+        this);
+  }
+
+  /**
+   * The shadow root of this shadow host.
+   *
+   * ## Other resources
+   *
+   * * [Shadow DOM 101](http://www.html5rocks.com/en/tutorials/webcomponents/shadowdom/)
+   *   from HTML5Rocks.
+   * * [Shadow DOM specification](http://www.w3.org/TR/shadow-dom/)
+   *   from W3C.
+   */
+  @SupportedBrowser(SupportedBrowser.CHROME, '25')
+  ShadowRoot get shadowRoot =>
+      JS('ShadowRoot|Null', '#.shadowRoot || #.webkitShadowRoot', this, this);
+
+  /**
+   * Access this element's content position.
+   *
+   * This returns a rectangle with the dimensions actually available for content
+   * in this element, in pixels, regardless of this element's box-sizing
+   * property. Unlike [getBoundingClientRect], the dimensions of this rectangle
+   * will return the same numerical height if the element is hidden or not.
+   *
+   * _Important_ _note_: use of this method _will_ perform CSS calculations that
+   * can trigger a browser reflow. Therefore, use of this property _during_ an
+   * animation frame is discouraged. See also:
+   * [Browser Reflow](https://developers.google.com/speed/articles/reflow)
+   */
+  CssRect get contentEdge => new _ContentCssRect(this);
+
+  /**
+   * Access the dimensions and position of this element's content + padding box.
+   *
+   * This returns a rectangle with the dimensions actually available for content
+   * in this element, in pixels, regardless of this element's box-sizing
+   * property. Unlike [getBoundingClientRect], the dimensions of this rectangle
+   * will return the same numerical height if the element is hidden or not. This
+   * can be used to retrieve jQuery's
+   * [innerHeight](http://api.jquery.com/innerHeight/) value for an element.
+   * This is also a rectangle equalling the dimensions of clientHeight and
+   * clientWidth.
+   *
+   * _Important_ _note_: use of this method _will_ perform CSS calculations that
+   * can trigger a browser reflow. Therefore, use of this property _during_ an
+   * animation frame is discouraged. See also:
+   * [Browser Reflow](https://developers.google.com/speed/articles/reflow)
+   */
+  CssRect get paddingEdge => new _PaddingCssRect(this);
+
+  /**
+   * Access the dimensions and position of this element's content + padding +
+   * border box.
+   *
+   * This returns a rectangle with the dimensions actually available for content
+   * in this element, in pixels, regardless of this element's box-sizing
+   * property. Unlike [getBoundingClientRect], the dimensions of this rectangle
+   * will return the same numerical height if the element is hidden or not. This
+   * can be used to retrieve jQuery's
+   * [outerHeight](http://api.jquery.com/outerHeight/) value for an element.
+   *
+   * _Important_ _note_: use of this method _will_ perform CSS calculations that
+   * can trigger a browser reflow. Therefore, use of this property _during_ an
+   * animation frame is discouraged. See also:
+   * [Browser Reflow](https://developers.google.com/speed/articles/reflow)
+   */
+  CssRect get borderEdge => new _BorderCssRect(this);
+
+  /**
+   * Access the dimensions and position of this element's content + padding +
+   * border + margin box.
+   *
+   * This returns a rectangle with the dimensions actually available for content
+   * in this element, in pixels, regardless of this element's box-sizing
+   * property. Unlike [getBoundingClientRect], the dimensions of this rectangle
+   * will return the same numerical height if the element is hidden or not. This
+   * can be used to retrieve jQuery's
+   * [outerHeight](http://api.jquery.com/outerHeight/) value for an element.
+   *
+   * _Important_ _note_: use of this method will perform CSS calculations that
+   * can trigger a browser reflow. Therefore, use of this property _during_ an
+   * animation frame is discouraged. See also:
+   * [Browser Reflow](https://developers.google.com/speed/articles/reflow)
+   */
+  CssRect get marginEdge => new _MarginCssRect(this);
+
+  /**
+   * Provides the coordinates of the element relative to the top of the
+   * document.
+   *
+   * This method is the Dart equivalent to jQuery's
+   * [offset](http://api.jquery.com/offset/) method.
+   */
+  Point get documentOffset => offsetTo(document.documentElement);
+
+  /**
+   * Provides the offset of this element's [borderEdge] relative to the
+   * specified [parent].
+   *
+   * This is the Dart equivalent of jQuery's
+   * [position](http://api.jquery.com/position/) method. Unlike jQuery's
+   * position, however, [parent] can be any parent element of `this`,
+   * rather than only `this`'s immediate [offsetParent]. If the specified
+   * element is _not_ an offset parent or transitive offset parent to this
+   * element, an [ArgumentError] is thrown.
+   */
+  Point offsetTo(Element parent) {
+    return Element._offsetToHelper(this, parent);
+  }
+
+  static Point _offsetToHelper(Element current, Element parent) {
+    // We're hopping from _offsetParent_ to offsetParent (not just parent), so
+    // offsetParent, "tops out" at BODY. But people could conceivably pass in
+    // the document.documentElement and I want it to return an absolute offset,
+    // so we have the special case checking for HTML.
+    bool sameAsParent = identical(current, parent);
+    bool foundAsParent = sameAsParent || parent.tagName == 'HTML';
+    if (current == null || sameAsParent) {
+      if (foundAsParent) return new Point(0, 0);
+      throw new ArgumentError("Specified element is not a transitive offset "
+          "parent of this element.");
+    }
+    Element parentOffset = current.offsetParent;
+    Point p = Element._offsetToHelper(parentOffset, parent);
+    return new Point(p.x + current.offsetLeft, p.y + current.offsetTop);
+  }
+
+  static HtmlDocument _parseDocument;
+  static Range _parseRange;
+  static NodeValidatorBuilder _defaultValidator;
+  static _ValidatingTreeSanitizer _defaultSanitizer;
+
+  /**
+   * Create a DocumentFragment from the HTML fragment and ensure that it follows
+   * the sanitization rules specified by the validator or treeSanitizer.
+   *
+   * If the default validation behavior is too restrictive then a new
+   * NodeValidator should be created, either extending or wrapping a default
+   * validator and overriding the validation APIs.
+   *
+   * The treeSanitizer is used to walk the generated node tree and sanitize it.
+   * A custom treeSanitizer can also be provided to perform special validation
+   * rules but since the API is more complex to implement this is discouraged.
+   *
+   * The returned tree is guaranteed to only contain nodes and attributes which
+   * are allowed by the provided validator.
+   *
+   * See also:
+   *
+   * * [NodeValidator]
+   * * [NodeTreeSanitizer]
+   */
+  DocumentFragment createFragment(String html,
+      {NodeValidator validator, NodeTreeSanitizer treeSanitizer}) {
+    if (treeSanitizer == null) {
+      if (validator == null) {
+        if (_defaultValidator == null) {
+          _defaultValidator = new NodeValidatorBuilder.common();
+        }
+        validator = _defaultValidator;
+      }
+      if (_defaultSanitizer == null) {
+        _defaultSanitizer = new _ValidatingTreeSanitizer(validator);
+      } else {
+        _defaultSanitizer.validator = validator;
+      }
+      treeSanitizer = _defaultSanitizer;
+    } else if (validator != null) {
+      throw new ArgumentError(
+          'validator can only be passed if treeSanitizer is null');
+    }
+
+    if (_parseDocument == null) {
+      _parseDocument = document.implementation.createHtmlDocument('');
+      _parseRange = _parseDocument.createRange();
+
+      // Workaround for Safari bug. Was also previously Chrome bug 229142
+      // - URIs are not resolved in new doc.
+      BaseElement base = _parseDocument.createElement('base');
+      base.href = document.baseUri;
+      _parseDocument.head.append(base);
+    }
+
+    // TODO(terry): Fixes Chromium 50 change no body after createHtmlDocument()
+    if (_parseDocument.body == null) {
+      _parseDocument.body = _parseDocument.createElement("body");
+    }
+
+    var contextElement;
+    if (this is BodyElement) {
+      contextElement = _parseDocument.body;
+    } else {
+      contextElement = _parseDocument.createElement(tagName);
+      _parseDocument.body.append(contextElement);
+    }
+    var fragment;
+    if (Range.supportsCreateContextualFragment &&
+        _canBeUsedToCreateContextualFragment) {
+      _parseRange.selectNodeContents(contextElement);
+      fragment = _parseRange.createContextualFragment(html);
+    } else {
+      contextElement._innerHtml = html;
+
+      fragment = _parseDocument.createDocumentFragment();
+      while (contextElement.firstChild != null) {
+        fragment.append(contextElement.firstChild);
+      }
+    }
+    if (contextElement != _parseDocument.body) {
+      contextElement.remove();
+    }
+
+    treeSanitizer.sanitizeTree(fragment);
+    // Copy the fragment over to the main document (fix for 14184)
+    document.adoptNode(fragment);
+
+    return fragment;
+  }
+
+  /** Test if createContextualFragment is supported for this element type */
+  bool get _canBeUsedToCreateContextualFragment =>
+      !_cannotBeUsedToCreateContextualFragment;
+
+  /** Test if createContextualFragment is NOT supported for this element type */
+  bool get _cannotBeUsedToCreateContextualFragment =>
+      _tagsForWhichCreateContextualFragmentIsNotSupported.contains(tagName);
+
+  /**
+   * A hard-coded list of the tag names for which createContextualFragment
+   * isn't supported.
+   */
+  static const _tagsForWhichCreateContextualFragmentIsNotSupported = const [
+    'HEAD',
+    'AREA',
+    'BASE',
+    'BASEFONT',
+    'BR',
+    'COL',
+    'COLGROUP',
+    'EMBED',
+    'FRAME',
+    'FRAMESET',
+    'HR',
+    'IMAGE',
+    'IMG',
+    'INPUT',
+    'ISINDEX',
+    'LINK',
+    'META',
+    'PARAM',
+    'SOURCE',
+    'STYLE',
+    'TITLE',
+    'WBR'
+  ];
+
+  /**
+   * Parses the HTML fragment and sets it as the contents of this element.
+   *
+   * This uses the default sanitization behavior to sanitize the HTML fragment,
+   * use [setInnerHtml] to override the default behavior.
+   */
+  set innerHtml(String html) {
+    this.setInnerHtml(html);
+  }
+
+  /**
+   * Parses the HTML fragment and sets it as the contents of this element.
+   * This ensures that the generated content follows the sanitization rules
+   * specified by the validator or treeSanitizer.
+   *
+   * If the default validation behavior is too restrictive then a new
+   * NodeValidator should be created, either extending or wrapping a default
+   * validator and overriding the validation APIs.
+   *
+   * The treeSanitizer is used to walk the generated node tree and sanitize it.
+   * A custom treeSanitizer can also be provided to perform special validation
+   * rules but since the API is more complex to implement this is discouraged.
+   *
+   * The resulting tree is guaranteed to only contain nodes and attributes which
+   * are allowed by the provided validator.
+   *
+   * See also:
+   *
+   * * [NodeValidator]
+   * * [NodeTreeSanitizer]
+   */
+  void setInnerHtml(String html,
+      {NodeValidator validator, NodeTreeSanitizer treeSanitizer}) {
+    text = null;
+    if (treeSanitizer is _TrustedHtmlTreeSanitizer) {
+      _innerHtml = html;
+    } else {
+      append(createFragment(html,
+          validator: validator, treeSanitizer: treeSanitizer));
+    }
+  }
+
+  String get innerHtml => _innerHtml;
+
+  @JSName('innerText')
+  String innerText;
+
+  /**
+   * This is an ease-of-use accessor for event streams which should only be
+   * used when an explicit accessor is not available.
+   */
+  ElementEvents get on => new ElementEvents(this);
+
+  /**
+   * Verify if any of the attributes that we use in the sanitizer look unexpected,
+   * possibly indicating DOM clobbering attacks.
+   *
+   * Those attributes are: attributes, lastChild, children, previousNode and tagName.
+   */
+  static bool _hasCorruptedAttributes(Element element) {
+    return JS(
+        'bool',
+        r'''
+       (function(element) {
+         if (!(element.attributes instanceof NamedNodeMap)) {
+	   return true;
+	 }
+	 var childNodes = element.childNodes;
+	 if (element.lastChild &&
+	     element.lastChild !== childNodes[childNodes.length -1]) {
+	   return true;
+	 }
+	 if (element.children) { // On Safari, children can apparently be null.
+  	   if (!((element.children instanceof HTMLCollection) ||
+               (element.children instanceof NodeList))) {
+	     return true;
+	   }
+	 }
+         var length = 0;
+         if (element.children) {
+           length = element.children.length;
+         }
+         for (var i = 0; i < length; i++) {
+           var child = element.children[i];
+           // On IE it seems like we sometimes don't see the clobbered attribute,
+           // perhaps as a result of an over-optimization. Also use another route
+           // to check of attributes, children, or lastChild are clobbered. It may
+           // seem silly to check children as we rely on children to do this iteration,
+           // but it seems possible that the access to children might see the real thing,
+           // allowing us to check for clobbering that may show up in other accesses.
+           if (child["id"] == 'attributes' || child["name"] == 'attributes' ||
+               child["id"] == 'lastChild'  || child["name"] == 'lastChild' ||
+               child["id"] == 'children' || child["name"] == 'children') {
+             return true;
+           }
+         }
+	 return false;
+          })(#)''',
+        element);
+  }
+
+  /// A secondary check for corruption, needed on IE
+  static bool _hasCorruptedAttributesAdditionalCheck(Element element) {
+    return JS('bool', r'!(#.attributes instanceof NamedNodeMap)', element);
+  }
+
+  static String _safeTagName(element) {
+    String result = 'element tag unavailable';
+    try {
+      if (element.tagName is String) {
+        result = element.tagName;
+      }
+    } catch (e) {}
+    return result;
+  }
+
+  final Element offsetParent;
+
+  int get offsetHeight => JS<num>('num', '#.offsetHeight', this).round();
+
+  int get offsetLeft => JS<num>('num', '#.offsetLeft', this).round();
+
+  int get offsetTop => JS<num>('num', '#.offsetTop', this).round();
+
+  int get offsetWidth => JS<num>('num', '#.offsetWidth', this).round();
+
+  int get scrollHeight => JS<num>('num', '#.scrollHeight', this).round();
+  int get scrollLeft => JS<num>('num', '#.scrollLeft', this).round();
+
+  set scrollLeft(int value) {
+    JS("void", "#.scrollLeft = #", this, value.round());
+  }
+
+  int get scrollTop => JS<num>('num', '#.scrollTop', this).round();
+
+  set scrollTop(int value) {
+    JS("void", "#.scrollTop = #", this, value.round());
+  }
+
+  int get scrollWidth => JS<num>('num', '#.scrollWidth', this).round();
+
+  // To suppress missing implicit constructor warnings.
+  factory Element._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  /**
+   * Static factory designed to expose `abort` events to event
+   * handlers that are not necessarily instances of [Element].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<Event> abortEvent =
+      const EventStreamProvider<Event>('abort');
+
+  /**
+   * Static factory designed to expose `beforecopy` events to event
+   * handlers that are not necessarily instances of [Element].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<Event> beforeCopyEvent =
+      const EventStreamProvider<Event>('beforecopy');
+
+  /**
+   * Static factory designed to expose `beforecut` events to event
+   * handlers that are not necessarily instances of [Element].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<Event> beforeCutEvent =
+      const EventStreamProvider<Event>('beforecut');
+
+  /**
+   * Static factory designed to expose `beforepaste` events to event
+   * handlers that are not necessarily instances of [Element].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<Event> beforePasteEvent =
+      const EventStreamProvider<Event>('beforepaste');
+
+  /**
+   * Static factory designed to expose `blur` events to event
+   * handlers that are not necessarily instances of [Element].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<Event> blurEvent =
+      const EventStreamProvider<Event>('blur');
+
+  static const EventStreamProvider<Event> canPlayEvent =
+      const EventStreamProvider<Event>('canplay');
+
+  static const EventStreamProvider<Event> canPlayThroughEvent =
+      const EventStreamProvider<Event>('canplaythrough');
+
+  /**
+   * Static factory designed to expose `change` events to event
+   * handlers that are not necessarily instances of [Element].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<Event> changeEvent =
+      const EventStreamProvider<Event>('change');
+
+  /**
+   * Static factory designed to expose `click` events to event
+   * handlers that are not necessarily instances of [Element].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<MouseEvent> clickEvent =
+      const EventStreamProvider<MouseEvent>('click');
+
+  /**
+   * Static factory designed to expose `contextmenu` events to event
+   * handlers that are not necessarily instances of [Element].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<MouseEvent> contextMenuEvent =
+      const EventStreamProvider<MouseEvent>('contextmenu');
+
+  /**
+   * Static factory designed to expose `copy` events to event
+   * handlers that are not necessarily instances of [Element].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<ClipboardEvent> copyEvent =
+      const EventStreamProvider<ClipboardEvent>('copy');
+
+  /**
+   * Static factory designed to expose `cut` events to event
+   * handlers that are not necessarily instances of [Element].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<ClipboardEvent> cutEvent =
+      const EventStreamProvider<ClipboardEvent>('cut');
+
+  /**
+   * Static factory designed to expose `doubleclick` events to event
+   * handlers that are not necessarily instances of [Element].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  @DomName('Element.dblclickEvent')
+  static const EventStreamProvider<Event> doubleClickEvent =
+      const EventStreamProvider<Event>('dblclick');
+
+  /**
+   * A stream of `drag` events fired when an element is currently being dragged.
+   *
+   * A `drag` event is added to this stream as soon as the drag begins.
+   * A `drag` event is also added to this stream at intervals while the drag
+   * operation is still ongoing.
+   *
+   * ## Other resources
+   *
+   * * [Drag and drop
+   *   sample](https://github.com/dart-lang/dart-samples/tree/master/html5/web/dnd/basics)
+   *   based on [the tutorial](http://www.html5rocks.com/en/tutorials/dnd/basics/)
+   *   from HTML5Rocks.
+   * * [Drag and drop
+   *   specification](https://html.spec.whatwg.org/multipage/interaction.html#dnd)
+   *   from WHATWG.
+   */
+  static const EventStreamProvider<MouseEvent> dragEvent =
+      const EventStreamProvider<MouseEvent>('drag');
+
+  /**
+   * A stream of `dragend` events fired when an element completes a drag
+   * operation.
+   *
+   * ## Other resources
+   *
+   * * [Drag and drop
+   *   sample](https://github.com/dart-lang/dart-samples/tree/master/html5/web/dnd/basics)
+   *   based on [the tutorial](http://www.html5rocks.com/en/tutorials/dnd/basics/)
+   *   from HTML5Rocks.
+   * * [Drag and drop
+   *   specification](https://html.spec.whatwg.org/multipage/interaction.html#dnd)
+   *   from WHATWG.
+   */
+  static const EventStreamProvider<MouseEvent> dragEndEvent =
+      const EventStreamProvider<MouseEvent>('dragend');
+
+  /**
+   * A stream of `dragenter` events fired when a dragged object is first dragged
+   * over an element.
+   *
+   * ## Other resources
+   *
+   * * [Drag and drop
+   *   sample](https://github.com/dart-lang/dart-samples/tree/master/html5/web/dnd/basics)
+   *   based on [the tutorial](http://www.html5rocks.com/en/tutorials/dnd/basics/)
+   *   from HTML5Rocks.
+   * * [Drag and drop
+   *   specification](https://html.spec.whatwg.org/multipage/interaction.html#dnd)
+   *   from WHATWG.
+   */
+  static const EventStreamProvider<MouseEvent> dragEnterEvent =
+      const EventStreamProvider<MouseEvent>('dragenter');
+
+  /**
+   * A stream of `dragleave` events fired when an object being dragged over an
+   * element leaves the element's target area.
+   *
+   * ## Other resources
+   *
+   * * [Drag and drop
+   *   sample](https://github.com/dart-lang/dart-samples/tree/master/html5/web/dnd/basics)
+   *   based on [the tutorial](http://www.html5rocks.com/en/tutorials/dnd/basics/)
+   *   from HTML5Rocks.
+   * * [Drag and drop
+   *   specification](https://html.spec.whatwg.org/multipage/interaction.html#dnd)
+   *   from WHATWG.
+   */
+  static const EventStreamProvider<MouseEvent> dragLeaveEvent =
+      const EventStreamProvider<MouseEvent>('dragleave');
+
+  /**
+   * A stream of `dragover` events fired when a dragged object is currently
+   * being dragged over an element.
+   *
+   * ## Other resources
+   *
+   * * [Drag and drop
+   *   sample](https://github.com/dart-lang/dart-samples/tree/master/html5/web/dnd/basics)
+   *   based on [the tutorial](http://www.html5rocks.com/en/tutorials/dnd/basics/)
+   *   from HTML5Rocks.
+   * * [Drag and drop
+   *   specification](https://html.spec.whatwg.org/multipage/interaction.html#dnd)
+   *   from WHATWG.
+   */
+  static const EventStreamProvider<MouseEvent> dragOverEvent =
+      const EventStreamProvider<MouseEvent>('dragover');
+
+  /**
+   * A stream of `dragstart` events for a dragged element whose drag has begun.
+   *
+   * ## Other resources
+   *
+   * * [Drag and drop
+   *   sample](https://github.com/dart-lang/dart-samples/tree/master/html5/web/dnd/basics)
+   *   based on [the tutorial](http://www.html5rocks.com/en/tutorials/dnd/basics/)
+   *   from HTML5Rocks.
+   * * [Drag and drop
+   *   specification](https://html.spec.whatwg.org/multipage/interaction.html#dnd)
+   *   from WHATWG.
+   */
+  static const EventStreamProvider<MouseEvent> dragStartEvent =
+      const EventStreamProvider<MouseEvent>('dragstart');
+
+  /**
+   * A stream of `drop` events fired when a dragged object is dropped on an
+   * element.
+   *
+   * ## Other resources
+   *
+   * * [Drag and drop
+   *   sample](https://github.com/dart-lang/dart-samples/tree/master/html5/web/dnd/basics)
+   *   based on [the tutorial](http://www.html5rocks.com/en/tutorials/dnd/basics/)
+   *   from HTML5Rocks.
+   * * [Drag and drop
+   *   specification](https://html.spec.whatwg.org/multipage/interaction.html#dnd)
+   *   from WHATWG.
+   */
+  static const EventStreamProvider<MouseEvent> dropEvent =
+      const EventStreamProvider<MouseEvent>('drop');
+
+  static const EventStreamProvider<Event> durationChangeEvent =
+      const EventStreamProvider<Event>('durationchange');
+
+  static const EventStreamProvider<Event> emptiedEvent =
+      const EventStreamProvider<Event>('emptied');
+
+  static const EventStreamProvider<Event> endedEvent =
+      const EventStreamProvider<Event>('ended');
+
+  /**
+   * Static factory designed to expose `error` events to event
+   * handlers that are not necessarily instances of [Element].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<Event> errorEvent =
+      const EventStreamProvider<Event>('error');
+
+  /**
+   * Static factory designed to expose `focus` events to event
+   * handlers that are not necessarily instances of [Element].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<Event> focusEvent =
+      const EventStreamProvider<Event>('focus');
+
+  /**
+   * Static factory designed to expose `input` events to event
+   * handlers that are not necessarily instances of [Element].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<Event> inputEvent =
+      const EventStreamProvider<Event>('input');
+
+  /**
+   * Static factory designed to expose `invalid` events to event
+   * handlers that are not necessarily instances of [Element].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<Event> invalidEvent =
+      const EventStreamProvider<Event>('invalid');
+
+  /**
+   * Static factory designed to expose `keydown` events to event
+   * handlers that are not necessarily instances of [Element].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<KeyboardEvent> keyDownEvent =
+      const EventStreamProvider<KeyboardEvent>('keydown');
+
+  /**
+   * Static factory designed to expose `keypress` events to event
+   * handlers that are not necessarily instances of [Element].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<KeyboardEvent> keyPressEvent =
+      const EventStreamProvider<KeyboardEvent>('keypress');
+
+  /**
+   * Static factory designed to expose `keyup` events to event
+   * handlers that are not necessarily instances of [Element].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<KeyboardEvent> keyUpEvent =
+      const EventStreamProvider<KeyboardEvent>('keyup');
+
+  /**
+   * Static factory designed to expose `load` events to event
+   * handlers that are not necessarily instances of [Element].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<Event> loadEvent =
+      const EventStreamProvider<Event>('load');
+
+  static const EventStreamProvider<Event> loadedDataEvent =
+      const EventStreamProvider<Event>('loadeddata');
+
+  static const EventStreamProvider<Event> loadedMetadataEvent =
+      const EventStreamProvider<Event>('loadedmetadata');
+
+  /**
+   * Static factory designed to expose `mousedown` events to event
+   * handlers that are not necessarily instances of [Element].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<MouseEvent> mouseDownEvent =
+      const EventStreamProvider<MouseEvent>('mousedown');
+
+  /**
+   * Static factory designed to expose `mouseenter` events to event
+   * handlers that are not necessarily instances of [Element].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<MouseEvent> mouseEnterEvent =
+      const EventStreamProvider<MouseEvent>('mouseenter');
+
+  /**
+   * Static factory designed to expose `mouseleave` events to event
+   * handlers that are not necessarily instances of [Element].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<MouseEvent> mouseLeaveEvent =
+      const EventStreamProvider<MouseEvent>('mouseleave');
+
+  /**
+   * Static factory designed to expose `mousemove` events to event
+   * handlers that are not necessarily instances of [Element].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<MouseEvent> mouseMoveEvent =
+      const EventStreamProvider<MouseEvent>('mousemove');
+
+  /**
+   * Static factory designed to expose `mouseout` events to event
+   * handlers that are not necessarily instances of [Element].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<MouseEvent> mouseOutEvent =
+      const EventStreamProvider<MouseEvent>('mouseout');
+
+  /**
+   * Static factory designed to expose `mouseover` events to event
+   * handlers that are not necessarily instances of [Element].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<MouseEvent> mouseOverEvent =
+      const EventStreamProvider<MouseEvent>('mouseover');
+
+  /**
+   * Static factory designed to expose `mouseup` events to event
+   * handlers that are not necessarily instances of [Element].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<MouseEvent> mouseUpEvent =
+      const EventStreamProvider<MouseEvent>('mouseup');
+
+  /**
+   * Static factory designed to expose `paste` events to event
+   * handlers that are not necessarily instances of [Element].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<ClipboardEvent> pasteEvent =
+      const EventStreamProvider<ClipboardEvent>('paste');
+
+  static const EventStreamProvider<Event> pauseEvent =
+      const EventStreamProvider<Event>('pause');
+
+  static const EventStreamProvider<Event> playEvent =
+      const EventStreamProvider<Event>('play');
+
+  static const EventStreamProvider<Event> playingEvent =
+      const EventStreamProvider<Event>('playing');
+
+  static const EventStreamProvider<Event> rateChangeEvent =
+      const EventStreamProvider<Event>('ratechange');
+
+  /**
+   * Static factory designed to expose `reset` events to event
+   * handlers that are not necessarily instances of [Element].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<Event> resetEvent =
+      const EventStreamProvider<Event>('reset');
+
+  static const EventStreamProvider<Event> resizeEvent =
+      const EventStreamProvider<Event>('resize');
+
+  /**
+   * Static factory designed to expose `scroll` events to event
+   * handlers that are not necessarily instances of [Element].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<Event> scrollEvent =
+      const EventStreamProvider<Event>('scroll');
+
+  /**
+   * Static factory designed to expose `search` events to event
+   * handlers that are not necessarily instances of [Element].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<Event> searchEvent =
+      const EventStreamProvider<Event>('search');
+
+  static const EventStreamProvider<Event> seekedEvent =
+      const EventStreamProvider<Event>('seeked');
+
+  static const EventStreamProvider<Event> seekingEvent =
+      const EventStreamProvider<Event>('seeking');
+
+  /**
+   * Static factory designed to expose `select` events to event
+   * handlers that are not necessarily instances of [Element].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<Event> selectEvent =
+      const EventStreamProvider<Event>('select');
+
+  /**
+   * Static factory designed to expose `selectstart` events to event
+   * handlers that are not necessarily instances of [Element].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<Event> selectStartEvent =
+      const EventStreamProvider<Event>('selectstart');
+
+  static const EventStreamProvider<Event> stalledEvent =
+      const EventStreamProvider<Event>('stalled');
+
+  /**
+   * Static factory designed to expose `submit` events to event
+   * handlers that are not necessarily instances of [Element].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<Event> submitEvent =
+      const EventStreamProvider<Event>('submit');
+
+  static const EventStreamProvider<Event> suspendEvent =
+      const EventStreamProvider<Event>('suspend');
+
+  static const EventStreamProvider<Event> timeUpdateEvent =
+      const EventStreamProvider<Event>('timeupdate');
+
+  /**
+   * Static factory designed to expose `touchcancel` events to event
+   * handlers that are not necessarily instances of [Element].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<TouchEvent> touchCancelEvent =
+      const EventStreamProvider<TouchEvent>('touchcancel');
+
+  /**
+   * Static factory designed to expose `touchend` events to event
+   * handlers that are not necessarily instances of [Element].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<TouchEvent> touchEndEvent =
+      const EventStreamProvider<TouchEvent>('touchend');
+
+  /**
+   * Static factory designed to expose `touchenter` events to event
+   * handlers that are not necessarily instances of [Element].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<TouchEvent> touchEnterEvent =
+      const EventStreamProvider<TouchEvent>('touchenter');
+
+  /**
+   * Static factory designed to expose `touchleave` events to event
+   * handlers that are not necessarily instances of [Element].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<TouchEvent> touchLeaveEvent =
+      const EventStreamProvider<TouchEvent>('touchleave');
+
+  /**
+   * Static factory designed to expose `touchmove` events to event
+   * handlers that are not necessarily instances of [Element].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<TouchEvent> touchMoveEvent =
+      const EventStreamProvider<TouchEvent>('touchmove');
+
+  /**
+   * Static factory designed to expose `touchstart` events to event
+   * handlers that are not necessarily instances of [Element].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<TouchEvent> touchStartEvent =
+      const EventStreamProvider<TouchEvent>('touchstart');
+
+  static const EventStreamProvider<Event> volumeChangeEvent =
+      const EventStreamProvider<Event>('volumechange');
+
+  static const EventStreamProvider<Event> waitingEvent =
+      const EventStreamProvider<Event>('waiting');
+
+  /**
+   * Static factory designed to expose `fullscreenchange` events to event
+   * handlers that are not necessarily instances of [Element].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  @SupportedBrowser(SupportedBrowser.CHROME)
+  @SupportedBrowser(SupportedBrowser.SAFARI)
+  static const EventStreamProvider<Event> fullscreenChangeEvent =
+      const EventStreamProvider<Event>('webkitfullscreenchange');
+
+  /**
+   * Static factory designed to expose `fullscreenerror` events to event
+   * handlers that are not necessarily instances of [Element].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  @SupportedBrowser(SupportedBrowser.CHROME)
+  @SupportedBrowser(SupportedBrowser.SAFARI)
+  static const EventStreamProvider<Event> fullscreenErrorEvent =
+      const EventStreamProvider<Event>('webkitfullscreenerror');
+
+  static const EventStreamProvider<WheelEvent> wheelEvent =
+      const EventStreamProvider<WheelEvent>('wheel');
+
+  String contentEditable;
+
+  String dir;
+
+  /**
+   * Indicates whether the element can be dragged and dropped.
+   *
+   * ## Other resources
+   *
+   * * [Drag and drop
+   *   sample](https://github.com/dart-lang/dart-samples/tree/master/html5/web/dnd/basics)
+   *   based on [the tutorial](http://www.html5rocks.com/en/tutorials/dnd/basics/)
+   *   from HTML5Rocks.
+   * * [Drag and drop
+   *   specification](https://html.spec.whatwg.org/multipage/interaction.html#dnd)
+   *   from WHATWG.
+   */
+  bool draggable;
+
+  /**
+   * Indicates whether the element is not relevant to the page's current state.
+   *
+   * ## Other resources
+   *
+   * * [Hidden attribute
+   *   specification](https://html.spec.whatwg.org/multipage/interaction.html#the-hidden-attribute)
+   *   from WHATWG.
+   */
+  bool hidden;
+
+  bool inert;
+
+  String inputMode;
+
+  // Using property as subclass shadows.
+  bool get isContentEditable => JS("bool", "#.isContentEditable", this);
+
+  String lang;
+
+  bool spellcheck;
+
+  final CssStyleDeclaration style;
+
+  int tabIndex;
+
+  String title;
+
+  /**
+   * Specifies whether this element's text content changes when the page is
+   * localized.
+   *
+   * ## Other resources
+   *
+   * * [The translate
+   *   attribute](https://html.spec.whatwg.org/multipage/dom.html#the-translate-attribute)
+   *   from WHATWG.
+   */
+  bool translate;
+
+  void blur() native;
+
+  void click() native;
+
+  void focus() native;
+
+  final AccessibleNode accessibleNode;
+
+  final SlotElement assignedSlot;
+
+  @JSName('attributes')
+  final _NamedNodeMap _attributes;
+
+  String className;
+
+  final int clientHeight;
+
+  final int clientLeft;
+
+  final int clientTop;
+
+  final int clientWidth;
+
+  final String computedName;
+
+  final String computedRole;
+
+  String id;
+
+  @JSName('innerHTML')
+  String _innerHtml;
+
+  @JSName('localName')
+  final String _localName;
+
+  @JSName('namespaceURI')
+  final String _namespaceUri;
+
+  // Using property as subclass shadows.
+  String get outerHtml => JS("String", "#.outerHTML", this);
+
+  @JSName('scrollHeight')
+  final int _scrollHeight;
+
+  @JSName('scrollLeft')
+  num _scrollLeft;
+
+  @JSName('scrollTop')
+  num _scrollTop;
+
+  @JSName('scrollWidth')
+  final int _scrollWidth;
+
+  String slot;
+
+  final StylePropertyMap styleMap;
+
+  final String tagName;
+
+  ShadowRoot attachShadow(Map shadowRootInitDict) {
+    var shadowRootInitDict_1 =
+        convertDartToNative_Dictionary(shadowRootInitDict);
+    return _attachShadow_1(shadowRootInitDict_1);
+  }
+
+  @JSName('attachShadow')
+  ShadowRoot _attachShadow_1(shadowRootInitDict) native;
+
+  Element closest(String selectors) native;
+
+  List<Animation> getAnimations() native;
+
+  @JSName('getAttribute')
+  String _getAttribute(String name) native;
+
+  @JSName('getAttributeNS')
+  String _getAttributeNS(String namespaceURI, String localName) native;
+
+  List<String> getAttributeNames() native;
+
+  /**
+   * Returns the smallest bounding rectangle that encompasses this element's
+   * padding, scrollbar, and border.
+   *
+   * ## Other resources
+   *
+   * * [Element.getBoundingClientRect](https://developer.mozilla.org/en-US/docs/Web/API/Element.getBoundingClientRect)
+   *   from MDN.
+   * * [The getBoundingClientRect()
+   *   method](http://www.w3.org/TR/cssom-view/#the-getclientrects()-and-getboundingclientrect()-methods)
+   *   from W3C.
+   */
+  @Creates('_DomRect')
+  @Returns('_DomRect|Null')
+  Rectangle getBoundingClientRect() native;
+
+  @JSName('getClientRects')
+  /**
+   * Returns a list of bounding rectangles for each box associated with this
+   * element.
+   *
+   * ## Other resources
+   *
+   * * [Element.getClientRects](https://developer.mozilla.org/en-US/docs/Web/API/Element.getClientRects)
+   *   from MDN.
+   * * [The getClientRects()
+   *   method](http://www.w3.org/TR/cssom-view/#the-getclientrects()-and-getboundingclientrect()-methods)
+   *   from W3C.
+   */
+  @Creates('DomRectList')
+  @Returns('DomRectList|Null')
+  List<Rectangle> _getClientRects() native;
+
+  /**
+   * Returns a list of shadow DOM insertion points to which this element is
+   * distributed.
+   *
+   * ## Other resources
+   *
+   * * [Shadow DOM
+   *   specification](https://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/shadow/index.html)
+   *   from W3C.
+   */
+  @Returns('NodeList|Null')
+  @Creates('NodeList')
+  List<Node> getDestinationInsertionPoints() native;
+
+  /**
+   * Returns a list of nodes with the given class name inside this element.
+   *
+   * ## Other resources
+   *
+   * * [getElementsByClassName](https://developer.mozilla.org/en-US/docs/Web/API/document.getElementsByClassName)
+   *   from MDN.
+   * * [DOM specification](http://www.w3.org/TR/domcore/) from W3C.
+   */
+  @Creates('NodeList|HtmlCollection')
+  @Returns('NodeList|HtmlCollection')
+  List<Node> getElementsByClassName(String classNames) native;
+
+  @JSName('getElementsByTagName')
+  @Creates('NodeList|HtmlCollection')
+  @Returns('NodeList|HtmlCollection')
+  List<Node> _getElementsByTagName(String localName) native;
+
+  @JSName('hasAttribute')
+  bool _hasAttribute(String name) native;
+
+  @JSName('hasAttributeNS')
+  bool _hasAttributeNS(String namespaceURI, String localName) native;
+
+  bool hasPointerCapture(int pointerId) native;
+
+  void releasePointerCapture(int pointerId) native;
+
+  @JSName('removeAttribute')
+  void _removeAttribute(String name) native;
+
+  @JSName('removeAttributeNS')
+  void _removeAttributeNS(String namespaceURI, String localName) native;
+
+  void requestPointerLock() native;
+
+  void scroll([options_OR_x, num y]) {
+    if (options_OR_x == null && y == null) {
+      _scroll_1();
+      return;
+    }
+    if ((options_OR_x is Map) && y == null) {
+      var options_1 = convertDartToNative_Dictionary(options_OR_x);
+      _scroll_2(options_1);
+      return;
+    }
+    if (y != null && (options_OR_x is num)) {
+      _scroll_3(options_OR_x, y);
+      return;
+    }
+    throw new ArgumentError("Incorrect number or type of arguments");
+  }
+
+  @JSName('scroll')
+  void _scroll_1() native;
+  @JSName('scroll')
+  void _scroll_2(options) native;
+  @JSName('scroll')
+  void _scroll_3(num x, y) native;
+
+  void scrollBy([options_OR_x, num y]) {
+    if (options_OR_x == null && y == null) {
+      _scrollBy_1();
+      return;
+    }
+    if ((options_OR_x is Map) && y == null) {
+      var options_1 = convertDartToNative_Dictionary(options_OR_x);
+      _scrollBy_2(options_1);
+      return;
+    }
+    if (y != null && (options_OR_x is num)) {
+      _scrollBy_3(options_OR_x, y);
+      return;
+    }
+    throw new ArgumentError("Incorrect number or type of arguments");
+  }
+
+  @JSName('scrollBy')
+  void _scrollBy_1() native;
+  @JSName('scrollBy')
+  void _scrollBy_2(options) native;
+  @JSName('scrollBy')
+  void _scrollBy_3(num x, y) native;
+
+  @JSName('scrollIntoView')
+  void _scrollIntoView([Object arg]) native;
+
+  @JSName('scrollIntoViewIfNeeded')
+  void _scrollIntoViewIfNeeded([bool centerIfNeeded]) native;
+
+  void scrollTo([options_OR_x, num y]) {
+    if (options_OR_x == null && y == null) {
+      _scrollTo_1();
+      return;
+    }
+    if ((options_OR_x is Map) && y == null) {
+      var options_1 = convertDartToNative_Dictionary(options_OR_x);
+      _scrollTo_2(options_1);
+      return;
+    }
+    if (y != null && (options_OR_x is num)) {
+      _scrollTo_3(options_OR_x, y);
+      return;
+    }
+    throw new ArgumentError("Incorrect number or type of arguments");
+  }
+
+  @JSName('scrollTo')
+  void _scrollTo_1() native;
+  @JSName('scrollTo')
+  void _scrollTo_2(options) native;
+  @JSName('scrollTo')
+  void _scrollTo_3(num x, y) native;
+
+  @JSName('setAttribute')
+  void _setAttribute(String name, String value) native;
+
+  @JSName('setAttributeNS')
+  void _setAttributeNS(String namespaceURI, String name, String value) native;
+
+  void setPointerCapture(int pointerId) native;
+
+  @JSName('webkitRequestFullscreen')
+  /**
+   * Displays this element fullscreen.
+   *
+   * ## Other resources
+   *
+   * * [Fullscreen
+   *   API](https://developer.mozilla.org/en-US/docs/Web/API/Fullscreen_API)
+   *   from MDN.
+   * * [Fullscreen specification](http://www.w3.org/TR/fullscreen/) from W3C.
+   */
+  @SupportedBrowser(SupportedBrowser.CHROME)
+  @SupportedBrowser(SupportedBrowser.SAFARI)
+  void requestFullscreen() native;
+
+  // From ChildNode
+
+  void after(Object nodes) native;
+
+  void before(Object nodes) native;
+
+  // From NonDocumentTypeChildNode
+
+  final Element nextElementSibling;
+
+  final Element previousElementSibling;
+
+  // From ParentNode
+
+  @JSName('childElementCount')
+  final int _childElementCount;
+
+  @JSName('children')
+  @Returns('HtmlCollection|Null')
+  @Creates('HtmlCollection')
+  final List<Node> _children;
+
+  @JSName('firstElementChild')
+  final Element _firstElementChild;
+
+  @JSName('lastElementChild')
+  final Element _lastElementChild;
+
+  /**
+   * Finds the first descendant element of this element that matches the
+   * specified group of selectors.
+   *
+   * [selectors] should be a string using CSS selector syntax.
+   *
+   *     // Gets the first descendant with the class 'classname'
+   *     var element = element.querySelector('.className');
+   *     // Gets the element with id 'id'
+   *     var element = element.querySelector('#id');
+   *     // Gets the first descendant [ImageElement]
+   *     var img = element.querySelector('img');
+   *
+   * For details about CSS selector syntax, see the
+   * [CSS selector specification](http://www.w3.org/TR/css3-selectors/).
+   */
+  Element querySelector(String selectors) native;
+
+  @JSName('querySelectorAll')
+  @Creates('NodeList')
+  @Returns('NodeList')
+  List<Node> _querySelectorAll(String selectors) native;
+
+  /// Stream of `abort` events handled by this [Element].
+  ElementStream<Event> get onAbort => abortEvent.forElement(this);
+
+  /// Stream of `beforecopy` events handled by this [Element].
+  ElementStream<Event> get onBeforeCopy => beforeCopyEvent.forElement(this);
+
+  /// Stream of `beforecut` events handled by this [Element].
+  ElementStream<Event> get onBeforeCut => beforeCutEvent.forElement(this);
+
+  /// Stream of `beforepaste` events handled by this [Element].
+  ElementStream<Event> get onBeforePaste => beforePasteEvent.forElement(this);
+
+  /// Stream of `blur` events handled by this [Element].
+  ElementStream<Event> get onBlur => blurEvent.forElement(this);
+
+  ElementStream<Event> get onCanPlay => canPlayEvent.forElement(this);
+
+  ElementStream<Event> get onCanPlayThrough =>
+      canPlayThroughEvent.forElement(this);
+
+  /// Stream of `change` events handled by this [Element].
+  ElementStream<Event> get onChange => changeEvent.forElement(this);
+
+  /// Stream of `click` events handled by this [Element].
+  ElementStream<MouseEvent> get onClick => clickEvent.forElement(this);
+
+  /// Stream of `contextmenu` events handled by this [Element].
+  ElementStream<MouseEvent> get onContextMenu =>
+      contextMenuEvent.forElement(this);
+
+  /// Stream of `copy` events handled by this [Element].
+  ElementStream<ClipboardEvent> get onCopy => copyEvent.forElement(this);
+
+  /// Stream of `cut` events handled by this [Element].
+  ElementStream<ClipboardEvent> get onCut => cutEvent.forElement(this);
+
+  /// Stream of `doubleclick` events handled by this [Element].
+  @DomName('Element.ondblclick')
+  ElementStream<Event> get onDoubleClick => doubleClickEvent.forElement(this);
+
+  /**
+   * A stream of `drag` events fired when this element currently being dragged.
+   *
+   * A `drag` event is added to this stream as soon as the drag begins.
+   * A `drag` event is also added to this stream at intervals while the drag
+   * operation is still ongoing.
+   *
+   * ## Other resources
+   *
+   * * [Drag and drop
+   *   sample](https://github.com/dart-lang/dart-samples/tree/master/html5/web/dnd/basics)
+   *   based on [the tutorial](http://www.html5rocks.com/en/tutorials/dnd/basics/)
+   *   from HTML5Rocks.
+   * * [Drag and drop
+   *   specification](https://html.spec.whatwg.org/multipage/interaction.html#dnd)
+   *   from WHATWG.
+   */
+  ElementStream<MouseEvent> get onDrag => dragEvent.forElement(this);
+
+  /**
+   * A stream of `dragend` events fired when this element completes a drag
+   * operation.
+   *
+   * ## Other resources
+   *
+   * * [Drag and drop
+   *   sample](https://github.com/dart-lang/dart-samples/tree/master/html5/web/dnd/basics)
+   *   based on [the tutorial](http://www.html5rocks.com/en/tutorials/dnd/basics/)
+   *   from HTML5Rocks.
+   * * [Drag and drop
+   *   specification](https://html.spec.whatwg.org/multipage/interaction.html#dnd)
+   *   from WHATWG.
+   */
+  ElementStream<MouseEvent> get onDragEnd => dragEndEvent.forElement(this);
+
+  /**
+   * A stream of `dragenter` events fired when a dragged object is first dragged
+   * over this element.
+   *
+   * ## Other resources
+   *
+   * * [Drag and drop
+   *   sample](https://github.com/dart-lang/dart-samples/tree/master/html5/web/dnd/basics)
+   *   based on [the tutorial](http://www.html5rocks.com/en/tutorials/dnd/basics/)
+   *   from HTML5Rocks.
+   * * [Drag and drop
+   *   specification](https://html.spec.whatwg.org/multipage/interaction.html#dnd)
+   *   from WHATWG.
+   */
+  ElementStream<MouseEvent> get onDragEnter => dragEnterEvent.forElement(this);
+
+  /**
+   * A stream of `dragleave` events fired when an object being dragged over this
+   * element leaves this element's target area.
+   *
+   * ## Other resources
+   *
+   * * [Drag and drop
+   *   sample](https://github.com/dart-lang/dart-samples/tree/master/html5/web/dnd/basics)
+   *   based on [the tutorial](http://www.html5rocks.com/en/tutorials/dnd/basics/)
+   *   from HTML5Rocks.
+   * * [Drag and drop
+   *   specification](https://html.spec.whatwg.org/multipage/interaction.html#dnd)
+   *   from WHATWG.
+   */
+  ElementStream<MouseEvent> get onDragLeave => dragLeaveEvent.forElement(this);
+
+  /**
+   * A stream of `dragover` events fired when a dragged object is currently
+   * being dragged over this element.
+   *
+   * ## Other resources
+   *
+   * * [Drag and drop
+   *   sample](https://github.com/dart-lang/dart-samples/tree/master/html5/web/dnd/basics)
+   *   based on [the tutorial](http://www.html5rocks.com/en/tutorials/dnd/basics/)
+   *   from HTML5Rocks.
+   * * [Drag and drop
+   *   specification](https://html.spec.whatwg.org/multipage/interaction.html#dnd)
+   *   from WHATWG.
+   */
+  ElementStream<MouseEvent> get onDragOver => dragOverEvent.forElement(this);
+
+  /**
+   * A stream of `dragstart` events fired when this element starts being
+   * dragged.
+   *
+   * ## Other resources
+   *
+   * * [Drag and drop
+   *   sample](https://github.com/dart-lang/dart-samples/tree/master/html5/web/dnd/basics)
+   *   based on [the tutorial](http://www.html5rocks.com/en/tutorials/dnd/basics/)
+   *   from HTML5Rocks.
+   * * [Drag and drop
+   *   specification](https://html.spec.whatwg.org/multipage/interaction.html#dnd)
+   *   from WHATWG.
+   */
+  ElementStream<MouseEvent> get onDragStart => dragStartEvent.forElement(this);
+
+  /**
+   * A stream of `drop` events fired when a dragged object is dropped on this
+   * element.
+   *
+   * ## Other resources
+   *
+   * * [Drag and drop
+   *   sample](https://github.com/dart-lang/dart-samples/tree/master/html5/web/dnd/basics)
+   *   based on [the tutorial](http://www.html5rocks.com/en/tutorials/dnd/basics/)
+   *   from HTML5Rocks.
+   * * [Drag and drop
+   *   specification](https://html.spec.whatwg.org/multipage/interaction.html#dnd)
+   *   from WHATWG.
+   */
+  ElementStream<MouseEvent> get onDrop => dropEvent.forElement(this);
+
+  ElementStream<Event> get onDurationChange =>
+      durationChangeEvent.forElement(this);
+
+  ElementStream<Event> get onEmptied => emptiedEvent.forElement(this);
+
+  ElementStream<Event> get onEnded => endedEvent.forElement(this);
+
+  /// Stream of `error` events handled by this [Element].
+  ElementStream<Event> get onError => errorEvent.forElement(this);
+
+  /// Stream of `focus` events handled by this [Element].
+  ElementStream<Event> get onFocus => focusEvent.forElement(this);
+
+  /// Stream of `input` events handled by this [Element].
+  ElementStream<Event> get onInput => inputEvent.forElement(this);
+
+  /// Stream of `invalid` events handled by this [Element].
+  ElementStream<Event> get onInvalid => invalidEvent.forElement(this);
+
+  /// Stream of `keydown` events handled by this [Element].
+  ElementStream<KeyboardEvent> get onKeyDown => keyDownEvent.forElement(this);
+
+  /// Stream of `keypress` events handled by this [Element].
+  ElementStream<KeyboardEvent> get onKeyPress => keyPressEvent.forElement(this);
+
+  /// Stream of `keyup` events handled by this [Element].
+  ElementStream<KeyboardEvent> get onKeyUp => keyUpEvent.forElement(this);
+
+  /// Stream of `load` events handled by this [Element].
+  ElementStream<Event> get onLoad => loadEvent.forElement(this);
+
+  ElementStream<Event> get onLoadedData => loadedDataEvent.forElement(this);
+
+  ElementStream<Event> get onLoadedMetadata =>
+      loadedMetadataEvent.forElement(this);
+
+  /// Stream of `mousedown` events handled by this [Element].
+  ElementStream<MouseEvent> get onMouseDown => mouseDownEvent.forElement(this);
+
+  /// Stream of `mouseenter` events handled by this [Element].
+  ElementStream<MouseEvent> get onMouseEnter =>
+      mouseEnterEvent.forElement(this);
+
+  /// Stream of `mouseleave` events handled by this [Element].
+  ElementStream<MouseEvent> get onMouseLeave =>
+      mouseLeaveEvent.forElement(this);
+
+  /// Stream of `mousemove` events handled by this [Element].
+  ElementStream<MouseEvent> get onMouseMove => mouseMoveEvent.forElement(this);
+
+  /// Stream of `mouseout` events handled by this [Element].
+  ElementStream<MouseEvent> get onMouseOut => mouseOutEvent.forElement(this);
+
+  /// Stream of `mouseover` events handled by this [Element].
+  ElementStream<MouseEvent> get onMouseOver => mouseOverEvent.forElement(this);
+
+  /// Stream of `mouseup` events handled by this [Element].
+  ElementStream<MouseEvent> get onMouseUp => mouseUpEvent.forElement(this);
+
+  /// Stream of `mousewheel` events handled by this [Element].
+  ElementStream<WheelEvent> get onMouseWheel =>
+      mouseWheelEvent.forElement(this);
+
+  /// Stream of `paste` events handled by this [Element].
+  ElementStream<ClipboardEvent> get onPaste => pasteEvent.forElement(this);
+
+  ElementStream<Event> get onPause => pauseEvent.forElement(this);
+
+  ElementStream<Event> get onPlay => playEvent.forElement(this);
+
+  ElementStream<Event> get onPlaying => playingEvent.forElement(this);
+
+  ElementStream<Event> get onRateChange => rateChangeEvent.forElement(this);
+
+  /// Stream of `reset` events handled by this [Element].
+  ElementStream<Event> get onReset => resetEvent.forElement(this);
+
+  ElementStream<Event> get onResize => resizeEvent.forElement(this);
+
+  /// Stream of `scroll` events handled by this [Element].
+  ElementStream<Event> get onScroll => scrollEvent.forElement(this);
+
+  /// Stream of `search` events handled by this [Element].
+  ElementStream<Event> get onSearch => searchEvent.forElement(this);
+
+  ElementStream<Event> get onSeeked => seekedEvent.forElement(this);
+
+  ElementStream<Event> get onSeeking => seekingEvent.forElement(this);
+
+  /// Stream of `select` events handled by this [Element].
+  ElementStream<Event> get onSelect => selectEvent.forElement(this);
+
+  /// Stream of `selectstart` events handled by this [Element].
+  ElementStream<Event> get onSelectStart => selectStartEvent.forElement(this);
+
+  ElementStream<Event> get onStalled => stalledEvent.forElement(this);
+
+  /// Stream of `submit` events handled by this [Element].
+  ElementStream<Event> get onSubmit => submitEvent.forElement(this);
+
+  ElementStream<Event> get onSuspend => suspendEvent.forElement(this);
+
+  ElementStream<Event> get onTimeUpdate => timeUpdateEvent.forElement(this);
+
+  /// Stream of `touchcancel` events handled by this [Element].
+  ElementStream<TouchEvent> get onTouchCancel =>
+      touchCancelEvent.forElement(this);
+
+  /// Stream of `touchend` events handled by this [Element].
+  ElementStream<TouchEvent> get onTouchEnd => touchEndEvent.forElement(this);
+
+  /// Stream of `touchenter` events handled by this [Element].
+  ElementStream<TouchEvent> get onTouchEnter =>
+      touchEnterEvent.forElement(this);
+
+  /// Stream of `touchleave` events handled by this [Element].
+  ElementStream<TouchEvent> get onTouchLeave =>
+      touchLeaveEvent.forElement(this);
+
+  /// Stream of `touchmove` events handled by this [Element].
+  ElementStream<TouchEvent> get onTouchMove => touchMoveEvent.forElement(this);
+
+  /// Stream of `touchstart` events handled by this [Element].
+  ElementStream<TouchEvent> get onTouchStart =>
+      touchStartEvent.forElement(this);
+
+  /// Stream of `transitionend` events handled by this [Element].
+  @SupportedBrowser(SupportedBrowser.CHROME)
+  @SupportedBrowser(SupportedBrowser.FIREFOX)
+  @SupportedBrowser(SupportedBrowser.IE, '10')
+  @SupportedBrowser(SupportedBrowser.SAFARI)
+  ElementStream<TransitionEvent> get onTransitionEnd =>
+      transitionEndEvent.forElement(this);
+
+  ElementStream<Event> get onVolumeChange => volumeChangeEvent.forElement(this);
+
+  ElementStream<Event> get onWaiting => waitingEvent.forElement(this);
+
+  /// Stream of `fullscreenchange` events handled by this [Element].
+  ElementStream<Event> get onFullscreenChange =>
+      fullscreenChangeEvent.forElement(this);
+
+  /// Stream of `fullscreenerror` events handled by this [Element].
+  ElementStream<Event> get onFullscreenError =>
+      fullscreenErrorEvent.forElement(this);
+
+  ElementStream<WheelEvent> get onWheel => wheelEvent.forElement(this);
+}
+
+class _ElementFactoryProvider {
+  // Optimization to improve performance until the dart2js compiler inlines this
+  // method.
+  static dynamic createElement_tag(String tag, String typeExtension) {
+    // Firefox may return a JS function for some types (Embed, Object).
+    if (typeExtension != null) {
+      return JS('Element|=Object', 'document.createElement(#, #)', tag,
+          typeExtension);
+    }
+    // Should be able to eliminate this and just call the two-arg version above
+    // with null typeExtension, but Chrome treats the tag as case-sensitive if
+    // typeExtension is null.
+    // https://code.google.com/p/chromium/issues/detail?id=282467
+    return JS('Element|=Object', 'document.createElement(#)', tag);
+  }
+}
+
+/**
+ * Options for Element.scrollIntoView.
+ */
+class ScrollAlignment {
+  final _value;
+  const ScrollAlignment._internal(this._value);
+  toString() => 'ScrollAlignment.$_value';
+
+  /// Attempt to align the element to the top of the scrollable area.
+  static const TOP = const ScrollAlignment._internal('TOP');
+
+  /// Attempt to center the element in the scrollable area.
+  static const CENTER = const ScrollAlignment._internal('CENTER');
+
+  /// Attempt to align the element to the bottom of the scrollable area.
+  static const BOTTOM = const ScrollAlignment._internal('BOTTOM');
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.IE)
+@SupportedBrowser(SupportedBrowser.SAFARI)
+@Unstable()
+@Native("HTMLEmbedElement")
+class EmbedElement extends HtmlElement {
+  // To suppress missing implicit constructor warnings.
+  factory EmbedElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory EmbedElement() => document.createElement("embed");
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  EmbedElement.created() : super.created();
+
+  /// Checks if this type is supported on the current platform.
+  static bool get supported => Element.isTagSupported('embed');
+
+  String height;
+
+  String name;
+
+  String src;
+
+  String type;
+
+  String width;
+
+  Node __getter__(String name) native;
+
+  void __setter__(String name, Node value) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+typedef void _EntriesCallback(List entries);
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("Entry")
+class Entry extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory Entry._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final FileSystem filesystem;
+
+  final String fullPath;
+
+  final bool isDirectory;
+
+  final bool isFile;
+
+  final String name;
+
+  @JSName('copyTo')
+  void _copyTo(DirectoryEntry parent,
+      [String name,
+      _EntryCallback successCallback,
+      _ErrorCallback errorCallback]) native;
+
+  @JSName('copyTo')
+  Future<Entry> copyTo(DirectoryEntry parent, {String name}) {
+    var completer = new Completer<Entry>();
+    _copyTo(parent, name, (value) {
+      completer.complete(value);
+    }, (error) {
+      completer.completeError(error);
+    });
+    return completer.future;
+  }
+
+  @JSName('getMetadata')
+  void _getMetadata(MetadataCallback successCallback,
+      [_ErrorCallback errorCallback]) native;
+
+  @JSName('getMetadata')
+  Future<Metadata> getMetadata() {
+    var completer = new Completer<Metadata>();
+    _getMetadata((value) {
+      applyExtension('Metadata', value);
+      completer.complete(value);
+    }, (error) {
+      completer.completeError(error);
+    });
+    return completer.future;
+  }
+
+  @JSName('getParent')
+  void _getParent(
+      [_EntryCallback successCallback, _ErrorCallback errorCallback]) native;
+
+  @JSName('getParent')
+  Future<Entry> getParent() {
+    var completer = new Completer<Entry>();
+    _getParent((value) {
+      applyExtension('Entry', value);
+      completer.complete(value);
+    }, (error) {
+      completer.completeError(error);
+    });
+    return completer.future;
+  }
+
+  @JSName('moveTo')
+  void _moveTo(DirectoryEntry parent,
+      [String name,
+      _EntryCallback successCallback,
+      _ErrorCallback errorCallback]) native;
+
+  @JSName('moveTo')
+  Future<Entry> moveTo(DirectoryEntry parent, {String name}) {
+    var completer = new Completer<Entry>();
+    _moveTo(parent, name, (value) {
+      completer.complete(value);
+    }, (error) {
+      completer.completeError(error);
+    });
+    return completer.future;
+  }
+
+  @JSName('remove')
+  void _remove(VoidCallback successCallback, [_ErrorCallback errorCallback])
+      native;
+
+  @JSName('remove')
+  Future remove() {
+    var completer = new Completer();
+    _remove(() {
+      completer.complete();
+    }, (error) {
+      completer.completeError(error);
+    });
+    return completer.future;
+  }
+
+  @JSName('toURL')
+  String toUrl() native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+typedef void _EntryCallback(Entry entry);
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+typedef void _ErrorCallback(DomException error);
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("ErrorEvent")
+class ErrorEvent extends Event {
+  // To suppress missing implicit constructor warnings.
+  factory ErrorEvent._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory ErrorEvent(String type, [Map eventInitDict]) {
+    if (eventInitDict != null) {
+      var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+      return ErrorEvent._create_1(type, eventInitDict_1);
+    }
+    return ErrorEvent._create_2(type);
+  }
+  static ErrorEvent _create_1(type, eventInitDict) =>
+      JS('ErrorEvent', 'new ErrorEvent(#,#)', type, eventInitDict);
+  static ErrorEvent _create_2(type) =>
+      JS('ErrorEvent', 'new ErrorEvent(#)', type);
+
+  final int colno;
+
+  @Creates('Null')
+  final Object error;
+
+  final String filename;
+
+  final int lineno;
+
+  final String message;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+@Native("Event,InputEvent")
+class Event extends Interceptor {
+  // In JS, canBubble and cancelable are technically required parameters to
+  // init*Event. In practice, though, if they aren't provided they simply
+  // default to false (since that's Boolean(undefined)).
+  //
+  // Contrary to JS, we default canBubble and cancelable to true, since that's
+  // what people want most of the time anyway.
+  factory Event(String type, {bool canBubble: true, bool cancelable: true}) {
+    return new Event.eventType('Event', type,
+        canBubble: canBubble, cancelable: cancelable);
+  }
+
+  /**
+   * Creates a new Event object of the specified type.
+   *
+   * This is analogous to document.createEvent.
+   * Normally events should be created via their constructors, if available.
+   *
+   *     var e = new Event.type('MouseEvent', 'mousedown', true, true);
+   */
+  factory Event.eventType(String type, String name,
+      {bool canBubble: true, bool cancelable: true}) {
+    final Event e = document._createEvent(type);
+    e._initEvent(name, canBubble, cancelable);
+    return e;
+  }
+
+  /** The CSS selector involved with event delegation. */
+  String _selector;
+
+  /**
+   * A pointer to the element whose CSS selector matched within which an event
+   * was fired. If this Event was not associated with any Event delegation,
+   * accessing this value will throw an [UnsupportedError].
+   */
+  Element get matchingTarget {
+    if (_selector == null) {
+      throw new UnsupportedError('Cannot call matchingTarget if this Event did'
+          ' not arise as a result of event delegation.');
+    }
+    Element currentTarget = this.currentTarget;
+    Element target = this.target;
+    var matchedTarget;
+    do {
+      if (target.matches(_selector)) return target;
+      target = target.parent;
+    } while (target != null && target != currentTarget.parent);
+    throw new StateError('No selector matched for populating matchedTarget.');
+  }
+
+  List<EventTarget> get path =>
+      JS('bool', '!!#.composedPath', this) ? composedPath() : [];
+
+  factory Event._(String type, [Map eventInitDict]) {
+    if (eventInitDict != null) {
+      var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+      return Event._create_1(type, eventInitDict_1);
+    }
+    return Event._create_2(type);
+  }
+  static Event _create_1(type, eventInitDict) =>
+      JS('Event', 'new Event(#,#)', type, eventInitDict);
+  static Event _create_2(type) => JS('Event', 'new Event(#)', type);
+
+  /**
+   * This event is being handled by the event target.
+   *
+   * ## Other resources
+   *
+   * * [Target phase](http://www.w3.org/TR/DOM-Level-3-Events/#target-phase)
+   *   from W3C.
+   */
+  static const int AT_TARGET = 2;
+
+  /**
+   * This event is bubbling up through the target's ancestors.
+   *
+   * ## Other resources
+   *
+   * * [Bubble phase](http://www.w3.org/TR/DOM-Level-3-Events/#bubble-phase)
+   *   from W3C.
+   */
+  static const int BUBBLING_PHASE = 3;
+
+  /**
+   * This event is propagating through the target's ancestors, starting from the
+   * document.
+   *
+   * ## Other resources
+   *
+   * * [Bubble phase](http://www.w3.org/TR/DOM-Level-3-Events/#bubble-phase)
+   *   from W3C.
+   */
+  static const int CAPTURING_PHASE = 1;
+
+  final bool bubbles;
+
+  final bool cancelable;
+
+  final bool composed;
+
+  EventTarget get currentTarget =>
+      _convertNativeToDart_EventTarget(this._get_currentTarget);
+  @JSName('currentTarget')
+  @Creates('Null')
+  @Returns('EventTarget|=Object|Null')
+  final dynamic _get_currentTarget;
+
+  final bool defaultPrevented;
+
+  final int eventPhase;
+
+  final bool isTrusted;
+
+  EventTarget get target => _convertNativeToDart_EventTarget(this._get_target);
+  @JSName('target')
+  @Creates('Node')
+  @Returns('EventTarget|=Object')
+  final dynamic _get_target;
+
+  final num timeStamp;
+
+  final String type;
+
+  List<EventTarget> composedPath() native;
+
+  @JSName('initEvent')
+  void _initEvent(String type, [bool bubbles, bool cancelable]) native;
+
+  void preventDefault() native;
+
+  void stopImmediatePropagation() native;
+
+  void stopPropagation() native;
+}
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("EventSource")
+class EventSource extends EventTarget {
+  factory EventSource(String url, {withCredentials: false}) {
+    var parsedOptions = {
+      'withCredentials': withCredentials,
+    };
+    return EventSource._factoryEventSource(url, parsedOptions);
+  }
+  // To suppress missing implicit constructor warnings.
+  factory EventSource._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  /**
+   * Static factory designed to expose `error` events to event
+   * handlers that are not necessarily instances of [EventSource].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<Event> errorEvent =
+      const EventStreamProvider<Event>('error');
+
+  /**
+   * Static factory designed to expose `message` events to event
+   * handlers that are not necessarily instances of [EventSource].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<MessageEvent> messageEvent =
+      const EventStreamProvider<MessageEvent>('message');
+
+  /**
+   * Static factory designed to expose `open` events to event
+   * handlers that are not necessarily instances of [EventSource].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<Event> openEvent =
+      const EventStreamProvider<Event>('open');
+
+  static EventSource _factoryEventSource(String url,
+      [Map eventSourceInitDict]) {
+    if (eventSourceInitDict != null) {
+      var eventSourceInitDict_1 =
+          convertDartToNative_Dictionary(eventSourceInitDict);
+      return EventSource._create_1(url, eventSourceInitDict_1);
+    }
+    return EventSource._create_2(url);
+  }
+
+  static EventSource _create_1(url, eventSourceInitDict) =>
+      JS('EventSource', 'new EventSource(#,#)', url, eventSourceInitDict);
+  static EventSource _create_2(url) =>
+      JS('EventSource', 'new EventSource(#)', url);
+
+  static const int CLOSED = 2;
+
+  static const int CONNECTING = 0;
+
+  static const int OPEN = 1;
+
+  final int readyState;
+
+  final String url;
+
+  final bool withCredentials;
+
+  void close() native;
+
+  /// Stream of `error` events handled by this [EventSource].
+  Stream<Event> get onError => errorEvent.forTarget(this);
+
+  /// Stream of `message` events handled by this [EventSource].
+  Stream<MessageEvent> get onMessage => messageEvent.forTarget(this);
+
+  /// Stream of `open` events handled by this [EventSource].
+  Stream<Event> get onOpen => openEvent.forTarget(this);
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/**
+ * Base class that supports listening for and dispatching browser events.
+ *
+ * Normally events are accessed via the Stream getter:
+ *
+ *     element.onMouseOver.listen((e) => print('Mouse over!'));
+ *
+ * To access bubbling events which are declared on one element, but may bubble
+ * up to another element type (common for MediaElement events):
+ *
+ *     MediaElement.pauseEvent.forTarget(document.body).listen(...);
+ *
+ * To useCapture on events:
+ *
+ *     Element.keyDownEvent.forTarget(element, useCapture: true).listen(...);
+ *
+ * Custom events can be declared as:
+ *
+ *     class DataGenerator {
+ *       static EventStreamProvider<Event> dataEvent =
+ *           new EventStreamProvider('data');
+ *     }
+ *
+ * Then listeners should access the event with:
+ *
+ *     DataGenerator.dataEvent.forTarget(element).listen(...);
+ *
+ * Custom events can also be accessed as:
+ *
+ *     element.on['some_event'].listen(...);
+ *
+ * This approach is generally discouraged as it loses the event typing and
+ * some DOM events may have multiple platform-dependent event names under the
+ * covers. By using the standard Stream getters you will get the platform
+ * specific event name automatically.
+ */
+class Events {
+  /* Raw event target. */
+  final EventTarget _ptr;
+
+  Events(this._ptr);
+
+  Stream<Event> operator [](String type) {
+    return new _EventStream(_ptr, type, false);
+  }
+}
+
+class ElementEvents extends Events {
+  static final webkitEvents = {
+    'animationend': 'webkitAnimationEnd',
+    'animationiteration': 'webkitAnimationIteration',
+    'animationstart': 'webkitAnimationStart',
+    'fullscreenchange': 'webkitfullscreenchange',
+    'fullscreenerror': 'webkitfullscreenerror',
+    'keyadded': 'webkitkeyadded',
+    'keyerror': 'webkitkeyerror',
+    'keymessage': 'webkitkeymessage',
+    'needkey': 'webkitneedkey',
+    'pointerlockchange': 'webkitpointerlockchange',
+    'pointerlockerror': 'webkitpointerlockerror',
+    'resourcetimingbufferfull': 'webkitresourcetimingbufferfull',
+    'transitionend': 'webkitTransitionEnd',
+    'speechchange': 'webkitSpeechChange'
+  };
+
+  ElementEvents(Element ptr) : super(ptr);
+
+  Stream<Event> operator [](String type) {
+    if (webkitEvents.keys.contains(type.toLowerCase())) {
+      if (Device.isWebKit) {
+        return new _ElementEventStreamImpl(
+            _ptr, webkitEvents[type.toLowerCase()], false);
+      }
+    }
+    return new _ElementEventStreamImpl(_ptr, type, false);
+  }
+}
+
+/**
+ * Base class for all browser objects that support events.
+ *
+ * Use the [on] property to add, and remove events
+ * for compile-time type checks and a more concise API.
+ */
+@Native("EventTarget")
+class EventTarget extends Interceptor {
+  // Custom element created callback.
+  EventTarget._created();
+
+  /**
+   * This is an ease-of-use accessor for event streams which should only be
+   * used when an explicit accessor is not available.
+   */
+  Events get on => new Events(this);
+
+  void addEventListener(String type, EventListener listener,
+      [bool useCapture]) {
+    // TODO(leafp): This check is avoid a bug in our dispatch code when
+    // listener is null.  The browser treats this call as a no-op in this
+    // case, so it's fine to short-circuit it, but we should not have to.
+    if (listener != null) {
+      _addEventListener(type, listener, useCapture);
+    }
+  }
+
+  void removeEventListener(String type, EventListener listener,
+      [bool useCapture]) {
+    // TODO(leafp): This check is avoid a bug in our dispatch code when
+    // listener is null.  The browser treats this call as a no-op in this
+    // case, so it's fine to short-circuit it, but we should not have to.
+    if (listener != null) {
+      _removeEventListener(type, listener, useCapture);
+    }
+  }
+
+  // To suppress missing implicit constructor warnings.
+  factory EventTarget._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  @JSName('addEventListener')
+  void _addEventListener(String type, EventListener listener, [bool options])
+      native;
+
+  bool dispatchEvent(Event event) native;
+
+  @JSName('removeEventListener')
+  void _removeEventListener(String type, EventListener listener, [bool options])
+      native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("ExtendableEvent")
+class ExtendableEvent extends Event {
+  // To suppress missing implicit constructor warnings.
+  factory ExtendableEvent._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory ExtendableEvent(String type, [Map eventInitDict]) {
+    if (eventInitDict != null) {
+      var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+      return ExtendableEvent._create_1(type, eventInitDict_1);
+    }
+    return ExtendableEvent._create_2(type);
+  }
+  static ExtendableEvent _create_1(type, eventInitDict) =>
+      JS('ExtendableEvent', 'new ExtendableEvent(#,#)', type, eventInitDict);
+  static ExtendableEvent _create_2(type) =>
+      JS('ExtendableEvent', 'new ExtendableEvent(#)', type);
+
+  void waitUntil(Future f) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("ExtendableMessageEvent")
+class ExtendableMessageEvent extends ExtendableEvent {
+  // To suppress missing implicit constructor warnings.
+  factory ExtendableMessageEvent._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  @annotation_Creates_SerializedScriptValue
+  @annotation_Returns_SerializedScriptValue
+  final Object data;
+
+  final String lastEventId;
+
+  final String origin;
+
+  final List<MessagePort> ports;
+
+  @Creates('Client|ServiceWorker|MessagePort')
+  @Returns('Client|ServiceWorker|MessagePort|Null')
+  final Object source;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("External")
+class External extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory External._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  void AddSearchProvider() native;
+
+  void IsSearchProviderInstalled() native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("FaceDetector")
+class FaceDetector extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory FaceDetector._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory FaceDetector([Map faceDetectorOptions]) {
+    if (faceDetectorOptions != null) {
+      var faceDetectorOptions_1 =
+          convertDartToNative_Dictionary(faceDetectorOptions);
+      return FaceDetector._create_1(faceDetectorOptions_1);
+    }
+    return FaceDetector._create_2();
+  }
+  static FaceDetector _create_1(faceDetectorOptions) =>
+      JS('FaceDetector', 'new FaceDetector(#)', faceDetectorOptions);
+  static FaceDetector _create_2() => JS('FaceDetector', 'new FaceDetector()');
+
+  Future<List<DetectedFace>> detect(/*ImageBitmapSource*/ image) =>
+      promiseToFuture<List<DetectedFace>>(JS("", "#.detect(#)", this, image));
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("FederatedCredential")
+class FederatedCredential extends Credential implements CredentialUserData {
+  // To suppress missing implicit constructor warnings.
+  factory FederatedCredential._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory FederatedCredential(Map data) {
+    var data_1 = convertDartToNative_Dictionary(data);
+    return FederatedCredential._create_1(data_1);
+  }
+  static FederatedCredential _create_1(data) =>
+      JS('FederatedCredential', 'new FederatedCredential(#)', data);
+
+  final String protocol;
+
+  final String provider;
+
+  // From CredentialUserData
+
+  @JSName('iconURL')
+  final String iconUrl;
+
+  final String name;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("FetchEvent")
+class FetchEvent extends ExtendableEvent {
+  // To suppress missing implicit constructor warnings.
+  factory FetchEvent._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory FetchEvent(String type, Map eventInitDict) {
+    var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+    return FetchEvent._create_1(type, eventInitDict_1);
+  }
+  static FetchEvent _create_1(type, eventInitDict) =>
+      JS('FetchEvent', 'new FetchEvent(#,#)', type, eventInitDict);
+
+  final String clientId;
+
+  final bool isReload;
+
+  Future get preloadResponse =>
+      promiseToFuture(JS("", "#.preloadResponse", this));
+
+  final _Request request;
+
+  void respondWith(Future r) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("HTMLFieldSetElement")
+class FieldSetElement extends HtmlElement {
+  // To suppress missing implicit constructor warnings.
+  factory FieldSetElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory FieldSetElement() => JS(
+      'returns:FieldSetElement;creates:FieldSetElement;new:true',
+      '#.createElement(#)',
+      document,
+      "fieldset");
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  FieldSetElement.created() : super.created();
+
+  bool disabled;
+
+  @Returns('HtmlCollection|Null')
+  @Creates('HtmlCollection')
+  final List<Node> elements;
+
+  final FormElement form;
+
+  String name;
+
+  final String type;
+
+  final String validationMessage;
+
+  final ValidityState validity;
+
+  final bool willValidate;
+
+  bool checkValidity() native;
+
+  bool reportValidity() native;
+
+  void setCustomValidity(String error) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("File")
+class File extends Blob {
+  // To suppress missing implicit constructor warnings.
+  factory File._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory File(List<Object> fileBits, String fileName, [Map options]) {
+    if (options != null) {
+      var options_1 = convertDartToNative_Dictionary(options);
+      return File._create_1(fileBits, fileName, options_1);
+    }
+    return File._create_2(fileBits, fileName);
+  }
+  static File _create_1(fileBits, fileName, options) =>
+      JS('File', 'new File(#,#,#)', fileBits, fileName, options);
+  static File _create_2(fileBits, fileName) =>
+      JS('File', 'new File(#,#)', fileBits, fileName);
+
+  final int lastModified;
+
+  DateTime get lastModifiedDate =>
+      convertNativeToDart_DateTime(this._get_lastModifiedDate);
+  @JSName('lastModifiedDate')
+  @Creates('Null')
+  final dynamic _get_lastModifiedDate;
+
+  final String name;
+
+  @JSName('webkitRelativePath')
+  @SupportedBrowser(SupportedBrowser.CHROME)
+  @SupportedBrowser(SupportedBrowser.SAFARI)
+  final String relativePath;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+typedef void _FileCallback(File file);
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("FileEntry")
+class FileEntry extends Entry {
+  // To suppress missing implicit constructor warnings.
+  factory FileEntry._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  @JSName('createWriter')
+  void _createWriter(_FileWriterCallback successCallback,
+      [_ErrorCallback errorCallback]) native;
+
+  @JSName('createWriter')
+  Future<FileWriter> createWriter() {
+    var completer = new Completer<FileWriter>();
+    _createWriter((value) {
+      applyExtension('FileWriter', value);
+      completer.complete(value);
+    }, (error) {
+      completer.completeError(error);
+    });
+    return completer.future;
+  }
+
+  @JSName('file')
+  void _file(_FileCallback successCallback, [_ErrorCallback errorCallback])
+      native;
+
+  @JSName('file')
+  Future<File> file() {
+    var completer = new Completer<File>();
+    _file((value) {
+      applyExtension('File', value);
+      completer.complete(value);
+    }, (error) {
+      completer.completeError(error);
+    });
+    return completer.future;
+  }
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("FileList")
+class FileList extends Interceptor
+    with ListMixin<File>, ImmutableListMixin<File>
+    implements List<File>, JavaScriptIndexingBehavior<File> {
+  // To suppress missing implicit constructor warnings.
+  factory FileList._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  int get length => JS("int", "#.length", this);
+
+  File operator [](int index) {
+    if (JS("bool", "# >>> 0 !== # || # >= #", index, index, index, length))
+      throw new RangeError.index(index, this);
+    return JS("File", "#[#]", this, index);
+  }
+
+  void operator []=(int index, File value) {
+    throw new UnsupportedError("Cannot assign element of immutable List.");
+  }
+  // -- start List<File> mixins.
+  // File is the element type.
+
+  set length(int value) {
+    throw new UnsupportedError("Cannot resize immutable List.");
+  }
+
+  File get first {
+    if (this.length > 0) {
+      return JS('File', '#[0]', this);
+    }
+    throw new StateError("No elements");
+  }
+
+  File get last {
+    int len = this.length;
+    if (len > 0) {
+      return JS('File', '#[#]', this, len - 1);
+    }
+    throw new StateError("No elements");
+  }
+
+  File get single {
+    int len = this.length;
+    if (len == 1) {
+      return JS('File', '#[0]', this);
+    }
+    if (len == 0) throw new StateError("No elements");
+    throw new StateError("More than one element");
+  }
+
+  File elementAt(int index) => this[index];
+  // -- end List<File> mixins.
+
+  File item(int index) native;
+}
+// Copyright (c) 2014, 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.
+
+@Native("FileReader")
+class FileReader extends EventTarget {
+  Object get result {
+    var res = JS('Null|String|NativeByteBuffer', '#.result', this);
+    if (res is ByteBuffer) {
+      return new Uint8List.view(res);
+    }
+    return res;
+  }
+
+  // To suppress missing implicit constructor warnings.
+  factory FileReader._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  /**
+   * Static factory designed to expose `abort` events to event
+   * handlers that are not necessarily instances of [FileReader].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<ProgressEvent> abortEvent =
+      const EventStreamProvider<ProgressEvent>('abort');
+
+  /**
+   * Static factory designed to expose `error` events to event
+   * handlers that are not necessarily instances of [FileReader].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<ProgressEvent> errorEvent =
+      const EventStreamProvider<ProgressEvent>('error');
+
+  /**
+   * Static factory designed to expose `load` events to event
+   * handlers that are not necessarily instances of [FileReader].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<ProgressEvent> loadEvent =
+      const EventStreamProvider<ProgressEvent>('load');
+
+  /**
+   * Static factory designed to expose `loadend` events to event
+   * handlers that are not necessarily instances of [FileReader].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<ProgressEvent> loadEndEvent =
+      const EventStreamProvider<ProgressEvent>('loadend');
+
+  /**
+   * Static factory designed to expose `loadstart` events to event
+   * handlers that are not necessarily instances of [FileReader].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<ProgressEvent> loadStartEvent =
+      const EventStreamProvider<ProgressEvent>('loadstart');
+
+  /**
+   * Static factory designed to expose `progress` events to event
+   * handlers that are not necessarily instances of [FileReader].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<ProgressEvent> progressEvent =
+      const EventStreamProvider<ProgressEvent>('progress');
+
+  factory FileReader() {
+    return FileReader._create_1();
+  }
+  static FileReader _create_1() => JS('FileReader', 'new FileReader()');
+
+  static const int DONE = 2;
+
+  static const int EMPTY = 0;
+
+  static const int LOADING = 1;
+
+  final DomException error;
+
+  final int readyState;
+
+  void abort() native;
+
+  void readAsArrayBuffer(Blob blob) native;
+
+  @JSName('readAsDataURL')
+  void readAsDataUrl(Blob blob) native;
+
+  void readAsText(Blob blob, [String label]) native;
+
+  /// Stream of `abort` events handled by this [FileReader].
+  Stream<ProgressEvent> get onAbort => abortEvent.forTarget(this);
+
+  /// Stream of `error` events handled by this [FileReader].
+  Stream<ProgressEvent> get onError => errorEvent.forTarget(this);
+
+  /// Stream of `load` events handled by this [FileReader].
+  Stream<ProgressEvent> get onLoad => loadEvent.forTarget(this);
+
+  /// Stream of `loadend` events handled by this [FileReader].
+  Stream<ProgressEvent> get onLoadEnd => loadEndEvent.forTarget(this);
+
+  /// Stream of `loadstart` events handled by this [FileReader].
+  Stream<ProgressEvent> get onLoadStart => loadStartEvent.forTarget(this);
+
+  /// Stream of `progress` events handled by this [FileReader].
+  Stream<ProgressEvent> get onProgress => progressEvent.forTarget(this);
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@Native("DOMFileSystem")
+class FileSystem extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory FileSystem._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  /// Checks if this type is supported on the current platform.
+  static bool get supported => JS('bool', '!!(window.webkitRequestFileSystem)');
+
+  final String name;
+
+  final DirectoryEntry root;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+typedef void _FileSystemCallback(FileSystem fileSystem);
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("FileWriter")
+class FileWriter extends EventTarget {
+  // To suppress missing implicit constructor warnings.
+  factory FileWriter._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  /**
+   * Static factory designed to expose `abort` events to event
+   * handlers that are not necessarily instances of [FileWriter].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<ProgressEvent> abortEvent =
+      const EventStreamProvider<ProgressEvent>('abort');
+
+  /**
+   * Static factory designed to expose `error` events to event
+   * handlers that are not necessarily instances of [FileWriter].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<Event> errorEvent =
+      const EventStreamProvider<Event>('error');
+
+  /**
+   * Static factory designed to expose `progress` events to event
+   * handlers that are not necessarily instances of [FileWriter].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<ProgressEvent> progressEvent =
+      const EventStreamProvider<ProgressEvent>('progress');
+
+  /**
+   * Static factory designed to expose `write` events to event
+   * handlers that are not necessarily instances of [FileWriter].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<ProgressEvent> writeEvent =
+      const EventStreamProvider<ProgressEvent>('write');
+
+  /**
+   * Static factory designed to expose `writeend` events to event
+   * handlers that are not necessarily instances of [FileWriter].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<ProgressEvent> writeEndEvent =
+      const EventStreamProvider<ProgressEvent>('writeend');
+
+  /**
+   * Static factory designed to expose `writestart` events to event
+   * handlers that are not necessarily instances of [FileWriter].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<ProgressEvent> writeStartEvent =
+      const EventStreamProvider<ProgressEvent>('writestart');
+
+  static const int DONE = 2;
+
+  static const int INIT = 0;
+
+  static const int WRITING = 1;
+
+  final DomException error;
+
+  final int length;
+
+  final int position;
+
+  final int readyState;
+
+  void abort() native;
+
+  void seek(int position) native;
+
+  void truncate(int size) native;
+
+  void write(Blob data) native;
+
+  /// Stream of `abort` events handled by this [FileWriter].
+  Stream<ProgressEvent> get onAbort => abortEvent.forTarget(this);
+
+  /// Stream of `error` events handled by this [FileWriter].
+  Stream<Event> get onError => errorEvent.forTarget(this);
+
+  /// Stream of `progress` events handled by this [FileWriter].
+  Stream<ProgressEvent> get onProgress => progressEvent.forTarget(this);
+
+  /// Stream of `write` events handled by this [FileWriter].
+  Stream<ProgressEvent> get onWrite => writeEvent.forTarget(this);
+
+  /// Stream of `writeend` events handled by this [FileWriter].
+  Stream<ProgressEvent> get onWriteEnd => writeEndEvent.forTarget(this);
+
+  /// Stream of `writestart` events handled by this [FileWriter].
+  Stream<ProgressEvent> get onWriteStart => writeStartEvent.forTarget(this);
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+typedef void _FileWriterCallback(FileWriter fileWriter);
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("FocusEvent")
+class FocusEvent extends UIEvent {
+  // To suppress missing implicit constructor warnings.
+  factory FocusEvent._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory FocusEvent(String type, [Map eventInitDict]) {
+    if (eventInitDict != null) {
+      var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+      return FocusEvent._create_1(type, eventInitDict_1);
+    }
+    return FocusEvent._create_2(type);
+  }
+  static FocusEvent _create_1(type, eventInitDict) =>
+      JS('FocusEvent', 'new FocusEvent(#,#)', type, eventInitDict);
+  static FocusEvent _create_2(type) =>
+      JS('FocusEvent', 'new FocusEvent(#)', type);
+
+  EventTarget get relatedTarget =>
+      _convertNativeToDart_EventTarget(this._get_relatedTarget);
+  @JSName('relatedTarget')
+  @Creates('Null')
+  final dynamic _get_relatedTarget;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("FontFace")
+class FontFace extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory FontFace._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory FontFace(String family, Object source, [Map descriptors]) {
+    if (descriptors != null) {
+      var descriptors_1 = convertDartToNative_Dictionary(descriptors);
+      return FontFace._create_1(family, source, descriptors_1);
+    }
+    return FontFace._create_2(family, source);
+  }
+  static FontFace _create_1(family, source, descriptors) =>
+      JS('FontFace', 'new FontFace(#,#,#)', family, source, descriptors);
+  static FontFace _create_2(family, source) =>
+      JS('FontFace', 'new FontFace(#,#)', family, source);
+
+  String display;
+
+  String family;
+
+  String featureSettings;
+
+  Future<FontFace> get loaded =>
+      promiseToFuture<FontFace>(JS("", "#.loaded", this));
+
+  final String status;
+
+  String stretch;
+
+  String style;
+
+  String unicodeRange;
+
+  String variant;
+
+  String weight;
+
+  Future<FontFace> load() =>
+      promiseToFuture<FontFace>(JS("", "#.load()", this));
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("FontFaceSet")
+class FontFaceSet extends EventTarget {
+  // To suppress missing implicit constructor warnings.
+  factory FontFaceSet._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  static const EventStreamProvider<FontFaceSetLoadEvent> loadingEvent =
+      const EventStreamProvider<FontFaceSetLoadEvent>('loading');
+
+  static const EventStreamProvider<FontFaceSetLoadEvent> loadingDoneEvent =
+      const EventStreamProvider<FontFaceSetLoadEvent>('loadingdone');
+
+  static const EventStreamProvider<FontFaceSetLoadEvent> loadingErrorEvent =
+      const EventStreamProvider<FontFaceSetLoadEvent>('loadingerror');
+
+  final String status;
+
+  FontFaceSet add(FontFace arg) native;
+
+  bool check(String font, [String text]) native;
+
+  void clear() native;
+
+  bool delete(FontFace arg) native;
+
+  void forEach(FontFaceSetForEachCallback callback, [Object thisArg]) native;
+
+  bool has(FontFace arg) native;
+
+  Stream<FontFaceSetLoadEvent> get onLoading => loadingEvent.forTarget(this);
+
+  Stream<FontFaceSetLoadEvent> get onLoadingDone =>
+      loadingDoneEvent.forTarget(this);
+
+  Stream<FontFaceSetLoadEvent> get onLoadingError =>
+      loadingErrorEvent.forTarget(this);
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("FontFaceSetLoadEvent")
+class FontFaceSetLoadEvent extends Event {
+  // To suppress missing implicit constructor warnings.
+  factory FontFaceSetLoadEvent._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory FontFaceSetLoadEvent(String type, [Map eventInitDict]) {
+    if (eventInitDict != null) {
+      var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+      return FontFaceSetLoadEvent._create_1(type, eventInitDict_1);
+    }
+    return FontFaceSetLoadEvent._create_2(type);
+  }
+  static FontFaceSetLoadEvent _create_1(type, eventInitDict) => JS(
+      'FontFaceSetLoadEvent',
+      'new FontFaceSetLoadEvent(#,#)',
+      type,
+      eventInitDict);
+  static FontFaceSetLoadEvent _create_2(type) =>
+      JS('FontFaceSetLoadEvent', 'new FontFaceSetLoadEvent(#)', type);
+
+  final List<FontFace> fontfaces;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("FontFaceSource")
+class FontFaceSource extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory FontFaceSource._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final FontFaceSet fonts;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("ForeignFetchEvent")
+class ForeignFetchEvent extends ExtendableEvent {
+  // To suppress missing implicit constructor warnings.
+  factory ForeignFetchEvent._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory ForeignFetchEvent(String type, Map eventInitDict) {
+    var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+    return ForeignFetchEvent._create_1(type, eventInitDict_1);
+  }
+  static ForeignFetchEvent _create_1(type, eventInitDict) => JS(
+      'ForeignFetchEvent', 'new ForeignFetchEvent(#,#)', type, eventInitDict);
+
+  final String origin;
+
+  final _Request request;
+
+  void respondWith(Future r) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.FIREFOX)
+@SupportedBrowser(SupportedBrowser.IE, '10')
+@SupportedBrowser(SupportedBrowser.SAFARI)
+@Native("FormData")
+class FormData extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory FormData._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory FormData([FormElement form]) {
+    if (form != null) {
+      return FormData._create_1(form);
+    }
+    return FormData._create_2();
+  }
+  static FormData _create_1(form) => JS('FormData', 'new FormData(#)', form);
+  static FormData _create_2() => JS('FormData', 'new FormData()');
+
+  /// Checks if this type is supported on the current platform.
+  static bool get supported => JS('bool', '!!(window.FormData)');
+
+  void append(String name, String value) native;
+
+  @JSName('append')
+  void appendBlob(String name, Blob value, [String filename]) native;
+
+  void delete(String name) native;
+
+  Object get(String name) native;
+
+  List<Object> getAll(String name) native;
+
+  bool has(String name) native;
+
+  void set(String name, value, [String filename]) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("HTMLFormElement")
+class FormElement extends HtmlElement {
+  // To suppress missing implicit constructor warnings.
+  factory FormElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory FormElement() => JS(
+      'returns:FormElement;creates:FormElement;new:true',
+      '#.createElement(#)',
+      document,
+      "form");
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  FormElement.created() : super.created();
+
+  String acceptCharset;
+
+  String action;
+
+  String autocomplete;
+
+  String encoding;
+
+  String enctype;
+
+  final int length;
+
+  String method;
+
+  String name;
+
+  bool noValidate;
+
+  String target;
+
+  Object __getter__(String name) native;
+
+  bool checkValidity() native;
+
+  Element item(int index) native;
+
+  bool reportValidity() native;
+
+  void requestAutocomplete(Map details) {
+    var details_1 = convertDartToNative_Dictionary(details);
+    _requestAutocomplete_1(details_1);
+    return;
+  }
+
+  @JSName('requestAutocomplete')
+  void _requestAutocomplete_1(details) native;
+
+  void reset() native;
+
+  void submit() native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+typedef void FrameRequestCallback(num highResTime);
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+typedef void FunctionStringCallback(String data);
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("Gamepad")
+class Gamepad extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory Gamepad._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final List<num> axes;
+
+  @Creates('JSExtendableArray|GamepadButton')
+  @Returns('JSExtendableArray')
+  final List<GamepadButton> buttons;
+
+  final bool connected;
+
+  final int displayId;
+
+  final String hand;
+
+  final String id;
+
+  final int index;
+
+  final String mapping;
+
+  final GamepadPose pose;
+
+  final int timestamp;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("GamepadButton")
+class GamepadButton extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory GamepadButton._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final bool pressed;
+
+  final bool touched;
+
+  final num value;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("GamepadEvent")
+class GamepadEvent extends Event {
+  // To suppress missing implicit constructor warnings.
+  factory GamepadEvent._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory GamepadEvent(String type, [Map eventInitDict]) {
+    if (eventInitDict != null) {
+      var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+      return GamepadEvent._create_1(type, eventInitDict_1);
+    }
+    return GamepadEvent._create_2(type);
+  }
+  static GamepadEvent _create_1(type, eventInitDict) =>
+      JS('GamepadEvent', 'new GamepadEvent(#,#)', type, eventInitDict);
+  static GamepadEvent _create_2(type) =>
+      JS('GamepadEvent', 'new GamepadEvent(#)', type);
+
+  final Gamepad gamepad;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("GamepadPose")
+class GamepadPose extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory GamepadPose._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final Float32List angularAcceleration;
+
+  final Float32List angularVelocity;
+
+  final bool hasOrientation;
+
+  final bool hasPosition;
+
+  final Float32List linearAcceleration;
+
+  final Float32List linearVelocity;
+
+  final Float32List orientation;
+
+  final Float32List position;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("Geolocation")
+class Geolocation extends Interceptor {
+  Future<Geoposition> getCurrentPosition(
+      {bool enableHighAccuracy, Duration timeout, Duration maximumAge}) {
+    var options = {};
+    if (enableHighAccuracy != null) {
+      options['enableHighAccuracy'] = enableHighAccuracy;
+    }
+    if (timeout != null) {
+      options['timeout'] = timeout.inMilliseconds;
+    }
+    if (maximumAge != null) {
+      options['maximumAge'] = maximumAge.inMilliseconds;
+    }
+    var completer = new Completer<Geoposition>();
+    try {
+      _getCurrentPosition((position) {
+        completer.complete(_ensurePosition(position));
+      }, (error) {
+        completer.completeError(error);
+      }, options);
+    } catch (e, stacktrace) {
+      completer.completeError(e, stacktrace);
+    }
+    return completer.future;
+  }
+
+  Stream<Geoposition> watchPosition(
+      {bool enableHighAccuracy, Duration timeout, Duration maximumAge}) {
+    var options = {};
+    if (enableHighAccuracy != null) {
+      options['enableHighAccuracy'] = enableHighAccuracy;
+    }
+    if (timeout != null) {
+      options['timeout'] = timeout.inMilliseconds;
+    }
+    if (maximumAge != null) {
+      options['maximumAge'] = maximumAge.inMilliseconds;
+    }
+
+    int watchId;
+    // TODO(jacobr): it seems like a bug that we have to specifiy the static
+    // type here for controller.stream to have the right type.
+    // dartbug.com/26278
+    StreamController<Geoposition> controller;
+    controller = new StreamController<Geoposition>(
+        sync: true,
+        onListen: () {
+          assert(watchId == null);
+          watchId = _watchPosition((position) {
+            controller.add(_ensurePosition(position));
+          }, (error) {
+            controller.addError(error);
+          }, options);
+        },
+        onCancel: () {
+          assert(watchId != null);
+          _clearWatch(watchId);
+        });
+
+    return controller.stream;
+  }
+
+  Geoposition _ensurePosition(domPosition) {
+    try {
+      // Firefox may throw on this.
+      if (domPosition is Geoposition) {
+        return domPosition;
+      }
+    } catch (e) {}
+    return new _GeopositionWrapper(domPosition);
+  }
+
+  // To suppress missing implicit constructor warnings.
+  factory Geolocation._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  @JSName('clearWatch')
+  void _clearWatch(int watchID) native;
+
+  void _getCurrentPosition(_PositionCallback successCallback,
+      [_PositionErrorCallback errorCallback, Map options]) {
+    if (options != null) {
+      var successCallback_1 = convertDartClosureToJS(successCallback, 1);
+      var options_2 = convertDartToNative_Dictionary(options);
+      _getCurrentPosition_1(successCallback_1, errorCallback, options_2);
+      return;
+    }
+    if (errorCallback != null) {
+      var successCallback_1 = convertDartClosureToJS(successCallback, 1);
+      _getCurrentPosition_2(successCallback_1, errorCallback);
+      return;
+    }
+    var successCallback_1 = convertDartClosureToJS(successCallback, 1);
+    _getCurrentPosition_3(successCallback_1);
+    return;
+  }
+
+  @JSName('getCurrentPosition')
+  void _getCurrentPosition_1(
+      successCallback, _PositionErrorCallback errorCallback, options) native;
+  @JSName('getCurrentPosition')
+  void _getCurrentPosition_2(
+      successCallback, _PositionErrorCallback errorCallback) native;
+  @JSName('getCurrentPosition')
+  void _getCurrentPosition_3(successCallback) native;
+
+  int _watchPosition(_PositionCallback successCallback,
+      [_PositionErrorCallback errorCallback, Map options]) {
+    if (options != null) {
+      var successCallback_1 = convertDartClosureToJS(successCallback, 1);
+      var options_2 = convertDartToNative_Dictionary(options);
+      return _watchPosition_1(successCallback_1, errorCallback, options_2);
+    }
+    if (errorCallback != null) {
+      var successCallback_1 = convertDartClosureToJS(successCallback, 1);
+      return _watchPosition_2(successCallback_1, errorCallback);
+    }
+    var successCallback_1 = convertDartClosureToJS(successCallback, 1);
+    return _watchPosition_3(successCallback_1);
+  }
+
+  @JSName('watchPosition')
+  int _watchPosition_1(
+      successCallback, _PositionErrorCallback errorCallback, options) native;
+  @JSName('watchPosition')
+  int _watchPosition_2(successCallback, _PositionErrorCallback errorCallback)
+      native;
+  @JSName('watchPosition')
+  int _watchPosition_3(successCallback) native;
+}
+
+/**
+ * Wrapper for Firefox- it returns an object which we cannot map correctly.
+ * Basically Firefox was returning a [xpconnect wrapped nsIDOMGeoPosition] but
+ * which has further oddities.
+ */
+class _GeopositionWrapper implements Geoposition {
+  var _ptr;
+  _GeopositionWrapper(this._ptr);
+
+  Coordinates get coords => JS('Coordinates', '#.coords', _ptr);
+  int get timestamp => JS('int', '#.timestamp', _ptr);
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("Position")
+class Geoposition extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory Geoposition._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final Coordinates coords;
+
+  final int timestamp;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// We implement EventTarget and have stubs for its methods because it's tricky to
+// convince the scripts to make our instance methods abstract, and the bodies that
+// get generated require `this` to be an EventTarget.
+abstract class GlobalEventHandlers implements EventTarget {
+  void addEventListener(String type, dynamic listener(Event event),
+      [bool useCapture]);
+  bool dispatchEvent(Event event);
+  void removeEventListener(String type, dynamic listener(Event event),
+      [bool useCapture]);
+  Events get on;
+
+  // To suppress missing implicit constructor warnings.
+  factory GlobalEventHandlers._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  static const EventStreamProvider<Event> abortEvent =
+      const EventStreamProvider<Event>('abort');
+
+  static const EventStreamProvider<Event> blurEvent =
+      const EventStreamProvider<Event>('blur');
+
+  static const EventStreamProvider<Event> canPlayEvent =
+      const EventStreamProvider<Event>('canplay');
+
+  static const EventStreamProvider<Event> canPlayThroughEvent =
+      const EventStreamProvider<Event>('canplaythrough');
+
+  static const EventStreamProvider<Event> changeEvent =
+      const EventStreamProvider<Event>('change');
+
+  static const EventStreamProvider<MouseEvent> clickEvent =
+      const EventStreamProvider<MouseEvent>('click');
+
+  static const EventStreamProvider<MouseEvent> contextMenuEvent =
+      const EventStreamProvider<MouseEvent>('contextmenu');
+
+  @DomName('GlobalEventHandlers.dblclickEvent')
+  static const EventStreamProvider<Event> doubleClickEvent =
+      const EventStreamProvider<Event>('dblclick');
+
+  static const EventStreamProvider<MouseEvent> dragEvent =
+      const EventStreamProvider<MouseEvent>('drag');
+
+  static const EventStreamProvider<MouseEvent> dragEndEvent =
+      const EventStreamProvider<MouseEvent>('dragend');
+
+  static const EventStreamProvider<MouseEvent> dragEnterEvent =
+      const EventStreamProvider<MouseEvent>('dragenter');
+
+  static const EventStreamProvider<MouseEvent> dragLeaveEvent =
+      const EventStreamProvider<MouseEvent>('dragleave');
+
+  static const EventStreamProvider<MouseEvent> dragOverEvent =
+      const EventStreamProvider<MouseEvent>('dragover');
+
+  static const EventStreamProvider<MouseEvent> dragStartEvent =
+      const EventStreamProvider<MouseEvent>('dragstart');
+
+  static const EventStreamProvider<MouseEvent> dropEvent =
+      const EventStreamProvider<MouseEvent>('drop');
+
+  static const EventStreamProvider<Event> durationChangeEvent =
+      const EventStreamProvider<Event>('durationchange');
+
+  static const EventStreamProvider<Event> emptiedEvent =
+      const EventStreamProvider<Event>('emptied');
+
+  static const EventStreamProvider<Event> endedEvent =
+      const EventStreamProvider<Event>('ended');
+
+  static const EventStreamProvider<Event> errorEvent =
+      const EventStreamProvider<Event>('error');
+
+  static const EventStreamProvider<Event> focusEvent =
+      const EventStreamProvider<Event>('focus');
+
+  static const EventStreamProvider<Event> inputEvent =
+      const EventStreamProvider<Event>('input');
+
+  static const EventStreamProvider<Event> invalidEvent =
+      const EventStreamProvider<Event>('invalid');
+
+  static const EventStreamProvider<KeyboardEvent> keyDownEvent =
+      const EventStreamProvider<KeyboardEvent>('keydown');
+
+  static const EventStreamProvider<KeyboardEvent> keyPressEvent =
+      const EventStreamProvider<KeyboardEvent>('keypress');
+
+  static const EventStreamProvider<KeyboardEvent> keyUpEvent =
+      const EventStreamProvider<KeyboardEvent>('keyup');
+
+  static const EventStreamProvider<Event> loadEvent =
+      const EventStreamProvider<Event>('load');
+
+  static const EventStreamProvider<Event> loadedDataEvent =
+      const EventStreamProvider<Event>('loadeddata');
+
+  static const EventStreamProvider<Event> loadedMetadataEvent =
+      const EventStreamProvider<Event>('loadedmetadata');
+
+  static const EventStreamProvider<MouseEvent> mouseDownEvent =
+      const EventStreamProvider<MouseEvent>('mousedown');
+
+  static const EventStreamProvider<MouseEvent> mouseEnterEvent =
+      const EventStreamProvider<MouseEvent>('mouseenter');
+
+  static const EventStreamProvider<MouseEvent> mouseLeaveEvent =
+      const EventStreamProvider<MouseEvent>('mouseleave');
+
+  static const EventStreamProvider<MouseEvent> mouseMoveEvent =
+      const EventStreamProvider<MouseEvent>('mousemove');
+
+  static const EventStreamProvider<MouseEvent> mouseOutEvent =
+      const EventStreamProvider<MouseEvent>('mouseout');
+
+  static const EventStreamProvider<MouseEvent> mouseOverEvent =
+      const EventStreamProvider<MouseEvent>('mouseover');
+
+  static const EventStreamProvider<MouseEvent> mouseUpEvent =
+      const EventStreamProvider<MouseEvent>('mouseup');
+
+  static const EventStreamProvider<WheelEvent> mouseWheelEvent =
+      const EventStreamProvider<WheelEvent>('mousewheel');
+
+  static const EventStreamProvider<Event> pauseEvent =
+      const EventStreamProvider<Event>('pause');
+
+  static const EventStreamProvider<Event> playEvent =
+      const EventStreamProvider<Event>('play');
+
+  static const EventStreamProvider<Event> playingEvent =
+      const EventStreamProvider<Event>('playing');
+
+  static const EventStreamProvider<Event> rateChangeEvent =
+      const EventStreamProvider<Event>('ratechange');
+
+  static const EventStreamProvider<Event> resetEvent =
+      const EventStreamProvider<Event>('reset');
+
+  static const EventStreamProvider<Event> resizeEvent =
+      const EventStreamProvider<Event>('resize');
+
+  static const EventStreamProvider<Event> scrollEvent =
+      const EventStreamProvider<Event>('scroll');
+
+  static const EventStreamProvider<Event> seekedEvent =
+      const EventStreamProvider<Event>('seeked');
+
+  static const EventStreamProvider<Event> seekingEvent =
+      const EventStreamProvider<Event>('seeking');
+
+  static const EventStreamProvider<Event> selectEvent =
+      const EventStreamProvider<Event>('select');
+
+  static const EventStreamProvider<Event> stalledEvent =
+      const EventStreamProvider<Event>('stalled');
+
+  static const EventStreamProvider<Event> submitEvent =
+      const EventStreamProvider<Event>('submit');
+
+  static const EventStreamProvider<Event> suspendEvent =
+      const EventStreamProvider<Event>('suspend');
+
+  static const EventStreamProvider<Event> timeUpdateEvent =
+      const EventStreamProvider<Event>('timeupdate');
+
+  static const EventStreamProvider<TouchEvent> touchCancelEvent =
+      const EventStreamProvider<TouchEvent>('touchcancel');
+
+  static const EventStreamProvider<TouchEvent> touchEndEvent =
+      const EventStreamProvider<TouchEvent>('touchend');
+
+  static const EventStreamProvider<TouchEvent> touchMoveEvent =
+      const EventStreamProvider<TouchEvent>('touchmove');
+
+  static const EventStreamProvider<TouchEvent> touchStartEvent =
+      const EventStreamProvider<TouchEvent>('touchstart');
+
+  static const EventStreamProvider<Event> volumeChangeEvent =
+      const EventStreamProvider<Event>('volumechange');
+
+  static const EventStreamProvider<Event> waitingEvent =
+      const EventStreamProvider<Event>('waiting');
+
+  static const EventStreamProvider<WheelEvent> wheelEvent =
+      const EventStreamProvider<WheelEvent>('wheel');
+
+  Stream<Event> get onAbort => abortEvent.forTarget(this);
+
+  Stream<Event> get onBlur => blurEvent.forTarget(this);
+
+  Stream<Event> get onCanPlay => canPlayEvent.forTarget(this);
+
+  Stream<Event> get onCanPlayThrough => canPlayThroughEvent.forTarget(this);
+
+  Stream<Event> get onChange => changeEvent.forTarget(this);
+
+  Stream<MouseEvent> get onClick => clickEvent.forTarget(this);
+
+  Stream<MouseEvent> get onContextMenu => contextMenuEvent.forTarget(this);
+
+  @DomName('GlobalEventHandlers.ondblclick')
+  Stream<Event> get onDoubleClick => doubleClickEvent.forTarget(this);
+
+  Stream<MouseEvent> get onDrag => dragEvent.forTarget(this);
+
+  Stream<MouseEvent> get onDragEnd => dragEndEvent.forTarget(this);
+
+  Stream<MouseEvent> get onDragEnter => dragEnterEvent.forTarget(this);
+
+  Stream<MouseEvent> get onDragLeave => dragLeaveEvent.forTarget(this);
+
+  Stream<MouseEvent> get onDragOver => dragOverEvent.forTarget(this);
+
+  Stream<MouseEvent> get onDragStart => dragStartEvent.forTarget(this);
+
+  Stream<MouseEvent> get onDrop => dropEvent.forTarget(this);
+
+  Stream<Event> get onDurationChange => durationChangeEvent.forTarget(this);
+
+  Stream<Event> get onEmptied => emptiedEvent.forTarget(this);
+
+  Stream<Event> get onEnded => endedEvent.forTarget(this);
+
+  Stream<Event> get onError => errorEvent.forTarget(this);
+
+  Stream<Event> get onFocus => focusEvent.forTarget(this);
+
+  Stream<Event> get onInput => inputEvent.forTarget(this);
+
+  Stream<Event> get onInvalid => invalidEvent.forTarget(this);
+
+  Stream<KeyboardEvent> get onKeyDown => keyDownEvent.forTarget(this);
+
+  Stream<KeyboardEvent> get onKeyPress => keyPressEvent.forTarget(this);
+
+  Stream<KeyboardEvent> get onKeyUp => keyUpEvent.forTarget(this);
+
+  Stream<Event> get onLoad => loadEvent.forTarget(this);
+
+  Stream<Event> get onLoadedData => loadedDataEvent.forTarget(this);
+
+  Stream<Event> get onLoadedMetadata => loadedMetadataEvent.forTarget(this);
+
+  Stream<MouseEvent> get onMouseDown => mouseDownEvent.forTarget(this);
+
+  Stream<MouseEvent> get onMouseEnter => mouseEnterEvent.forTarget(this);
+
+  Stream<MouseEvent> get onMouseLeave => mouseLeaveEvent.forTarget(this);
+
+  Stream<MouseEvent> get onMouseMove => mouseMoveEvent.forTarget(this);
+
+  Stream<MouseEvent> get onMouseOut => mouseOutEvent.forTarget(this);
+
+  Stream<MouseEvent> get onMouseOver => mouseOverEvent.forTarget(this);
+
+  Stream<MouseEvent> get onMouseUp => mouseUpEvent.forTarget(this);
+
+  Stream<WheelEvent> get onMouseWheel => mouseWheelEvent.forTarget(this);
+
+  Stream<Event> get onPause => pauseEvent.forTarget(this);
+
+  Stream<Event> get onPlay => playEvent.forTarget(this);
+
+  Stream<Event> get onPlaying => playingEvent.forTarget(this);
+
+  Stream<Event> get onRateChange => rateChangeEvent.forTarget(this);
+
+  Stream<Event> get onReset => resetEvent.forTarget(this);
+
+  Stream<Event> get onResize => resizeEvent.forTarget(this);
+
+  Stream<Event> get onScroll => scrollEvent.forTarget(this);
+
+  Stream<Event> get onSeeked => seekedEvent.forTarget(this);
+
+  Stream<Event> get onSeeking => seekingEvent.forTarget(this);
+
+  Stream<Event> get onSelect => selectEvent.forTarget(this);
+
+  Stream<Event> get onStalled => stalledEvent.forTarget(this);
+
+  Stream<Event> get onSubmit => submitEvent.forTarget(this);
+
+  Stream<Event> get onSuspend => suspendEvent.forTarget(this);
+
+  Stream<Event> get onTimeUpdate => timeUpdateEvent.forTarget(this);
+
+  Stream<TouchEvent> get onTouchCancel => touchCancelEvent.forTarget(this);
+
+  Stream<TouchEvent> get onTouchEnd => touchEndEvent.forTarget(this);
+
+  Stream<TouchEvent> get onTouchMove => touchMoveEvent.forTarget(this);
+
+  Stream<TouchEvent> get onTouchStart => touchStartEvent.forTarget(this);
+
+  Stream<Event> get onVolumeChange => volumeChangeEvent.forTarget(this);
+
+  Stream<Event> get onWaiting => waitingEvent.forTarget(this);
+
+  Stream<WheelEvent> get onWheel => wheelEvent.forTarget(this);
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("Gyroscope")
+class Gyroscope extends Sensor {
+  // To suppress missing implicit constructor warnings.
+  factory Gyroscope._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory Gyroscope([Map sensorOptions]) {
+    if (sensorOptions != null) {
+      var sensorOptions_1 = convertDartToNative_Dictionary(sensorOptions);
+      return Gyroscope._create_1(sensorOptions_1);
+    }
+    return Gyroscope._create_2();
+  }
+  static Gyroscope _create_1(sensorOptions) =>
+      JS('Gyroscope', 'new Gyroscope(#)', sensorOptions);
+  static Gyroscope _create_2() => JS('Gyroscope', 'new Gyroscope()');
+
+  final num x;
+
+  final num y;
+
+  final num z;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/**
+ * An `<hr>` tag.
+ */
+@Native("HTMLHRElement")
+class HRElement extends HtmlElement {
+  // To suppress missing implicit constructor warnings.
+  factory HRElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory HRElement() => JS('returns:HRElement;creates:HRElement;new:true',
+      '#.createElement(#)', document, "hr");
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  HRElement.created() : super.created();
+
+  String color;
+}
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.FIREFOX)
+@SupportedBrowser(SupportedBrowser.SAFARI)
+@Unstable()
+@Native("HashChangeEvent")
+class HashChangeEvent extends Event {
+  factory HashChangeEvent(String type,
+      {bool canBubble: true,
+      bool cancelable: true,
+      String oldUrl,
+      String newUrl}) {
+    var options = {
+      'canBubble': canBubble,
+      'cancelable': cancelable,
+      'oldURL': oldUrl,
+      'newURL': newUrl,
+    };
+    return JS('HashChangeEvent', 'new HashChangeEvent(#, #)', type,
+        convertDartToNative_Dictionary(options));
+  }
+
+  factory HashChangeEvent._(String type, [Map eventInitDict]) {
+    if (eventInitDict != null) {
+      var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+      return HashChangeEvent._create_1(type, eventInitDict_1);
+    }
+    return HashChangeEvent._create_2(type);
+  }
+  static HashChangeEvent _create_1(type, eventInitDict) =>
+      JS('HashChangeEvent', 'new HashChangeEvent(#,#)', type, eventInitDict);
+  static HashChangeEvent _create_2(type) =>
+      JS('HashChangeEvent', 'new HashChangeEvent(#)', type);
+
+  /// Checks if this type is supported on the current platform.
+  static bool get supported => Device.isEventTypeSupported('HashChangeEvent');
+
+  @JSName('newURL')
+  final String newUrl;
+
+  @JSName('oldURL')
+  final String oldUrl;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("HTMLHeadElement")
+class HeadElement extends HtmlElement {
+  // To suppress missing implicit constructor warnings.
+  factory HeadElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory HeadElement() => JS(
+      'returns:HeadElement;creates:HeadElement;new:true',
+      '#.createElement(#)',
+      document,
+      "head");
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  HeadElement.created() : super.created();
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("Headers")
+class Headers extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory Headers._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory Headers([Object init]) {
+    if (init != null) {
+      return Headers._create_1(init);
+    }
+    return Headers._create_2();
+  }
+  static Headers _create_1(init) => JS('Headers', 'new Headers(#)', init);
+  static Headers _create_2() => JS('Headers', 'new Headers()');
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("HTMLHeadingElement")
+class HeadingElement extends HtmlElement {
+  // To suppress missing implicit constructor warnings.
+  factory HeadingElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory HeadingElement.h1() => JS(
+      'returns:HeadingElement;creates:HeadingElement;new:true',
+      '#.createElement(#)',
+      document,
+      "h1");
+
+  factory HeadingElement.h2() => JS(
+      'returns:HeadingElement;creates:HeadingElement;new:true',
+      '#.createElement(#)',
+      document,
+      "h2");
+
+  factory HeadingElement.h3() => JS(
+      'returns:HeadingElement;creates:HeadingElement;new:true',
+      '#.createElement(#)',
+      document,
+      "h3");
+
+  factory HeadingElement.h4() => JS(
+      'returns:HeadingElement;creates:HeadingElement;new:true',
+      '#.createElement(#)',
+      document,
+      "h4");
+
+  factory HeadingElement.h5() => JS(
+      'returns:HeadingElement;creates:HeadingElement;new:true',
+      '#.createElement(#)',
+      document,
+      "h5");
+
+  factory HeadingElement.h6() => JS(
+      'returns:HeadingElement;creates:HeadingElement;new:true',
+      '#.createElement(#)',
+      document,
+      "h6");
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  HeadingElement.created() : super.created();
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("History")
+class History extends Interceptor implements HistoryBase {
+  /**
+   * Checks if the State APIs are supported on the current platform.
+   *
+   * See also:
+   *
+   * * [pushState]
+   * * [replaceState]
+   * * [state]
+   */
+  static bool get supportsState => JS('bool', '!!window.history.pushState');
+  // To suppress missing implicit constructor warnings.
+  factory History._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final int length;
+
+  String scrollRestoration;
+
+  dynamic get state =>
+      convertNativeToDart_SerializedScriptValue(this._get_state);
+  @JSName('state')
+  @annotation_Creates_SerializedScriptValue
+  @annotation_Returns_SerializedScriptValue
+  final dynamic _get_state;
+
+  void back() native;
+
+  void forward() native;
+
+  void go([int delta]) native;
+
+  @SupportedBrowser(SupportedBrowser.CHROME)
+  @SupportedBrowser(SupportedBrowser.FIREFOX)
+  @SupportedBrowser(SupportedBrowser.IE, '10')
+  @SupportedBrowser(SupportedBrowser.SAFARI)
+  void pushState(/*SerializedScriptValue*/ data, String title, String url) {
+    var data_1 = convertDartToNative_SerializedScriptValue(data);
+    _pushState_1(data_1, title, url);
+    return;
+  }
+
+  @JSName('pushState')
+  @SupportedBrowser(SupportedBrowser.CHROME)
+  @SupportedBrowser(SupportedBrowser.FIREFOX)
+  @SupportedBrowser(SupportedBrowser.IE, '10')
+  @SupportedBrowser(SupportedBrowser.SAFARI)
+  void _pushState_1(data, title, url) native;
+
+  @SupportedBrowser(SupportedBrowser.CHROME)
+  @SupportedBrowser(SupportedBrowser.FIREFOX)
+  @SupportedBrowser(SupportedBrowser.IE, '10')
+  @SupportedBrowser(SupportedBrowser.SAFARI)
+  void replaceState(/*SerializedScriptValue*/ data, String title, String url) {
+    var data_1 = convertDartToNative_SerializedScriptValue(data);
+    _replaceState_1(data_1, title, url);
+    return;
+  }
+
+  @JSName('replaceState')
+  @SupportedBrowser(SupportedBrowser.CHROME)
+  @SupportedBrowser(SupportedBrowser.FIREFOX)
+  @SupportedBrowser(SupportedBrowser.IE, '10')
+  @SupportedBrowser(SupportedBrowser.SAFARI)
+  void _replaceState_1(data, title, url) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("HTMLCollection")
+class HtmlCollection extends Interceptor
+    with ListMixin<Node>, ImmutableListMixin<Node>
+    implements JavaScriptIndexingBehavior<Node>, List<Node> {
+  // To suppress missing implicit constructor warnings.
+  factory HtmlCollection._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  int get length => JS("int", "#.length", this);
+
+  Node operator [](int index) {
+    if (JS("bool", "# >>> 0 !== # || # >= #", index, index, index, length))
+      throw new RangeError.index(index, this);
+    return JS("Node", "#[#]", this, index);
+  }
+
+  void operator []=(int index, Node value) {
+    throw new UnsupportedError("Cannot assign element of immutable List.");
+  }
+  // -- start List<Node> mixins.
+  // Node is the element type.
+
+  set length(int value) {
+    throw new UnsupportedError("Cannot resize immutable List.");
+  }
+
+  Node get first {
+    if (this.length > 0) {
+      return JS('Node', '#[0]', this);
+    }
+    throw new StateError("No elements");
+  }
+
+  Node get last {
+    int len = this.length;
+    if (len > 0) {
+      return JS('Node', '#[#]', this, len - 1);
+    }
+    throw new StateError("No elements");
+  }
+
+  Node get single {
+    int len = this.length;
+    if (len == 1) {
+      return JS('Node', '#[0]', this);
+    }
+    if (len == 0) throw new StateError("No elements");
+    throw new StateError("More than one element");
+  }
+
+  Node elementAt(int index) => this[index];
+  // -- end List<Node> mixins.
+
+  Node item(int index) native;
+
+  Object namedItem(String name) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+@Native("HTMLDocument")
+class HtmlDocument extends Document {
+  // To suppress missing implicit constructor warnings.
+  factory HtmlDocument._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  BodyElement body;
+
+  /// UNSTABLE: Chrome-only - create a Range from the given point.
+  @Unstable()
+  Range caretRangeFromPoint(int x, int y) {
+    return _caretRangeFromPoint(x, y);
+  }
+
+  Element elementFromPoint(int x, int y) {
+    return _elementFromPoint(x, y);
+  }
+
+  HeadElement get head => _head;
+
+  String get lastModified => _lastModified;
+
+  String get preferredStylesheetSet => _preferredStylesheetSet;
+
+  String get referrer => _referrer;
+
+  String get selectedStylesheetSet => _selectedStylesheetSet;
+  set selectedStylesheetSet(String value) {
+    _selectedStylesheetSet = value;
+  }
+
+  List<StyleSheet> get styleSheets => _styleSheets;
+
+  String get title => _title;
+
+  set title(String value) {
+    _title = value;
+  }
+
+  /**
+   * Returns page to standard layout.
+   *
+   * Has no effect if the page is not in fullscreen mode.
+   *
+   * ## Other resources
+   *
+   * * [Fullscreen
+   *   API](https://developer.mozilla.org/en-US/docs/Web/API/Fullscreen_API)
+   *   from MDN.
+   * * [Fullscreen specification](http://www.w3.org/TR/fullscreen/) from W3C.
+   */
+  @SupportedBrowser(SupportedBrowser.CHROME)
+  @SupportedBrowser(SupportedBrowser.SAFARI)
+  void exitFullscreen() {
+    _webkitExitFullscreen();
+  }
+
+  /**
+   * Register a custom subclass of Element to be instantiatable by the DOM.
+   *
+   * This is necessary to allow the construction of any custom elements.
+   *
+   * The class being registered must either subclass HtmlElement or SvgElement.
+   * If they subclass these directly then they can be used as:
+   *
+   *     class FooElement extends HtmlElement{
+   *        void created() {
+   *          print('FooElement created!');
+   *        }
+   *     }
+   *
+   *     main() {
+   *       document.registerElement('x-foo', FooElement);
+   *       var myFoo = new Element.tag('x-foo');
+   *       // prints 'FooElement created!' to the console.
+   *     }
+   *
+   * The custom element can also be instantiated via HTML using the syntax
+   * `<x-foo></x-foo>`
+   *
+   * Other elements can be subclassed as well:
+   *
+   *     class BarElement extends InputElement{
+   *        void created() {
+   *          print('BarElement created!');
+   *        }
+   *     }
+   *
+   *     main() {
+   *       document.registerElement('x-bar', BarElement);
+   *       var myBar = new Element.tag('input', 'x-bar');
+   *       // prints 'BarElement created!' to the console.
+   *     }
+   *
+   * This custom element can also be instantiated via HTML using the syntax
+   * `<input is="x-bar"></input>`
+   *
+   */
+  Function registerElement2(String tag, [Map options]) {
+    return _registerCustomElement(JS('', 'window'), this, tag, options);
+  }
+
+  /** *Deprecated*: use [registerElement] instead. */
+  @deprecated
+  void register(String tag, Type customElementClass, {String extendsTag}) {
+    return registerElement(tag, customElementClass, extendsTag: extendsTag);
+  }
+
+  /**
+   * Static factory designed to expose `visibilitychange` events to event
+   * handlers that are not necessarily instances of [Document].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  @SupportedBrowser(SupportedBrowser.CHROME)
+  @SupportedBrowser(SupportedBrowser.FIREFOX)
+  @SupportedBrowser(SupportedBrowser.IE, '10')
+  static const EventStreamProvider<Event> visibilityChangeEvent =
+      const _CustomEventStreamProvider<Event>(
+          _determineVisibilityChangeEventType);
+
+  static String _determineVisibilityChangeEventType(EventTarget e) {
+    if (JS('bool', '(typeof #.hidden !== "undefined")', e)) {
+      // Opera 12.10 and Firefox 18 and later support
+      return 'visibilitychange';
+    } else if (JS('bool', '(typeof #.mozHidden !== "undefined")', e)) {
+      return 'mozvisibilitychange';
+    } else if (JS('bool', '(typeof #.msHidden !== "undefined")', e)) {
+      return 'msvisibilitychange';
+    } else if (JS('bool', '(typeof #.webkitHidden !== "undefined")', e)) {
+      return 'webkitvisibilitychange';
+    }
+    return 'visibilitychange';
+  }
+
+  @SupportedBrowser(SupportedBrowser.CHROME)
+  @SupportedBrowser(SupportedBrowser.FIREFOX)
+  @SupportedBrowser(SupportedBrowser.IE, '10')
+  Stream<Event> get onVisibilityChange => visibilityChangeEvent.forTarget(this);
+
+  /// Creates an element upgrader which can be used to change the Dart wrapper
+  /// type for elements.
+  ///
+  /// The type specified must be a subclass of HtmlElement, when an element is
+  /// upgraded then the created constructor will be invoked on that element.
+  ///
+  /// If the type is not a direct subclass of HtmlElement then the extendsTag
+  /// parameter must be provided.
+  ElementUpgrader createElementUpgrader(Type type, {String extendsTag}) {
+    return new _JSElementUpgrader(this, type, extendsTag);
+  }
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("HTMLFormControlsCollection")
+class HtmlFormControlsCollection extends HtmlCollection {
+  // To suppress missing implicit constructor warnings.
+  factory HtmlFormControlsCollection._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  Node item(int index) native;
+
+  Object namedItem(String name) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("HTMLHtmlElement")
+class HtmlHtmlElement extends HtmlElement {
+  // To suppress missing implicit constructor warnings.
+  factory HtmlHtmlElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory HtmlHtmlElement() => JS(
+      'returns:HtmlHtmlElement;creates:HtmlHtmlElement;new:true',
+      '#.createElement(#)',
+      document,
+      "html");
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  HtmlHtmlElement.created() : super.created();
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("HTMLHyperlinkElementUtils")
+class HtmlHyperlinkElementUtils extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory HtmlHyperlinkElementUtils._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  String hash;
+
+  String host;
+
+  String hostname;
+
+  String href;
+
+  final String origin;
+
+  String password;
+
+  String pathname;
+
+  String port;
+
+  String protocol;
+
+  String search;
+
+  String username;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("HTMLOptionsCollection")
+class HtmlOptionsCollection extends HtmlCollection {
+  // To suppress missing implicit constructor warnings.
+  factory HtmlOptionsCollection._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  @JSName('item')
+  Element _item(int index) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/**
+  * A client-side XHR request for getting data from a URL,
+  * formally known as XMLHttpRequest.
+  *
+  * HttpRequest can be used to obtain data from HTTP and FTP protocols,
+  * and is useful for AJAX-style page updates.
+  *
+  * The simplest way to get the contents of a text file, such as a
+  * JSON-formatted file, is with [getString].
+  * For example, the following code gets the contents of a JSON file
+  * and prints its length:
+  *
+  *     var path = 'myData.json';
+  *     HttpRequest.getString(path).then((String fileContents) {
+  *       print(fileContents.length);
+  *     }).catchError((error) {
+  *       print(error.toString());
+  *     });
+  *
+  * ## Fetching data from other servers
+  *
+  * For security reasons, browsers impose restrictions on requests
+  * made by embedded apps.
+  * With the default behavior of this class,
+  * the code making the request must be served from the same origin
+  * (domain name, port, and application layer protocol)
+  * as the requested resource.
+  * In the example above, the myData.json file must be co-located with the
+  * app that uses it.
+  * You might be able to
+  * [get around this restriction](http://www.dartlang.org/articles/json-web-service/#a-note-on-cors-and-httprequest)
+  * by using CORS headers or JSONP.
+  *
+  * ## Other resources
+  *
+  * * [Fetch Data Dynamically](https://www.dartlang.org/docs/tutorials/fetchdata/),
+  * a tutorial from _A Game of Darts_,
+  * shows two different ways to use HttpRequest to get a JSON file.
+  * * [Get Input from a Form](https://www.dartlang.org/docs/tutorials/forms/),
+  * another tutorial from _A Game of Darts_,
+  * shows using HttpRequest with a custom server.
+  * * [Dart article on using HttpRequests](http://www.dartlang.org/articles/json-web-service/#getting-data)
+  * * [JS XMLHttpRequest](https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest)
+  * * [Using XMLHttpRequest](https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest/Using_XMLHttpRequest)
+ */
+@Native("XMLHttpRequest")
+class HttpRequest extends HttpRequestEventTarget {
+  /**
+   * Creates a GET request for the specified [url].
+   *
+   * This is similar to [request] but specialized for HTTP GET requests which
+   * return text content.
+   *
+   * To add query parameters, append them to the [url] following a `?`,
+   * joining each key to its value with `=` and separating key-value pairs with
+   * `&`.
+   *
+   *     var name = Uri.encodeQueryComponent('John');
+   *     var id = Uri.encodeQueryComponent('42');
+   *     HttpRequest.getString('users.json?name=$name&id=$id')
+   *       .then((String resp) {
+   *         // Do something with the response.
+   *     });
+   *
+   * See also:
+   *
+   * * [request]
+   */
+  static Future<String> getString(String url,
+      {bool withCredentials, void onProgress(ProgressEvent e)}) {
+    return request(url,
+            withCredentials: withCredentials, onProgress: onProgress)
+        .then((HttpRequest xhr) => xhr.responseText);
+  }
+
+  /**
+   * Makes a server POST request with the specified data encoded as form data.
+   *
+   * This is roughly the POST equivalent of [getString]. This method is similar
+   * to sending a [FormData] object with broader browser support but limited to
+   * String values.
+   *
+   * If [data] is supplied, the key/value pairs are URI encoded with
+   * [Uri.encodeQueryComponent] and converted into an HTTP query string.
+   *
+   * Unless otherwise specified, this method appends the following header:
+   *
+   *     Content-Type: application/x-www-form-urlencoded; charset=UTF-8
+   *
+   * Here's an example of using this method:
+   *
+   *     var data = { 'firstName' : 'John', 'lastName' : 'Doe' };
+   *     HttpRequest.postFormData('/send', data).then((HttpRequest resp) {
+   *       // Do something with the response.
+   *     });
+   *
+   * See also:
+   *
+   * * [request]
+   */
+  static Future<HttpRequest> postFormData(String url, Map<String, String> data,
+      {bool withCredentials,
+      String responseType,
+      Map<String, String> requestHeaders,
+      void onProgress(ProgressEvent e)}) {
+    var parts = [];
+    data.forEach((key, value) {
+      parts.add('${Uri.encodeQueryComponent(key)}='
+          '${Uri.encodeQueryComponent(value)}');
+    });
+    var formData = parts.join('&');
+
+    if (requestHeaders == null) {
+      requestHeaders = <String, String>{};
+    }
+    requestHeaders.putIfAbsent('Content-Type',
+        () => 'application/x-www-form-urlencoded; charset=UTF-8');
+
+    return request(url,
+        method: 'POST',
+        withCredentials: withCredentials,
+        responseType: responseType,
+        requestHeaders: requestHeaders,
+        sendData: formData,
+        onProgress: onProgress);
+  }
+
+  /**
+   * Creates and sends a URL request for the specified [url].
+   *
+   * By default `request` will perform an HTTP GET request, but a different
+   * method (`POST`, `PUT`, `DELETE`, etc) can be used by specifying the
+   * [method] parameter. (See also [HttpRequest.postFormData] for `POST` 
+   * requests only.
+   *
+   * The Future is completed when the response is available.
+   *
+   * If specified, `sendData` will send data in the form of a [ByteBuffer],
+   * [Blob], [Document], [String], or [FormData] along with the HttpRequest.
+   *
+   * If specified, [responseType] sets the desired response format for the
+   * request. By default it is [String], but can also be 'arraybuffer', 'blob', 
+   * 'document', 'json', or 'text'. See also [HttpRequest.responseType] 
+   * for more information.
+   *
+   * The [withCredentials] parameter specified that credentials such as a cookie
+   * (already) set in the header or
+   * [authorization headers](http://tools.ietf.org/html/rfc1945#section-10.2)
+   * should be specified for the request. Details to keep in mind when using
+   * credentials:
+   *
+   * * Using credentials is only useful for cross-origin requests.
+   * * The `Access-Control-Allow-Origin` header of `url` cannot contain a wildcard (*).
+   * * The `Access-Control-Allow-Credentials` header of `url` must be set to true.
+   * * If `Access-Control-Expose-Headers` has not been set to true, only a subset of all the response headers will be returned when calling [getAllRequestHeaders].
+   *
+   * The following is equivalent to the [getString] sample above:
+   *
+   *     var name = Uri.encodeQueryComponent('John');
+   *     var id = Uri.encodeQueryComponent('42');
+   *     HttpRequest.request('users.json?name=$name&id=$id')
+   *       .then((HttpRequest resp) {
+   *         // Do something with the response.
+   *     });
+   *
+   * Here's an example of submitting an entire form with [FormData].
+   *
+   *     var myForm = querySelector('form#myForm');
+   *     var data = new FormData(myForm);
+   *     HttpRequest.request('/submit', method: 'POST', sendData: data)
+   *       .then((HttpRequest resp) {
+   *         // Do something with the response.
+   *     });
+   *
+   * Note that requests for file:// URIs are only supported by Chrome extensions
+   * with appropriate permissions in their manifest. Requests to file:// URIs
+   * will also never fail- the Future will always complete successfully, even
+   * when the file cannot be found.
+   *
+   * See also: [authorization headers](http://en.wikipedia.org/wiki/Basic_access_authentication).
+   */
+  static Future<HttpRequest> request(String url,
+      {String method,
+      bool withCredentials,
+      String responseType,
+      String mimeType,
+      Map<String, String> requestHeaders,
+      sendData,
+      void onProgress(ProgressEvent e)}) {
+    var completer = new Completer<HttpRequest>();
+
+    var xhr = new HttpRequest();
+    if (method == null) {
+      method = 'GET';
+    }
+    xhr.open(method, url, async: true);
+
+    if (withCredentials != null) {
+      xhr.withCredentials = withCredentials;
+    }
+
+    if (responseType != null) {
+      xhr.responseType = responseType;
+    }
+
+    if (mimeType != null) {
+      xhr.overrideMimeType(mimeType);
+    }
+
+    if (requestHeaders != null) {
+      requestHeaders.forEach((header, value) {
+        xhr.setRequestHeader(header, value);
+      });
+    }
+
+    if (onProgress != null) {
+      xhr.onProgress.listen(onProgress);
+    }
+
+    xhr.onLoad.listen((e) {
+      var accepted = xhr.status >= 200 && xhr.status < 300;
+      var fileUri = xhr.status == 0; // file:// URIs have status of 0.
+      var notModified = xhr.status == 304;
+      // Redirect status is specified up to 307, but others have been used in
+      // practice. Notably Google Drive uses 308 Resume Incomplete for
+      // resumable uploads, and it's also been used as a redirect. The
+      // redirect case will be handled by the browser before it gets to us,
+      // so if we see it we should pass it through to the user.
+      var unknownRedirect = xhr.status > 307 && xhr.status < 400;
+
+      if (accepted || fileUri || notModified || unknownRedirect) {
+        completer.complete(xhr);
+      } else {
+        completer.completeError(e);
+      }
+    });
+
+    xhr.onError.listen(completer.completeError);
+
+    if (sendData != null) {
+      xhr.send(sendData);
+    } else {
+      xhr.send();
+    }
+
+    return completer.future;
+  }
+
+  /**
+   * Checks to see if the Progress event is supported on the current platform.
+   */
+  static bool get supportsProgressEvent {
+    var xhr = new HttpRequest();
+    return JS('bool', '("onprogress" in #)', xhr);
+  }
+
+  /**
+   * Checks to see if the current platform supports making cross origin
+   * requests.
+   *
+   * Note that even if cross origin requests are supported, they still may fail
+   * if the destination server does not support CORS requests.
+   */
+  static bool get supportsCrossOrigin {
+    var xhr = new HttpRequest();
+    return JS('bool', '("withCredentials" in #)', xhr);
+  }
+
+  /**
+   * Checks to see if the LoadEnd event is supported on the current platform.
+   */
+  static bool get supportsLoadEndEvent {
+    var xhr = new HttpRequest();
+    return JS('bool', '("onloadend" in #)', xhr);
+  }
+
+  /**
+   * Checks to see if the overrideMimeType method is supported on the current
+   * platform.
+   */
+  static bool get supportsOverrideMimeType {
+    var xhr = new HttpRequest();
+    return JS('bool', '("overrideMimeType" in #)', xhr);
+  }
+
+  /**
+   * Makes a cross-origin request to the specified URL.
+   *
+   * This API provides a subset of [request] which works on IE9. If IE9
+   * cross-origin support is not required then [request] should be used instead.
+   */
+  static Future<String> requestCrossOrigin(String url,
+      {String method, String sendData}) {
+    if (supportsCrossOrigin) {
+      return request(url, method: method, sendData: sendData).then((xhr) {
+        return xhr.responseText;
+      });
+    }
+    var completer = new Completer<String>();
+    if (method == null) {
+      method = 'GET';
+    }
+    var xhr = JS('var', 'new XDomainRequest()');
+    JS('', '#.open(#, #)', xhr, method, url);
+    JS(
+        '',
+        '#.onload = #',
+        xhr,
+        convertDartClosureToJS((e) {
+          var response = JS('String', '#.responseText', xhr);
+          completer.complete(response);
+        }, 1));
+    JS(
+        '',
+        '#.onerror = #',
+        xhr,
+        convertDartClosureToJS((e) {
+          completer.completeError(e);
+        }, 1));
+
+    // IE9 RTM - XDomainRequest issued requests may abort if all event handlers
+    // not specified
+    // http://social.msdn.microsoft.com/Forums/ie/en-US/30ef3add-767c-4436-b8a9-f1ca19b4812e/ie9-rtm-xdomainrequest-issued-requests-may-abort-if-all-event-handlers-not-specified
+    JS('', '#.onprogress = {}', xhr);
+    JS('', '#.ontimeout = {}', xhr);
+    JS('', '#.timeout = Number.MAX_VALUE', xhr);
+
+    if (sendData != null) {
+      JS('', '#.send(#)', xhr, sendData);
+    } else {
+      JS('', '#.send()', xhr);
+    }
+
+    return completer.future;
+  }
+
+  /**
+   * Returns all response headers as a key-value map.
+   *
+   * Multiple values for the same header key can be combined into one,
+   * separated by a comma and a space.
+   *
+   * See: http://www.w3.org/TR/XMLHttpRequest/#the-getresponseheader()-method
+   */
+  Map<String, String> get responseHeaders {
+    // from Closure's goog.net.Xhrio.getResponseHeaders.
+    var headers = <String, String>{};
+    var headersString = this.getAllResponseHeaders();
+    if (headersString == null) {
+      return headers;
+    }
+    var headersList = headersString.split('\r\n');
+    for (var header in headersList) {
+      if (header.isEmpty) {
+        continue;
+      }
+
+      var splitIdx = header.indexOf(': ');
+      if (splitIdx == -1) {
+        continue;
+      }
+      var key = header.substring(0, splitIdx).toLowerCase();
+      var value = header.substring(splitIdx + 2);
+      if (headers.containsKey(key)) {
+        headers[key] = '${headers[key]}, $value';
+      } else {
+        headers[key] = value;
+      }
+    }
+    return headers;
+  }
+
+  /**
+   * Specify the desired `url`, and `method` to use in making the request.
+   *
+   * By default the request is done asyncronously, with no user or password
+   * authentication information. If `async` is false, the request will be sent
+   * synchronously.
+   *
+   * Calling `open` again on a currently active request is equivalent to
+   * calling [abort].
+   *
+   * Note: Most simple HTTP requests can be accomplished using the [getString],
+   * [request], [requestCrossOrigin], or [postFormData] methods. Use of this
+   * `open` method is intended only for more complex HTTP requests where
+   * finer-grained control is needed.
+   */
+  void open(String method, String url,
+      {bool async, String user, String password}) native;
+
+  // To suppress missing implicit constructor warnings.
+  factory HttpRequest._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  /**
+   * Static factory designed to expose `readystatechange` events to event
+   * handlers that are not necessarily instances of [HttpRequest].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<Event> readyStateChangeEvent =
+      const EventStreamProvider<Event>('readystatechange');
+
+  /**
+   * General constructor for any type of request (GET, POST, etc).
+   *
+   * This call is used in conjunction with [open]:
+   *
+   *     var request = new HttpRequest();
+   *     request.open('GET', 'http://dartlang.org');
+   *     request.onLoad.listen((event) => print(
+   *         'Request complete ${event.target.reponseText}'));
+   *     request.send();
+   *
+   * is the (more verbose) equivalent of
+   *
+   *     HttpRequest.getString('http://dartlang.org').then(
+   *         (result) => print('Request complete: $result'));
+   */
+  factory HttpRequest() {
+    return HttpRequest._create_1();
+  }
+  static HttpRequest _create_1() => JS('HttpRequest', 'new XMLHttpRequest()');
+
+  static const int DONE = 4;
+
+  static const int HEADERS_RECEIVED = 2;
+
+  static const int LOADING = 3;
+
+  static const int OPENED = 1;
+
+  static const int UNSENT = 0;
+
+  /**
+   * Indicator of the current state of the request:
+   *
+   * <table>
+   *   <tr>
+   *     <td>Value</td>
+   *     <td>State</td>
+   *     <td>Meaning</td>
+   *   </tr>
+   *   <tr>
+   *     <td>0</td>
+   *     <td>unsent</td>
+   *     <td><code>open()</code> has not yet been called</td>
+   *   </tr>
+   *   <tr>
+   *     <td>1</td>
+   *     <td>opened</td>
+   *     <td><code>send()</code> has not yet been called</td>
+   *   </tr>
+   *   <tr>
+   *     <td>2</td>
+   *     <td>headers received</td>
+   *     <td><code>sent()</code> has been called; response headers and <code>status</code> are available</td>
+   *   </tr>
+   *   <tr>
+   *     <td>3</td> <td>loading</td> <td><code>responseText</code> holds some data</td>
+   *   </tr>
+   *   <tr>
+   *     <td>4</td> <td>done</td> <td>request is complete</td>
+   *   </tr>
+   * </table>
+   */
+  final int readyState;
+
+  /**
+   * The data received as a reponse from the request.
+   *
+   * The data could be in the
+   * form of a [String], [ByteBuffer], [Document], [Blob], or json (also a
+   * [String]). `null` indicates request failure.
+   */
+  @SupportedBrowser(SupportedBrowser.CHROME)
+  @SupportedBrowser(SupportedBrowser.FIREFOX)
+  @SupportedBrowser(SupportedBrowser.IE, '10')
+  @SupportedBrowser(SupportedBrowser.SAFARI)
+  dynamic get response => _convertNativeToDart_XHR_Response(this._get_response);
+  @JSName('response')
+  /**
+   * The data received as a reponse from the request.
+   *
+   * The data could be in the
+   * form of a [String], [ByteBuffer], [Document], [Blob], or json (also a
+   * [String]). `null` indicates request failure.
+   */
+  @SupportedBrowser(SupportedBrowser.CHROME)
+  @SupportedBrowser(SupportedBrowser.FIREFOX)
+  @SupportedBrowser(SupportedBrowser.IE, '10')
+  @SupportedBrowser(SupportedBrowser.SAFARI)
+  @Creates(
+      'NativeByteBuffer|Blob|Document|=Object|JSExtendableArray|String|num')
+  final dynamic _get_response;
+
+  /**
+   * The response in String form or empty String on failure.
+   */
+  final String responseText;
+
+  /**
+   * [String] telling the server the desired response format.
+   *
+   * Default is `String`.
+   * Other options are one of 'arraybuffer', 'blob', 'document', 'json',
+   * 'text'. Some newer browsers will throw NS_ERROR_DOM_INVALID_ACCESS_ERR if
+   * `responseType` is set while performing a synchronous request.
+   *
+   * See also: [MDN
+   * responseType](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest#xmlhttprequest-responsetype)
+   */
+  String responseType;
+
+  @JSName('responseURL')
+  final String responseUrl;
+
+  @JSName('responseXML')
+  /**
+   * The request response, or null on failure.
+   *
+   * The response is processed as
+   * `text/xml` stream, unless responseType = 'document' and the request is
+   * synchronous.
+   */
+  final Document responseXml;
+
+  /**
+   * The HTTP result code from the request (200, 404, etc).
+   * See also: [HTTP Status Codes](http://en.wikipedia.org/wiki/List_of_HTTP_status_codes)
+   */
+  final int status;
+
+  /**
+   * The request response string (such as \"OK\").
+   * See also: [HTTP Status Codes](http://en.wikipedia.org/wiki/List_of_HTTP_status_codes)
+   */
+  final String statusText;
+
+  /**
+   * Length of time in milliseconds before a request is automatically
+   * terminated.
+   *
+   * When the time has passed, a [TimeoutEvent] is dispatched.
+   *
+   * If [timeout] is set to 0, then the request will not time out.
+   *
+   * ## Other resources
+   *
+   * * [XMLHttpRequest.timeout](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest#xmlhttprequest-timeout)
+   *   from MDN.
+   * * [The timeout attribute](http://www.w3.org/TR/XMLHttpRequest/#the-timeout-attribute)
+   *   from W3C.
+   */
+  int timeout;
+
+  /**
+   * [EventTarget] that can hold listeners to track the progress of the request.
+   * The events fired will be members of [HttpRequestUploadEvents].
+   */
+  @Unstable()
+  final HttpRequestUpload upload;
+
+  /**
+   * True if cross-site requests should use credentials such as cookies
+   * or authorization headers; false otherwise.
+   *
+   * This value is ignored for same-site requests.
+   */
+  bool withCredentials;
+
+  /**
+   * Stop the current request.
+   *
+   * The request can only be stopped if readyState is `HEADERS_RECEIVED` or
+   * `LOADING`. If this method is not in the process of being sent, the method
+   * has no effect.
+   */
+  void abort() native;
+
+  /**
+   * Retrieve all the response headers from a request.
+   *
+   * `null` if no headers have been received. For multipart requests,
+   * `getAllResponseHeaders` will return the response headers for the current
+   * part of the request.
+   *
+   * See also [HTTP response
+   * headers](https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#Response_fields)
+   * for a list of common response headers.
+   */
+  @Unstable()
+  String getAllResponseHeaders() native;
+
+  /**
+   * Return the response header named `header`, or null if not found.
+   *
+   * See also [HTTP response
+   * headers](https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#Response_fields)
+   * for a list of common response headers.
+   */
+  @Unstable()
+  String getResponseHeader(String name) native;
+
+  /**
+   * Specify a particular MIME type (such as `text/xml`) desired for the
+   * response.
+   *
+   * This value must be set before the request has been sent. See also the list
+   * of [IANA Official MIME types](https://www.iana.org/assignments/media-types/media-types.xhtml).
+   */
+  @SupportedBrowser(SupportedBrowser.CHROME)
+  @SupportedBrowser(SupportedBrowser.FIREFOX)
+  @SupportedBrowser(SupportedBrowser.SAFARI)
+  void overrideMimeType(String mime) native;
+
+  /**
+   * Send the request with any given `data`.
+   *
+   * Note: Most simple HTTP requests can be accomplished using the [getString],
+   * [request], [requestCrossOrigin], or [postFormData] methods. Use of this
+   * `send` method is intended only for more complex HTTP requests where
+   * finer-grained control is needed.
+   *
+   * ## Other resources
+   *
+   * * [XMLHttpRequest.send](https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest#send%28%29)
+   *   from MDN.
+   */
+  void send([body_OR_data]) native;
+
+  /**
+   * Sets the value of an HTTP request header.
+   *
+   * This method should be called after the request is opened, but before
+   * the request is sent.
+   *
+   * Multiple calls with the same header will combine all their values into a
+   * single header.
+   *
+   * ## Other resources
+   *
+   * * [XMLHttpRequest.setRequestHeader](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest#setRequestHeader())
+   *   from MDN.
+   * * [The setRequestHeader()
+   *   method](http://www.w3.org/TR/XMLHttpRequest/#the-setrequestheader()-method)
+   *   from W3C.
+   */
+  void setRequestHeader(String name, String value) native;
+
+  /// Stream of `readystatechange` events handled by this [HttpRequest].
+/**
+   * Event listeners to be notified every time the [HttpRequest]
+   * object's `readyState` changes values.
+   */
+  Stream<Event> get onReadyStateChange => readyStateChangeEvent.forTarget(this);
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("XMLHttpRequestEventTarget")
+class HttpRequestEventTarget extends EventTarget {
+  // To suppress missing implicit constructor warnings.
+  factory HttpRequestEventTarget._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  /**
+   * Static factory designed to expose `abort` events to event
+   * handlers that are not necessarily instances of [HttpRequestEventTarget].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<ProgressEvent> abortEvent =
+      const EventStreamProvider<ProgressEvent>('abort');
+
+  /**
+   * Static factory designed to expose `error` events to event
+   * handlers that are not necessarily instances of [HttpRequestEventTarget].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<ProgressEvent> errorEvent =
+      const EventStreamProvider<ProgressEvent>('error');
+
+  /**
+   * Static factory designed to expose `load` events to event
+   * handlers that are not necessarily instances of [HttpRequestEventTarget].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<ProgressEvent> loadEvent =
+      const EventStreamProvider<ProgressEvent>('load');
+
+  /**
+   * Static factory designed to expose `loadend` events to event
+   * handlers that are not necessarily instances of [HttpRequestEventTarget].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<ProgressEvent> loadEndEvent =
+      const EventStreamProvider<ProgressEvent>('loadend');
+
+  /**
+   * Static factory designed to expose `loadstart` events to event
+   * handlers that are not necessarily instances of [HttpRequestEventTarget].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<ProgressEvent> loadStartEvent =
+      const EventStreamProvider<ProgressEvent>('loadstart');
+
+  /**
+   * Static factory designed to expose `progress` events to event
+   * handlers that are not necessarily instances of [HttpRequestEventTarget].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<ProgressEvent> progressEvent =
+      const EventStreamProvider<ProgressEvent>('progress');
+
+  /**
+   * Static factory designed to expose `timeout` events to event
+   * handlers that are not necessarily instances of [HttpRequestEventTarget].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<ProgressEvent> timeoutEvent =
+      const EventStreamProvider<ProgressEvent>('timeout');
+
+  /// Stream of `abort` events handled by this [HttpRequestEventTarget].
+  Stream<ProgressEvent> get onAbort => abortEvent.forTarget(this);
+
+  /// Stream of `error` events handled by this [HttpRequestEventTarget].
+  Stream<ProgressEvent> get onError => errorEvent.forTarget(this);
+
+  /// Stream of `load` events handled by this [HttpRequestEventTarget].
+  Stream<ProgressEvent> get onLoad => loadEvent.forTarget(this);
+
+  /// Stream of `loadend` events handled by this [HttpRequestEventTarget].
+  @SupportedBrowser(SupportedBrowser.CHROME)
+  @SupportedBrowser(SupportedBrowser.FIREFOX)
+  @SupportedBrowser(SupportedBrowser.IE, '10')
+  @SupportedBrowser(SupportedBrowser.SAFARI)
+  Stream<ProgressEvent> get onLoadEnd => loadEndEvent.forTarget(this);
+
+  /// Stream of `loadstart` events handled by this [HttpRequestEventTarget].
+  Stream<ProgressEvent> get onLoadStart => loadStartEvent.forTarget(this);
+
+  /// Stream of `progress` events handled by this [HttpRequestEventTarget].
+  @SupportedBrowser(SupportedBrowser.CHROME)
+  @SupportedBrowser(SupportedBrowser.FIREFOX)
+  @SupportedBrowser(SupportedBrowser.IE, '10')
+  @SupportedBrowser(SupportedBrowser.SAFARI)
+  Stream<ProgressEvent> get onProgress => progressEvent.forTarget(this);
+
+  /// Stream of `timeout` events handled by this [HttpRequestEventTarget].
+  Stream<ProgressEvent> get onTimeout => timeoutEvent.forTarget(this);
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("XMLHttpRequestUpload")
+class HttpRequestUpload extends HttpRequestEventTarget {
+  // To suppress missing implicit constructor warnings.
+  factory HttpRequestUpload._() {
+    throw new UnsupportedError("Not supported");
+  }
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("HTMLIFrameElement")
+class IFrameElement extends HtmlElement {
+  // To suppress missing implicit constructor warnings.
+  factory IFrameElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory IFrameElement() => JS(
+      'returns:IFrameElement;creates:IFrameElement;new:true',
+      '#.createElement(#)',
+      document,
+      "iframe");
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  IFrameElement.created() : super.created();
+
+  String allow;
+
+  bool allowFullscreen;
+
+  bool allowPaymentRequest;
+
+  WindowBase get contentWindow =>
+      _convertNativeToDart_Window(this._get_contentWindow);
+  @JSName('contentWindow')
+  @Creates('Window|=Object')
+  @Returns('Window|=Object')
+  final dynamic _get_contentWindow;
+
+  String csp;
+
+  String height;
+
+  String name;
+
+  String referrerPolicy;
+
+  final DomTokenList sandbox;
+
+  String src;
+
+  String srcdoc;
+
+  String width;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("IdleDeadline")
+class IdleDeadline extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory IdleDeadline._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final bool didTimeout;
+
+  double timeRemaining() native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+typedef void IdleRequestCallback(IdleDeadline deadline);
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("ImageBitmap")
+class ImageBitmap extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory ImageBitmap._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final int height;
+
+  final int width;
+
+  void close() native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("ImageBitmapRenderingContext")
+class ImageBitmapRenderingContext extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory ImageBitmapRenderingContext._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final CanvasElement canvas;
+
+  void transferFromImageBitmap(ImageBitmap bitmap) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("ImageCapture")
+class ImageCapture extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory ImageCapture._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory ImageCapture(MediaStreamTrack track) {
+    return ImageCapture._create_1(track);
+  }
+  static ImageCapture _create_1(track) =>
+      JS('ImageCapture', 'new ImageCapture(#)', track);
+
+  final MediaStreamTrack track;
+
+  Future<PhotoCapabilities> getPhotoCapabilities() =>
+      promiseToFuture<PhotoCapabilities>(
+          JS("", "#.getPhotoCapabilities()", this));
+
+  Future<Map<String, dynamic>> getPhotoSettings() =>
+      promiseToFutureAsMap(JS("", "#.getPhotoSettings()", this));
+
+  Future<ImageBitmap> grabFrame() =>
+      promiseToFuture<ImageBitmap>(JS("", "#.grabFrame()", this));
+
+  Future setOptions(Map photoSettings) {
+    var photoSettings_dict = convertDartToNative_Dictionary(photoSettings);
+    return promiseToFuture(JS("", "#.setOptions(#)", this, photoSettings_dict));
+  }
+
+  Future<Blob> takePhoto([Map photoSettings]) {
+    var photoSettings_dict = null;
+    if (photoSettings != null) {
+      photoSettings_dict = convertDartToNative_Dictionary(photoSettings);
+    }
+    return promiseToFuture<Blob>(
+        JS("", "#.takePhoto(#)", this, photoSettings_dict));
+  }
+}
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("ImageData")
+class ImageData extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory ImageData._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory ImageData(data_OR_sw, int sh_OR_sw, [int sh]) {
+    if ((sh_OR_sw is int) && (data_OR_sw is int) && sh == null) {
+      return ImageData._create_1(data_OR_sw, sh_OR_sw);
+    }
+    if ((sh_OR_sw is int) && (data_OR_sw is Uint8ClampedList) && sh == null) {
+      return ImageData._create_2(data_OR_sw, sh_OR_sw);
+    }
+    if ((sh is int) && (sh_OR_sw is int) && (data_OR_sw is Uint8ClampedList)) {
+      return ImageData._create_3(data_OR_sw, sh_OR_sw, sh);
+    }
+    throw new ArgumentError("Incorrect number or type of arguments");
+  }
+  static ImageData _create_1(data_OR_sw, sh_OR_sw) =>
+      JS('ImageData', 'new ImageData(#,#)', data_OR_sw, sh_OR_sw);
+  static ImageData _create_2(data_OR_sw, sh_OR_sw) =>
+      JS('ImageData', 'new ImageData(#,#)', data_OR_sw, sh_OR_sw);
+  static ImageData _create_3(data_OR_sw, sh_OR_sw, sh) =>
+      JS('ImageData', 'new ImageData(#,#,#)', data_OR_sw, sh_OR_sw, sh);
+
+  @Creates('NativeUint8ClampedList')
+  @Returns('NativeUint8ClampedList')
+  final Uint8ClampedList data;
+
+  final int height;
+
+  final int width;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("HTMLImageElement")
+class ImageElement extends HtmlElement implements CanvasImageSource {
+  // To suppress missing implicit constructor warnings.
+  factory ImageElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory ImageElement({String src, int width, int height}) {
+    ImageElement e = JS('returns:ImageElement;creates:ImageElement;new:true',
+        '#.createElement(#)', document, "img");
+    if (src != null) e.src = src;
+    if (width != null) e.width = width;
+    if (height != null) e.height = height;
+    return e;
+  }
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  ImageElement.created() : super.created();
+
+  String alt;
+
+  String async;
+
+  final bool complete;
+
+  String crossOrigin;
+
+  final String currentSrc;
+
+  int height;
+
+  bool isMap;
+
+  final int naturalHeight;
+
+  final int naturalWidth;
+
+  String referrerPolicy;
+
+  String sizes;
+
+  String src;
+
+  String srcset;
+
+  String useMap;
+
+  int width;
+
+  Future decode() => promiseToFuture(JS("", "#.decode()", this));
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("InputDeviceCapabilities")
+class InputDeviceCapabilities extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory InputDeviceCapabilities._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory InputDeviceCapabilities([Map deviceInitDict]) {
+    if (deviceInitDict != null) {
+      var deviceInitDict_1 = convertDartToNative_Dictionary(deviceInitDict);
+      return InputDeviceCapabilities._create_1(deviceInitDict_1);
+    }
+    return InputDeviceCapabilities._create_2();
+  }
+  static InputDeviceCapabilities _create_1(deviceInitDict) => JS(
+      'InputDeviceCapabilities',
+      'new InputDeviceCapabilities(#)',
+      deviceInitDict);
+  static InputDeviceCapabilities _create_2() =>
+      JS('InputDeviceCapabilities', 'new InputDeviceCapabilities()');
+
+  final bool firesTouchEvents;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("HTMLInputElement")
+class InputElement extends HtmlElement
+    implements
+        HiddenInputElement,
+        SearchInputElement,
+        TextInputElement,
+        UrlInputElement,
+        TelephoneInputElement,
+        EmailInputElement,
+        PasswordInputElement,
+        DateInputElement,
+        MonthInputElement,
+        WeekInputElement,
+        TimeInputElement,
+        LocalDateTimeInputElement,
+        NumberInputElement,
+        RangeInputElement,
+        CheckboxInputElement,
+        RadioButtonInputElement,
+        FileUploadInputElement,
+        SubmitButtonInputElement,
+        ImageButtonInputElement,
+        ResetButtonInputElement,
+        ButtonInputElement {
+  factory InputElement({String type}) {
+    InputElement e = document.createElement("input");
+    if (type != null) {
+      try {
+        // IE throws an exception for unknown types.
+        e.type = type;
+      } catch (_) {}
+    }
+    return e;
+  }
+
+  // To suppress missing implicit constructor warnings.
+  factory InputElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  InputElement.created() : super.created();
+
+  String accept;
+
+  String alt;
+
+  String autocapitalize;
+
+  String autocomplete;
+
+  bool autofocus;
+
+  String capture;
+
+  bool checked;
+
+  bool defaultChecked;
+
+  String defaultValue;
+
+  String dirName;
+
+  bool disabled;
+
+  @Returns('FileList|Null')
+  @Creates('FileList')
+  List<File> files;
+
+  final FormElement form;
+
+  String formAction;
+
+  String formEnctype;
+
+  String formMethod;
+
+  bool formNoValidate;
+
+  String formTarget;
+
+  int height;
+
+  bool incremental;
+
+  bool indeterminate;
+
+  @Returns('NodeList|Null')
+  @Creates('NodeList')
+  final List<Node> labels;
+
+  final HtmlElement list;
+
+  String max;
+
+  int maxLength;
+
+  String min;
+
+  int minLength;
+
+  bool multiple;
+
+  String name;
+
+  String pattern;
+
+  String placeholder;
+
+  bool readOnly;
+
+  bool required;
+
+  String selectionDirection;
+
+  int selectionEnd;
+
+  int selectionStart;
+
+  int size;
+
+  String src;
+
+  String step;
+
+  String type;
+
+  final String validationMessage;
+
+  final ValidityState validity;
+
+  String value;
+
+  DateTime get valueAsDate =>
+      convertNativeToDart_DateTime(this._get_valueAsDate);
+  @JSName('valueAsDate')
+  @Creates('Null')
+  final dynamic _get_valueAsDate;
+
+  set valueAsDate(DateTime value) {
+    this._set_valueAsDate = convertDartToNative_DateTime(value);
+  }
+
+  set _set_valueAsDate(/*dynamic*/ value) {
+    JS("void", "#.valueAsDate = #", this, value);
+  }
+
+  num valueAsNumber;
+
+  @JSName('webkitEntries')
+  @SupportedBrowser(SupportedBrowser.CHROME)
+  @SupportedBrowser(SupportedBrowser.SAFARI)
+  final List<Entry> entries;
+
+  @JSName('webkitdirectory')
+  @SupportedBrowser(SupportedBrowser.CHROME)
+  @SupportedBrowser(SupportedBrowser.SAFARI)
+  bool directory;
+
+  int width;
+
+  final bool willValidate;
+
+  bool checkValidity() native;
+
+  bool reportValidity() native;
+
+  void select() native;
+
+  void setCustomValidity(String error) native;
+
+  void setRangeText(String replacement,
+      {int start, int end, String selectionMode}) native;
+
+  void setSelectionRange(int start, int end, [String direction]) native;
+
+  void stepDown([int n]) native;
+
+  void stepUp([int n]) native;
+}
+
+// Interfaces representing the InputElement APIs which are supported
+// for the various types of InputElement. From:
+// https://w3c.github.io/html/sec-forms.html#the-input-element.
+
+/**
+ * Exposes the functionality common between all InputElement types.
+ */
+abstract class InputElementBase implements Element {
+  bool autofocus;
+
+  bool disabled;
+
+  bool incremental;
+
+  bool indeterminate;
+
+  List<Node> get labels;
+
+  String name;
+
+  String get validationMessage;
+
+  ValidityState get validity;
+
+  String value;
+
+  bool get willValidate;
+
+  bool checkValidity();
+
+  void setCustomValidity(String error);
+}
+
+/**
+ * Hidden input which is not intended to be seen or edited by the user.
+ */
+abstract class HiddenInputElement implements InputElementBase {
+  factory HiddenInputElement() => new InputElement(type: 'hidden');
+}
+
+/**
+ * Base interface for all inputs which involve text editing.
+ */
+abstract class TextInputElementBase implements InputElementBase {
+  String autocomplete;
+
+  int maxLength;
+
+  String pattern;
+
+  String placeholder;
+
+  bool readOnly;
+
+  bool required;
+
+  int size;
+
+  void select();
+
+  String selectionDirection;
+
+  int selectionEnd;
+
+  int selectionStart;
+
+  void setSelectionRange(int start, int end, [String direction]);
+}
+
+/**
+ * Similar to [TextInputElement], but on platforms where search is styled
+ * differently this will get the search style.
+ *
+ * Use [supported] to check if this is supported on the current platform.
+ */
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.FIREFOX)
+@SupportedBrowser(SupportedBrowser.IE, '10')
+@SupportedBrowser(SupportedBrowser.SAFARI)
+abstract class SearchInputElement implements TextInputElementBase {
+  factory SearchInputElement() => new InputElement(type: 'search');
+
+  String dirName;
+
+  Element get list;
+
+  /// Returns true if this input type is supported on the current platform.
+  static bool get supported {
+    return (new InputElement(type: 'search')).type == 'search';
+  }
+}
+
+/**
+ * A basic text input editor control.
+ */
+abstract class TextInputElement implements TextInputElementBase {
+  factory TextInputElement() => new InputElement(type: 'text');
+
+  String dirName;
+
+  Element get list;
+}
+
+/**
+ * A control for editing an absolute URL.
+ *
+ * Use [supported] to check if this is supported on the current platform.
+ */
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.FIREFOX)
+@SupportedBrowser(SupportedBrowser.IE, '10')
+@SupportedBrowser(SupportedBrowser.SAFARI)
+abstract class UrlInputElement implements TextInputElementBase {
+  factory UrlInputElement() => new InputElement(type: 'url');
+
+  Element get list;
+
+  /// Returns true if this input type is supported on the current platform.
+  static bool get supported {
+    return (new InputElement(type: 'url')).type == 'url';
+  }
+}
+
+/**
+ * Represents a control for editing a telephone number.
+ *
+ * This provides a single line of text with minimal formatting help since
+ * there is a wide variety of telephone numbers.
+ *
+ * Use [supported] to check if this is supported on the current platform.
+ */
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.FIREFOX)
+@SupportedBrowser(SupportedBrowser.IE, '10')
+@SupportedBrowser(SupportedBrowser.SAFARI)
+abstract class TelephoneInputElement implements TextInputElementBase {
+  factory TelephoneInputElement() => new InputElement(type: 'tel');
+
+  Element get list;
+
+  /// Returns true if this input type is supported on the current platform.
+  static bool get supported {
+    return (new InputElement(type: 'tel')).type == 'tel';
+  }
+}
+
+/**
+ * An e-mail address or list of e-mail addresses.
+ *
+ * Use [supported] to check if this is supported on the current platform.
+ */
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.FIREFOX)
+@SupportedBrowser(SupportedBrowser.IE, '10')
+@SupportedBrowser(SupportedBrowser.SAFARI)
+abstract class EmailInputElement implements TextInputElementBase {
+  factory EmailInputElement() => new InputElement(type: 'email');
+
+  String autocomplete;
+
+  bool autofocus;
+
+  Element get list;
+
+  int maxLength;
+
+  bool multiple;
+
+  String pattern;
+
+  String placeholder;
+
+  bool readOnly;
+
+  bool required;
+
+  int size;
+
+  /// Returns true if this input type is supported on the current platform.
+  static bool get supported {
+    return (new InputElement(type: 'email')).type == 'email';
+  }
+}
+
+/**
+ * Text with no line breaks (sensitive information).
+ */
+abstract class PasswordInputElement implements TextInputElementBase {
+  factory PasswordInputElement() => new InputElement(type: 'password');
+}
+
+/**
+ * Base interface for all input element types which involve ranges.
+ */
+abstract class RangeInputElementBase implements InputElementBase {
+  Element get list;
+
+  String max;
+
+  String min;
+
+  String step;
+
+  num valueAsNumber;
+
+  void stepDown([int n]);
+
+  void stepUp([int n]);
+}
+
+/**
+ * A date (year, month, day) with no time zone.
+ *
+ * Use [supported] to check if this is supported on the current platform.
+ */
+@SupportedBrowser(SupportedBrowser.CHROME, '25')
+abstract class DateInputElement implements RangeInputElementBase {
+  factory DateInputElement() => new InputElement(type: 'date');
+
+  DateTime valueAsDate;
+
+  bool readOnly;
+
+  bool required;
+
+  /// Returns true if this input type is supported on the current platform.
+  static bool get supported {
+    return (new InputElement(type: 'date')).type == 'date';
+  }
+}
+
+/**
+ * A date consisting of a year and a month with no time zone.
+ *
+ * Use [supported] to check if this is supported on the current platform.
+ */
+@SupportedBrowser(SupportedBrowser.CHROME, '25')
+abstract class MonthInputElement implements RangeInputElementBase {
+  factory MonthInputElement() => new InputElement(type: 'month');
+
+  DateTime valueAsDate;
+
+  bool readOnly;
+
+  bool required;
+
+  /// Returns true if this input type is supported on the current platform.
+  static bool get supported {
+    return (new InputElement(type: 'month')).type == 'month';
+  }
+}
+
+/**
+ * A date consisting of a week-year number and a week number with no time zone.
+ *
+ * Use [supported] to check if this is supported on the current platform.
+ */
+@SupportedBrowser(SupportedBrowser.CHROME, '25')
+abstract class WeekInputElement implements RangeInputElementBase {
+  factory WeekInputElement() => new InputElement(type: 'week');
+
+  DateTime valueAsDate;
+
+  bool readOnly;
+
+  bool required;
+
+  /// Returns true if this input type is supported on the current platform.
+  static bool get supported {
+    return (new InputElement(type: 'week')).type == 'week';
+  }
+}
+
+/**
+ * A time (hour, minute, seconds, fractional seconds) with no time zone.
+ *
+ * Use [supported] to check if this is supported on the current platform.
+ */
+@SupportedBrowser(SupportedBrowser.CHROME)
+abstract class TimeInputElement implements RangeInputElementBase {
+  factory TimeInputElement() => new InputElement(type: 'time');
+
+  DateTime valueAsDate;
+
+  bool readOnly;
+
+  bool required;
+
+  /// Returns true if this input type is supported on the current platform.
+  static bool get supported {
+    return (new InputElement(type: 'time')).type == 'time';
+  }
+}
+
+/**
+ * A date and time (year, month, day, hour, minute, second, fraction of a
+ * second) with no time zone.
+ *
+ * Use [supported] to check if this is supported on the current platform.
+ */
+@SupportedBrowser(SupportedBrowser.CHROME, '25')
+abstract class LocalDateTimeInputElement implements RangeInputElementBase {
+  factory LocalDateTimeInputElement() =>
+      new InputElement(type: 'datetime-local');
+
+  bool readOnly;
+
+  bool required;
+
+  /// Returns true if this input type is supported on the current platform.
+  static bool get supported {
+    return (new InputElement(type: 'datetime-local')).type == 'datetime-local';
+  }
+}
+
+/**
+ * A numeric editor control.
+ */
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.IE)
+@SupportedBrowser(SupportedBrowser.SAFARI)
+abstract class NumberInputElement implements RangeInputElementBase {
+  factory NumberInputElement() => new InputElement(type: 'number');
+
+  String placeholder;
+
+  bool readOnly;
+
+  bool required;
+
+  /// Returns true if this input type is supported on the current platform.
+  static bool get supported {
+    return (new InputElement(type: 'number')).type == 'number';
+  }
+}
+
+/**
+ * Similar to [NumberInputElement] but the browser may provide more optimal
+ * styling (such as a slider control).
+ *
+ * Use [supported] to check if this is supported on the current platform.
+ */
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.IE, '10')
+abstract class RangeInputElement implements RangeInputElementBase {
+  factory RangeInputElement() => new InputElement(type: 'range');
+
+  /// Returns true if this input type is supported on the current platform.
+  static bool get supported {
+    return (new InputElement(type: 'range')).type == 'range';
+  }
+}
+
+/**
+ * A boolean editor control.
+ *
+ * Note that if [indeterminate] is set then this control is in a third
+ * indeterminate state.
+ */
+abstract class CheckboxInputElement implements InputElementBase {
+  factory CheckboxInputElement() => new InputElement(type: 'checkbox');
+
+  bool checked;
+
+  bool required;
+}
+
+/**
+ * A control that when used with other [ReadioButtonInputElement] controls
+ * forms a radio button group in which only one control can be checked at a
+ * time.
+ *
+ * Radio buttons are considered to be in the same radio button group if:
+ *
+ * * They are all of type 'radio'.
+ * * They all have either the same [FormElement] owner, or no owner.
+ * * Their name attributes contain the same name.
+ */
+abstract class RadioButtonInputElement implements InputElementBase {
+  factory RadioButtonInputElement() => new InputElement(type: 'radio');
+
+  bool checked;
+
+  bool required;
+}
+
+/**
+ * A control for picking files from the user's computer.
+ */
+abstract class FileUploadInputElement implements InputElementBase {
+  factory FileUploadInputElement() => new InputElement(type: 'file');
+
+  String accept;
+
+  bool multiple;
+
+  bool required;
+
+  List<File> files;
+}
+
+/**
+ * A button, which when clicked, submits the form.
+ */
+abstract class SubmitButtonInputElement implements InputElementBase {
+  factory SubmitButtonInputElement() => new InputElement(type: 'submit');
+
+  String formAction;
+
+  String formEnctype;
+
+  String formMethod;
+
+  bool formNoValidate;
+
+  String formTarget;
+}
+
+/**
+ * Either an image which the user can select a coordinate to or a form
+ * submit button.
+ */
+abstract class ImageButtonInputElement implements InputElementBase {
+  factory ImageButtonInputElement() => new InputElement(type: 'image');
+
+  String alt;
+
+  String formAction;
+
+  String formEnctype;
+
+  String formMethod;
+
+  bool formNoValidate;
+
+  String formTarget;
+
+  int height;
+
+  String src;
+
+  int width;
+}
+
+/**
+ * A button, which when clicked, resets the form.
+ */
+abstract class ResetButtonInputElement implements InputElementBase {
+  factory ResetButtonInputElement() => new InputElement(type: 'reset');
+}
+
+/**
+ * A button, with no default behavior.
+ */
+abstract class ButtonInputElement implements InputElementBase {
+  factory ButtonInputElement() => new InputElement(type: 'button');
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("InstallEvent")
+class InstallEvent extends ExtendableEvent {
+  // To suppress missing implicit constructor warnings.
+  factory InstallEvent._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory InstallEvent(String type, [Map eventInitDict]) {
+    if (eventInitDict != null) {
+      var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+      return InstallEvent._create_1(type, eventInitDict_1);
+    }
+    return InstallEvent._create_2(type);
+  }
+  static InstallEvent _create_1(type, eventInitDict) =>
+      JS('InstallEvent', 'new InstallEvent(#,#)', type, eventInitDict);
+  static InstallEvent _create_2(type) =>
+      JS('InstallEvent', 'new InstallEvent(#)', type);
+
+  void registerForeignFetch(Map options) {
+    var options_1 = convertDartToNative_Dictionary(options);
+    _registerForeignFetch_1(options_1);
+    return;
+  }
+
+  @JSName('registerForeignFetch')
+  void _registerForeignFetch_1(options) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("IntersectionObserver")
+class IntersectionObserver extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory IntersectionObserver._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory IntersectionObserver(IntersectionObserverCallback callback,
+      [Map options]) {
+    if (options != null) {
+      var callback_1 = convertDartClosureToJS(callback, 2);
+      var options_2 = convertDartToNative_Dictionary(options);
+      return IntersectionObserver._create_1(callback_1, options_2);
+    }
+    var callback_1 = convertDartClosureToJS(callback, 2);
+    return IntersectionObserver._create_2(callback_1);
+  }
+  static IntersectionObserver _create_1(callback, options) => JS(
+      'IntersectionObserver',
+      'new IntersectionObserver(#,#)',
+      callback,
+      options);
+  static IntersectionObserver _create_2(callback) =>
+      JS('IntersectionObserver', 'new IntersectionObserver(#)', callback);
+
+  final Element root;
+
+  final String rootMargin;
+
+  final List<num> thresholds;
+
+  void disconnect() native;
+
+  void observe(Element target) native;
+
+  List<IntersectionObserverEntry> takeRecords() native;
+
+  void unobserve(Element target) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+typedef void IntersectionObserverCallback(
+    List entries, IntersectionObserver observer);
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("IntersectionObserverEntry")
+class IntersectionObserverEntry extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory IntersectionObserverEntry._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final DomRectReadOnly boundingClientRect;
+
+  final num intersectionRatio;
+
+  final DomRectReadOnly intersectionRect;
+
+  final bool isIntersecting;
+
+  final DomRectReadOnly rootBounds;
+
+  final Element target;
+
+  final num time;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("InterventionReport")
+class InterventionReport extends ReportBody {
+  // To suppress missing implicit constructor warnings.
+  factory InterventionReport._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final int lineNumber;
+
+  final String message;
+
+  final String sourceFile;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/**
+ * An event that describes user interaction with the keyboard.
+ *
+ * The [type] of the event identifies what kind of interaction occurred.
+ *
+ * See also:
+ *
+ * * [KeyboardEvent](https://developer.mozilla.org/en/DOM/KeyboardEvent) at MDN.
+ */
+@Native("KeyboardEvent")
+class KeyboardEvent extends UIEvent {
+  /**
+   * Programmatically create a KeyboardEvent.
+   *
+   * Due to browser differences, keyCode, charCode, or keyIdentifier values
+   * cannot be specified in this base level constructor. This constructor
+   * enables the user to programmatically create and dispatch a [KeyboardEvent],
+   * but it will not contain any particular key content. For programmatically
+   * creating keyboard events with specific key value contents, see the custom
+   * Event [KeyEvent].
+   */
+  factory KeyboardEvent(String type,
+      {Window view,
+      bool canBubble: true,
+      bool cancelable: true,
+      int location,
+      int keyLocation, // Legacy alias for location
+      bool ctrlKey: false,
+      bool altKey: false,
+      bool shiftKey: false,
+      bool metaKey: false}) {
+    if (view == null) {
+      view = window;
+    }
+    location ??= keyLocation ?? 1;
+    KeyboardEvent e = document._createEvent("KeyboardEvent");
+    e._initKeyboardEvent(type, canBubble, cancelable, view, "", location,
+        ctrlKey, altKey, shiftKey, metaKey);
+    return e;
+  }
+
+  void _initKeyboardEvent(
+      String type,
+      bool canBubble,
+      bool cancelable,
+      Window view,
+      String keyIdentifier,
+      int location,
+      bool ctrlKey,
+      bool altKey,
+      bool shiftKey,
+      bool metaKey) {
+    if (JS('bool', 'typeof(#.initKeyEvent) == "function"', this)) {
+      // initKeyEvent is only in Firefox (instead of initKeyboardEvent). It has
+      // a slightly different signature, and allows you to specify keyCode and
+      // charCode as the last two arguments, but we just set them as the default
+      // since they can't be specified in other browsers.
+      JS('void', '#.initKeyEvent(#, #, #, #, #, #, #, #, 0, 0)', this, type,
+          canBubble, cancelable, view, ctrlKey, altKey, shiftKey, metaKey);
+    } else {
+      // initKeyboardEvent is for all other browsers.
+      JS(
+          'void',
+          '#.initKeyboardEvent(#, #, #, #, #, #, #, #, #, #)',
+          this,
+          type,
+          canBubble,
+          cancelable,
+          view,
+          keyIdentifier,
+          location,
+          ctrlKey,
+          altKey,
+          shiftKey,
+          metaKey);
+    }
+  }
+
+  final int keyCode;
+
+  final int charCode;
+
+  int get which => _which;
+
+  factory KeyboardEvent._(String type, [Map eventInitDict]) {
+    if (eventInitDict != null) {
+      var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+      return KeyboardEvent._create_1(type, eventInitDict_1);
+    }
+    return KeyboardEvent._create_2(type);
+  }
+  static KeyboardEvent _create_1(type, eventInitDict) =>
+      JS('KeyboardEvent', 'new KeyboardEvent(#,#)', type, eventInitDict);
+  static KeyboardEvent _create_2(type) =>
+      JS('KeyboardEvent', 'new KeyboardEvent(#)', type);
+
+  static const int DOM_KEY_LOCATION_LEFT = 0x01;
+
+  static const int DOM_KEY_LOCATION_NUMPAD = 0x03;
+
+  static const int DOM_KEY_LOCATION_RIGHT = 0x02;
+
+  static const int DOM_KEY_LOCATION_STANDARD = 0x00;
+
+  final bool altKey;
+
+  @JSName('charCode')
+  final int _charCode;
+
+  final String code;
+
+  final bool ctrlKey;
+
+  final bool isComposing;
+
+  final String key;
+
+  @JSName('keyCode')
+  final int _keyCode;
+
+  final int location;
+
+  final bool metaKey;
+
+  final bool repeat;
+
+  final bool shiftKey;
+
+  bool getModifierState(String keyArg) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("KeyframeEffect")
+class KeyframeEffect extends KeyframeEffectReadOnly {
+  // To suppress missing implicit constructor warnings.
+  factory KeyframeEffect._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory KeyframeEffect(Element target, Object effect, [Object options]) {
+    if (options != null) {
+      return KeyframeEffect._create_1(target, effect, options);
+    }
+    return KeyframeEffect._create_2(target, effect);
+  }
+  static KeyframeEffect _create_1(target, effect, options) => JS(
+      'KeyframeEffect', 'new KeyframeEffect(#,#,#)', target, effect, options);
+  static KeyframeEffect _create_2(target, effect) =>
+      JS('KeyframeEffect', 'new KeyframeEffect(#,#)', target, effect);
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("KeyframeEffectReadOnly")
+class KeyframeEffectReadOnly extends AnimationEffectReadOnly {
+  // To suppress missing implicit constructor warnings.
+  factory KeyframeEffectReadOnly._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory KeyframeEffectReadOnly(Element target, Object effect,
+      [Object options]) {
+    if (options != null) {
+      return KeyframeEffectReadOnly._create_1(target, effect, options);
+    }
+    return KeyframeEffectReadOnly._create_2(target, effect);
+  }
+  static KeyframeEffectReadOnly _create_1(target, effect, options) => JS(
+      'KeyframeEffectReadOnly',
+      'new KeyframeEffectReadOnly(#,#,#)',
+      target,
+      effect,
+      options);
+  static KeyframeEffectReadOnly _create_2(target, effect) => JS(
+      'KeyframeEffectReadOnly',
+      'new KeyframeEffectReadOnly(#,#)',
+      target,
+      effect);
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("HTMLLIElement")
+class LIElement extends HtmlElement {
+  // To suppress missing implicit constructor warnings.
+  factory LIElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory LIElement() => JS('returns:LIElement;creates:LIElement;new:true',
+      '#.createElement(#)', document, "li");
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  LIElement.created() : super.created();
+
+  int value;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("HTMLLabelElement")
+class LabelElement extends HtmlElement {
+  // To suppress missing implicit constructor warnings.
+  factory LabelElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory LabelElement() => JS(
+      'returns:LabelElement;creates:LabelElement;new:true',
+      '#.createElement(#)',
+      document,
+      "label");
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  LabelElement.created() : super.created();
+
+  final HtmlElement control;
+
+  final FormElement form;
+
+  String htmlFor;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("HTMLLegendElement")
+class LegendElement extends HtmlElement {
+  // To suppress missing implicit constructor warnings.
+  factory LegendElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory LegendElement() => JS(
+      'returns:LegendElement;creates:LegendElement;new:true',
+      '#.createElement(#)',
+      document,
+      "legend");
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  LegendElement.created() : super.created();
+
+  final FormElement form;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("LinearAccelerationSensor")
+class LinearAccelerationSensor extends Accelerometer {
+  // To suppress missing implicit constructor warnings.
+  factory LinearAccelerationSensor._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory LinearAccelerationSensor([Map sensorOptions]) {
+    if (sensorOptions != null) {
+      var sensorOptions_1 = convertDartToNative_Dictionary(sensorOptions);
+      return LinearAccelerationSensor._create_1(sensorOptions_1);
+    }
+    return LinearAccelerationSensor._create_2();
+  }
+  static LinearAccelerationSensor _create_1(sensorOptions) => JS(
+      'LinearAccelerationSensor',
+      'new LinearAccelerationSensor(#)',
+      sensorOptions);
+  static LinearAccelerationSensor _create_2() =>
+      JS('LinearAccelerationSensor', 'new LinearAccelerationSensor()');
+}
+// Copyright (c) 2014, 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.
+
+@Native("HTMLLinkElement")
+class LinkElement extends HtmlElement {
+  // To suppress missing implicit constructor warnings.
+  factory LinkElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory LinkElement() => JS(
+      'returns:LinkElement;creates:LinkElement;new:true',
+      '#.createElement(#)',
+      document,
+      "link");
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  LinkElement.created() : super.created();
+
+  String as;
+
+  String crossOrigin;
+
+  bool disabled;
+
+  String href;
+
+  String hreflang;
+
+  final Document import;
+
+  String integrity;
+
+  String media;
+
+  String referrerPolicy;
+
+  String rel;
+
+  final DomTokenList relList;
+
+  String scope;
+
+  final StyleSheet sheet;
+
+  final DomTokenList sizes;
+
+  String type;
+
+  /// Checks if HTML imports are supported on the current platform.
+  bool get supportsImport {
+    return JS('bool', '("import" in #)', this);
+  }
+}
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("Location")
+class Location extends Interceptor implements LocationBase {
+  // To suppress missing implicit constructor warnings.
+  factory Location._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  @Returns('DomStringList|Null')
+  @Creates('DomStringList')
+  final List<String> ancestorOrigins;
+
+  String hash;
+
+  String host;
+
+  String hostname;
+
+  String href;
+
+  String pathname;
+
+  String port;
+
+  String protocol;
+
+  String search;
+
+  TrustedUrl trustedHref;
+
+  void assign([String url]) native;
+
+  void reload() native;
+
+  void replace(String url) native;
+
+  String get origin {
+    if (JS('bool', '("origin" in #)', this)) {
+      return JS('String', '#.origin', this);
+    }
+    return '${this.protocol}//${this.host}';
+  }
+
+  String toString() => JS('String', 'String(#)', this);
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("Magnetometer")
+class Magnetometer extends Sensor {
+  // To suppress missing implicit constructor warnings.
+  factory Magnetometer._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory Magnetometer([Map sensorOptions]) {
+    if (sensorOptions != null) {
+      var sensorOptions_1 = convertDartToNative_Dictionary(sensorOptions);
+      return Magnetometer._create_1(sensorOptions_1);
+    }
+    return Magnetometer._create_2();
+  }
+  static Magnetometer _create_1(sensorOptions) =>
+      JS('Magnetometer', 'new Magnetometer(#)', sensorOptions);
+  static Magnetometer _create_2() => JS('Magnetometer', 'new Magnetometer()');
+
+  final num x;
+
+  final num y;
+
+  final num z;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("HTMLMapElement")
+class MapElement extends HtmlElement {
+  // To suppress missing implicit constructor warnings.
+  factory MapElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory MapElement() => JS('returns:MapElement;creates:MapElement;new:true',
+      '#.createElement(#)', document, "map");
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  MapElement.created() : super.created();
+
+  @Returns('HtmlCollection|Null')
+  @Creates('HtmlCollection')
+  final List<Node> areas;
+
+  String name;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("MediaCapabilities")
+class MediaCapabilities extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory MediaCapabilities._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  Future<MediaCapabilitiesInfo> decodingInfo(Map configuration) {
+    var configuration_dict = convertDartToNative_Dictionary(configuration);
+    return promiseToFuture<MediaCapabilitiesInfo>(
+        JS("", "#.decodingInfo(#)", this, configuration_dict));
+  }
+
+  Future<MediaCapabilitiesInfo> encodingInfo(Map configuration) {
+    var configuration_dict = convertDartToNative_Dictionary(configuration);
+    return promiseToFuture<MediaCapabilitiesInfo>(
+        JS("", "#.encodingInfo(#)", this, configuration_dict));
+  }
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("MediaCapabilitiesInfo")
+class MediaCapabilitiesInfo extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory MediaCapabilitiesInfo._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final bool powerEfficient;
+
+  final bool smooth;
+
+  final bool supported;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("MediaDeviceInfo")
+class MediaDeviceInfo extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory MediaDeviceInfo._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final String deviceId;
+
+  final String groupId;
+
+  final String kind;
+
+  final String label;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("MediaDevices")
+class MediaDevices extends EventTarget {
+  // To suppress missing implicit constructor warnings.
+  factory MediaDevices._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  Future<List<MediaDeviceInfo>> enumerateDevices() =>
+      promiseToFuture<List<MediaDeviceInfo>>(
+          JS("", "#.enumerateDevices()", this));
+
+  Map getSupportedConstraints() {
+    return convertNativeToDart_Dictionary(_getSupportedConstraints_1());
+  }
+
+  @JSName('getSupportedConstraints')
+  _getSupportedConstraints_1() native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("HTMLMediaElement")
+class MediaElement extends HtmlElement {
+  // To suppress missing implicit constructor warnings.
+  factory MediaElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  MediaElement.created() : super.created();
+
+  static const int HAVE_CURRENT_DATA = 2;
+
+  static const int HAVE_ENOUGH_DATA = 4;
+
+  static const int HAVE_FUTURE_DATA = 3;
+
+  static const int HAVE_METADATA = 1;
+
+  static const int HAVE_NOTHING = 0;
+
+  static const int NETWORK_EMPTY = 0;
+
+  static const int NETWORK_IDLE = 1;
+
+  static const int NETWORK_LOADING = 2;
+
+  static const int NETWORK_NO_SOURCE = 3;
+
+  final AudioTrackList audioTracks;
+
+  bool autoplay;
+
+  final TimeRanges buffered;
+
+  bool controls;
+
+  final DomTokenList controlsList;
+
+  String crossOrigin;
+
+  final String currentSrc;
+
+  num currentTime;
+
+  bool defaultMuted;
+
+  num defaultPlaybackRate;
+
+  bool disableRemotePlayback;
+
+  final num duration;
+
+  final bool ended;
+
+  final MediaError error;
+
+  bool loop;
+
+  final MediaKeys mediaKeys;
+
+  bool muted;
+
+  final int networkState;
+
+  final bool paused;
+
+  num playbackRate;
+
+  final TimeRanges played;
+
+  String preload;
+
+  final int readyState;
+
+  final RemotePlayback remote;
+
+  final TimeRanges seekable;
+
+  final bool seeking;
+
+  final String sinkId;
+
+  String src;
+
+  MediaStream srcObject;
+
+  final TextTrackList textTracks;
+
+  final VideoTrackList videoTracks;
+
+  num volume;
+
+  @JSName('webkitAudioDecodedByteCount')
+  @SupportedBrowser(SupportedBrowser.CHROME)
+  @SupportedBrowser(SupportedBrowser.SAFARI)
+  final int audioDecodedByteCount;
+
+  @JSName('webkitVideoDecodedByteCount')
+  @SupportedBrowser(SupportedBrowser.CHROME)
+  @SupportedBrowser(SupportedBrowser.SAFARI)
+  final int videoDecodedByteCount;
+
+  TextTrack addTextTrack(String kind, [String label, String language]) native;
+
+  @Unstable()
+  String canPlayType(String type, [String keySystem]) native;
+
+  MediaStream captureStream() native;
+
+  void load() native;
+
+  void pause() native;
+
+  Future play() => promiseToFuture(JS("", "#.play()", this));
+
+  Future setMediaKeys(MediaKeys mediaKeys) =>
+      promiseToFuture(JS("", "#.setMediaKeys(#)", this, mediaKeys));
+
+  Future setSinkId(String sinkId) =>
+      promiseToFuture(JS("", "#.setSinkId(#)", this, sinkId));
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("MediaEncryptedEvent")
+class MediaEncryptedEvent extends Event {
+  // To suppress missing implicit constructor warnings.
+  factory MediaEncryptedEvent._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory MediaEncryptedEvent(String type, [Map eventInitDict]) {
+    if (eventInitDict != null) {
+      var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+      return MediaEncryptedEvent._create_1(type, eventInitDict_1);
+    }
+    return MediaEncryptedEvent._create_2(type);
+  }
+  static MediaEncryptedEvent _create_1(type, eventInitDict) => JS(
+      'MediaEncryptedEvent',
+      'new MediaEncryptedEvent(#,#)',
+      type,
+      eventInitDict);
+  static MediaEncryptedEvent _create_2(type) =>
+      JS('MediaEncryptedEvent', 'new MediaEncryptedEvent(#)', type);
+
+  final ByteBuffer initData;
+
+  final String initDataType;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("MediaError")
+class MediaError extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory MediaError._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  static const int MEDIA_ERR_ABORTED = 1;
+
+  static const int MEDIA_ERR_DECODE = 3;
+
+  static const int MEDIA_ERR_NETWORK = 2;
+
+  static const int MEDIA_ERR_SRC_NOT_SUPPORTED = 4;
+
+  final int code;
+
+  final String message;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("MediaKeyMessageEvent")
+class MediaKeyMessageEvent extends Event {
+  // To suppress missing implicit constructor warnings.
+  factory MediaKeyMessageEvent._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory MediaKeyMessageEvent(String type, Map eventInitDict) {
+    var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+    return MediaKeyMessageEvent._create_1(type, eventInitDict_1);
+  }
+  static MediaKeyMessageEvent _create_1(type, eventInitDict) => JS(
+      'MediaKeyMessageEvent',
+      'new MediaKeyMessageEvent(#,#)',
+      type,
+      eventInitDict);
+
+  final ByteBuffer message;
+
+  final String messageType;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("MediaKeySession")
+class MediaKeySession extends EventTarget {
+  // To suppress missing implicit constructor warnings.
+  factory MediaKeySession._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  static const EventStreamProvider<MessageEvent> messageEvent =
+      const EventStreamProvider<MessageEvent>('message');
+
+  Future<void> get closed => promiseToFuture<void>(JS("", "#.closed", this));
+
+  final num expiration;
+
+  final MediaKeyStatusMap keyStatuses;
+
+  final String sessionId;
+
+  Future close() => promiseToFuture(JS("", "#.close()", this));
+
+  Future generateRequest(String initDataType, /*BufferSource*/ initData) =>
+      promiseToFuture(
+          JS("", "#.generateRequest(#, #)", this, initDataType, initData));
+
+  Future load(String sessionId) =>
+      promiseToFuture(JS("", "#.load(#)", this, sessionId));
+
+  Future remove() => promiseToFuture(JS("", "#.remove()", this));
+
+  @JSName('update')
+  Future _update(/*BufferSource*/ response) native;
+
+  Stream<MessageEvent> get onMessage => messageEvent.forTarget(this);
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("MediaKeyStatusMap")
+class MediaKeyStatusMap extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory MediaKeyStatusMap._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final int size;
+
+  Object get(/*BufferSource*/ keyId) native;
+
+  bool has(/*BufferSource*/ keyId) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("MediaKeySystemAccess")
+class MediaKeySystemAccess extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory MediaKeySystemAccess._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final String keySystem;
+
+  Future createMediaKeys() =>
+      promiseToFuture(JS("", "#.createMediaKeys()", this));
+
+  Map getConfiguration() {
+    return convertNativeToDart_Dictionary(_getConfiguration_1());
+  }
+
+  @JSName('getConfiguration')
+  _getConfiguration_1() native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("MediaKeys")
+class MediaKeys extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory MediaKeys._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  @JSName('createSession')
+  MediaKeySession _createSession([String sessionType]) native;
+
+  Future getStatusForPolicy(MediaKeysPolicy policy) =>
+      promiseToFuture(JS("", "#.getStatusForPolicy(#)", this, policy));
+
+  Future setServerCertificate(/*BufferSource*/ serverCertificate) =>
+      promiseToFuture(
+          JS("", "#.setServerCertificate(#)", this, serverCertificate));
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("MediaKeysPolicy")
+class MediaKeysPolicy extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory MediaKeysPolicy._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory MediaKeysPolicy(Map init) {
+    var init_1 = convertDartToNative_Dictionary(init);
+    return MediaKeysPolicy._create_1(init_1);
+  }
+  static MediaKeysPolicy _create_1(init) =>
+      JS('MediaKeysPolicy', 'new MediaKeysPolicy(#)', init);
+
+  final String minHdcpVersion;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("MediaList")
+class MediaList extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory MediaList._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final int length;
+
+  String mediaText;
+
+  void appendMedium(String medium) native;
+
+  void deleteMedium(String medium) native;
+
+  String item(int index) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("MediaMetadata")
+class MediaMetadata extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory MediaMetadata._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory MediaMetadata([Map metadata]) {
+    if (metadata != null) {
+      var metadata_1 = convertDartToNative_Dictionary(metadata);
+      return MediaMetadata._create_1(metadata_1);
+    }
+    return MediaMetadata._create_2();
+  }
+  static MediaMetadata _create_1(metadata) =>
+      JS('MediaMetadata', 'new MediaMetadata(#)', metadata);
+  static MediaMetadata _create_2() =>
+      JS('MediaMetadata', 'new MediaMetadata()');
+
+  String album;
+
+  String artist;
+
+  List artwork;
+
+  String title;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("MediaQueryList")
+class MediaQueryList extends EventTarget {
+  // To suppress missing implicit constructor warnings.
+  factory MediaQueryList._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  static const EventStreamProvider<Event> changeEvent =
+      const EventStreamProvider<Event>('change');
+
+  final bool matches;
+
+  final String media;
+
+  void addListener(EventListener listener) native;
+
+  void removeListener(EventListener listener) native;
+
+  Stream<Event> get onChange => changeEvent.forTarget(this);
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("MediaQueryListEvent")
+class MediaQueryListEvent extends Event {
+  // To suppress missing implicit constructor warnings.
+  factory MediaQueryListEvent._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory MediaQueryListEvent(String type, [Map eventInitDict]) {
+    if (eventInitDict != null) {
+      var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+      return MediaQueryListEvent._create_1(type, eventInitDict_1);
+    }
+    return MediaQueryListEvent._create_2(type);
+  }
+  static MediaQueryListEvent _create_1(type, eventInitDict) => JS(
+      'MediaQueryListEvent',
+      'new MediaQueryListEvent(#,#)',
+      type,
+      eventInitDict);
+  static MediaQueryListEvent _create_2(type) =>
+      JS('MediaQueryListEvent', 'new MediaQueryListEvent(#)', type);
+
+  final bool matches;
+
+  final String media;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("MediaRecorder")
+class MediaRecorder extends EventTarget {
+  // To suppress missing implicit constructor warnings.
+  factory MediaRecorder._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  static const EventStreamProvider<Event> errorEvent =
+      const EventStreamProvider<Event>('error');
+
+  static const EventStreamProvider<Event> pauseEvent =
+      const EventStreamProvider<Event>('pause');
+
+  factory MediaRecorder(MediaStream stream, [Map options]) {
+    if (options != null) {
+      var options_1 = convertDartToNative_Dictionary(options);
+      return MediaRecorder._create_1(stream, options_1);
+    }
+    return MediaRecorder._create_2(stream);
+  }
+  static MediaRecorder _create_1(stream, options) =>
+      JS('MediaRecorder', 'new MediaRecorder(#,#)', stream, options);
+  static MediaRecorder _create_2(stream) =>
+      JS('MediaRecorder', 'new MediaRecorder(#)', stream);
+
+  final int audioBitsPerSecond;
+
+  final String mimeType;
+
+  final String state;
+
+  final MediaStream stream;
+
+  final int videoBitsPerSecond;
+
+  static bool isTypeSupported(String type) native;
+
+  void pause() native;
+
+  void requestData() native;
+
+  void resume() native;
+
+  void start([int timeslice]) native;
+
+  void stop() native;
+
+  Stream<Event> get onError => errorEvent.forTarget(this);
+
+  Stream<Event> get onPause => pauseEvent.forTarget(this);
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("MediaSession")
+class MediaSession extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory MediaSession._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  MediaMetadata metadata;
+
+  String playbackState;
+
+  void setActionHandler(String action, MediaSessionActionHandler handler)
+      native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+typedef void MediaSessionActionHandler();
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("MediaSettingsRange")
+class MediaSettingsRange extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory MediaSettingsRange._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final num max;
+
+  final num min;
+
+  final num step;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.IE, '11')
+@Native("MediaSource")
+class MediaSource extends EventTarget {
+  // To suppress missing implicit constructor warnings.
+  factory MediaSource._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory MediaSource() {
+    return MediaSource._create_1();
+  }
+  static MediaSource _create_1() => JS('MediaSource', 'new MediaSource()');
+
+  /// Checks if this type is supported on the current platform.
+  static bool get supported => JS('bool', '!!(window.MediaSource)');
+
+  final SourceBufferList activeSourceBuffers;
+
+  num duration;
+
+  final String readyState;
+
+  final SourceBufferList sourceBuffers;
+
+  SourceBuffer addSourceBuffer(String type) native;
+
+  void clearLiveSeekableRange() native;
+
+  void endOfStream([String error]) native;
+
+  static bool isTypeSupported(String type) native;
+
+  void removeSourceBuffer(SourceBuffer buffer) native;
+
+  void setLiveSeekableRange(num start, num end) native;
+}
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@Native("MediaStream")
+class MediaStream extends EventTarget {
+  // To suppress missing implicit constructor warnings.
+  factory MediaStream._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  /**
+   * Static factory designed to expose `addtrack` events to event
+   * handlers that are not necessarily instances of [MediaStream].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<Event> addTrackEvent =
+      const EventStreamProvider<Event>('addtrack');
+
+  /**
+   * Static factory designed to expose `removetrack` events to event
+   * handlers that are not necessarily instances of [MediaStream].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<Event> removeTrackEvent =
+      const EventStreamProvider<Event>('removetrack');
+
+  factory MediaStream([stream_OR_tracks]) {
+    if (stream_OR_tracks == null) {
+      return MediaStream._create_1();
+    }
+    if ((stream_OR_tracks is MediaStream)) {
+      return MediaStream._create_2(stream_OR_tracks);
+    }
+    if ((stream_OR_tracks is List<MediaStreamTrack>)) {
+      return MediaStream._create_3(stream_OR_tracks);
+    }
+    throw new ArgumentError("Incorrect number or type of arguments");
+  }
+  static MediaStream _create_1() => JS('MediaStream', 'new MediaStream()');
+  static MediaStream _create_2(stream_OR_tracks) =>
+      JS('MediaStream', 'new MediaStream(#)', stream_OR_tracks);
+  static MediaStream _create_3(stream_OR_tracks) =>
+      JS('MediaStream', 'new MediaStream(#)', stream_OR_tracks);
+
+  final bool active;
+
+  final String id;
+
+  void addTrack(MediaStreamTrack track) native;
+
+  MediaStream clone() native;
+
+  @Creates('JSExtendableArray|MediaStreamTrack')
+  @Returns('JSExtendableArray')
+  List<MediaStreamTrack> getAudioTracks() native;
+
+  MediaStreamTrack getTrackById(String trackId) native;
+
+  List<MediaStreamTrack> getTracks() native;
+
+  @Creates('JSExtendableArray|MediaStreamTrack')
+  @Returns('JSExtendableArray')
+  List<MediaStreamTrack> getVideoTracks() native;
+
+  void removeTrack(MediaStreamTrack track) native;
+
+  /// Stream of `addtrack` events handled by this [MediaStream].
+  Stream<Event> get onAddTrack => addTrackEvent.forTarget(this);
+
+  /// Stream of `removetrack` events handled by this [MediaStream].
+  Stream<Event> get onRemoveTrack => removeTrackEvent.forTarget(this);
+
+  /**
+   * Checks if the MediaStream APIs are supported on the current platform.
+   *
+   * See also:
+   *
+   * * [Navigator.getUserMedia]
+   */
+  static bool get supported => JS(
+      'bool',
+      '''!!(#.getUserMedia || #.webkitGetUserMedia ||
+        #.mozGetUserMedia || #.msGetUserMedia)''',
+      window.navigator,
+      window.navigator,
+      window.navigator,
+      window.navigator);
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@Native("MediaStreamEvent")
+class MediaStreamEvent extends Event {
+  // To suppress missing implicit constructor warnings.
+  factory MediaStreamEvent._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory MediaStreamEvent(String type, [Map eventInitDict]) {
+    if (eventInitDict != null) {
+      var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+      return MediaStreamEvent._create_1(type, eventInitDict_1);
+    }
+    return MediaStreamEvent._create_2(type);
+  }
+  static MediaStreamEvent _create_1(type, eventInitDict) =>
+      JS('MediaStreamEvent', 'new MediaStreamEvent(#,#)', type, eventInitDict);
+  static MediaStreamEvent _create_2(type) =>
+      JS('MediaStreamEvent', 'new MediaStreamEvent(#)', type);
+
+  /// Checks if this type is supported on the current platform.
+  static bool get supported => Device.isEventTypeSupported('MediaStreamEvent');
+
+  final MediaStream stream;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@Native("MediaStreamTrack")
+class MediaStreamTrack extends EventTarget {
+  // To suppress missing implicit constructor warnings.
+  factory MediaStreamTrack._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  /**
+   * Static factory designed to expose `ended` events to event
+   * handlers that are not necessarily instances of [MediaStreamTrack].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<Event> endedEvent =
+      const EventStreamProvider<Event>('ended');
+
+  /**
+   * Static factory designed to expose `mute` events to event
+   * handlers that are not necessarily instances of [MediaStreamTrack].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<Event> muteEvent =
+      const EventStreamProvider<Event>('mute');
+
+  /**
+   * Static factory designed to expose `unmute` events to event
+   * handlers that are not necessarily instances of [MediaStreamTrack].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<Event> unmuteEvent =
+      const EventStreamProvider<Event>('unmute');
+
+  String contentHint;
+
+  bool enabled;
+
+  final String id;
+
+  final String kind;
+
+  final String label;
+
+  final bool muted;
+
+  final String readyState;
+
+  Future applyConstraints([Map constraints]) {
+    var constraints_dict = null;
+    if (constraints != null) {
+      constraints_dict = convertDartToNative_Dictionary(constraints);
+    }
+    return promiseToFuture(
+        JS("", "#.applyConstraints(#)", this, constraints_dict));
+  }
+
+  MediaStreamTrack clone() native;
+
+  Map getCapabilities() {
+    return convertNativeToDart_Dictionary(_getCapabilities_1());
+  }
+
+  @JSName('getCapabilities')
+  _getCapabilities_1() native;
+
+  Map getConstraints() {
+    return convertNativeToDart_Dictionary(_getConstraints_1());
+  }
+
+  @JSName('getConstraints')
+  _getConstraints_1() native;
+
+  Map getSettings() {
+    return convertNativeToDart_Dictionary(_getSettings_1());
+  }
+
+  @JSName('getSettings')
+  _getSettings_1() native;
+
+  void stop() native;
+
+  /// Stream of `ended` events handled by this [MediaStreamTrack].
+  Stream<Event> get onEnded => endedEvent.forTarget(this);
+
+  /// Stream of `mute` events handled by this [MediaStreamTrack].
+  Stream<Event> get onMute => muteEvent.forTarget(this);
+
+  /// Stream of `unmute` events handled by this [MediaStreamTrack].
+  Stream<Event> get onUnmute => unmuteEvent.forTarget(this);
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@Native("MediaStreamTrackEvent")
+class MediaStreamTrackEvent extends Event {
+  // To suppress missing implicit constructor warnings.
+  factory MediaStreamTrackEvent._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory MediaStreamTrackEvent(String type, Map eventInitDict) {
+    var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+    return MediaStreamTrackEvent._create_1(type, eventInitDict_1);
+  }
+  static MediaStreamTrackEvent _create_1(type, eventInitDict) => JS(
+      'MediaStreamTrackEvent',
+      'new MediaStreamTrackEvent(#,#)',
+      type,
+      eventInitDict);
+
+  /// Checks if this type is supported on the current platform.
+  static bool get supported =>
+      Device.isEventTypeSupported('MediaStreamTrackEvent');
+
+  final MediaStreamTrack track;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("MemoryInfo")
+class MemoryInfo extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory MemoryInfo._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final int jsHeapSizeLimit;
+
+  final int totalJSHeapSize;
+
+  final int usedJSHeapSize;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/**
+ * An HTML <menu> element.
+ *
+ * A <menu> element represents an unordered list of menu commands.
+ *
+ * See also:
+ *
+ *  * [Menu Element](https://developer.mozilla.org/en-US/docs/HTML/Element/menu) from MDN.
+ *  * [Menu Element](http://www.w3.org/TR/html5/the-menu-element.html#the-menu-element) from the W3C.
+ */
+@Native("HTMLMenuElement")
+class MenuElement extends HtmlElement {
+  // To suppress missing implicit constructor warnings.
+  factory MenuElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory MenuElement() => JS(
+      'returns:MenuElement;creates:MenuElement;new:true',
+      '#.createElement(#)',
+      document,
+      "menu");
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  MenuElement.created() : super.created();
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+typedef void MessageCallback(Map message);
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("MessageChannel")
+class MessageChannel extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory MessageChannel._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory MessageChannel() {
+    return MessageChannel._create_1();
+  }
+  static MessageChannel _create_1() =>
+      JS('MessageChannel', 'new MessageChannel()');
+
+  final MessagePort port1;
+
+  final MessagePort port2;
+}
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+@Native("MessageEvent")
+class MessageEvent extends Event {
+  factory MessageEvent(String type,
+      {bool canBubble: false,
+      bool cancelable: false,
+      Object data,
+      String origin,
+      String lastEventId,
+      Window source,
+      List<MessagePort> messagePorts: const []}) {
+    if (source == null) {
+      source = window;
+    }
+    if (!Device.isIE) {
+      // TODO: This if check should be removed once IE
+      // implements the constructor.
+      return JS(
+          'MessageEvent',
+          'new MessageEvent(#, {bubbles: #, cancelable: #, data: #, origin: #, lastEventId: #, source: #, ports: #})',
+          type,
+          canBubble,
+          cancelable,
+          data,
+          origin,
+          lastEventId,
+          source,
+          messagePorts);
+    }
+    MessageEvent event = document._createEvent("MessageEvent");
+    event._initMessageEvent(type, canBubble, cancelable, data, origin,
+        lastEventId, source, messagePorts);
+    return event;
+  }
+
+  // TODO(alanknight): This really should be generated by the
+  // _OutputConversion in the systemnative.py script, but that doesn't
+  // use those conversions right now, so do this as a one-off.
+  dynamic get data => convertNativeToDart_SerializedScriptValue(this._get_data);
+
+  @JSName('data')
+  @annotation_Creates_SerializedScriptValue
+  @annotation_Returns_SerializedScriptValue
+  final dynamic _get_data;
+
+  factory MessageEvent._(String type, [Map eventInitDict]) {
+    if (eventInitDict != null) {
+      var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+      return MessageEvent._create_1(type, eventInitDict_1);
+    }
+    return MessageEvent._create_2(type);
+  }
+  static MessageEvent _create_1(type, eventInitDict) =>
+      JS('MessageEvent', 'new MessageEvent(#,#)', type, eventInitDict);
+  static MessageEvent _create_2(type) =>
+      JS('MessageEvent', 'new MessageEvent(#)', type);
+
+  @Unstable()
+  final String lastEventId;
+
+  final String origin;
+
+  @Unstable()
+  @Creates('JSExtendableArray')
+  final List<MessagePort> ports;
+
+  EventTarget get source => _convertNativeToDart_EventTarget(this._get_source);
+  @JSName('source')
+  @Creates('Null')
+  @Returns('EventTarget|=Object')
+  final dynamic _get_source;
+
+  final String suborigin;
+
+  void _initMessageEvent(
+      String typeArg,
+      bool canBubbleArg,
+      bool cancelableArg,
+      Object dataArg,
+      String originArg,
+      String lastEventIdArg,
+      EventTarget sourceArg,
+      List<MessagePort> portsArg) {
+    var sourceArg_1 = _convertDartToNative_EventTarget(sourceArg);
+    _initMessageEvent_1(typeArg, canBubbleArg, cancelableArg, dataArg,
+        originArg, lastEventIdArg, sourceArg_1, portsArg);
+    return;
+  }
+
+  @JSName('initMessageEvent')
+  void _initMessageEvent_1(typeArg, canBubbleArg, cancelableArg, dataArg,
+      originArg, lastEventIdArg, sourceArg, List<MessagePort> portsArg) native;
+}
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+@Unstable()
+@Native("MessagePort")
+class MessagePort extends EventTarget {
+  void addEventListener(String type, EventListener listener,
+      [bool useCapture]) {
+    // Messages posted to ports are initially paused, allowing listeners to be
+    // setup, start() needs to be explicitly invoked to begin handling messages.
+    if (type == 'message') {
+      _start();
+    }
+
+    super.addEventListener(type, listener, useCapture);
+  }
+
+  // To suppress missing implicit constructor warnings.
+  factory MessagePort._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  /**
+   * Static factory designed to expose `message` events to event
+   * handlers that are not necessarily instances of [MessagePort].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<MessageEvent> messageEvent =
+      const EventStreamProvider<MessageEvent>('message');
+
+  void close() native;
+
+  void postMessage(/*any*/ message, [List<Object> transfer]) {
+    if (transfer != null) {
+      var message_1 = convertDartToNative_SerializedScriptValue(message);
+      _postMessage_1(message_1, transfer);
+      return;
+    }
+    var message_1 = convertDartToNative_SerializedScriptValue(message);
+    _postMessage_2(message_1);
+    return;
+  }
+
+  @JSName('postMessage')
+  void _postMessage_1(message, List<Object> transfer) native;
+  @JSName('postMessage')
+  void _postMessage_2(message) native;
+
+  @JSName('start')
+  void _start() native;
+
+  /// Stream of `message` events handled by this [MessagePort].
+  Stream<MessageEvent> get onMessage => messageEvent.forTarget(this);
+}
+
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("HTMLMetaElement")
+class MetaElement extends HtmlElement {
+  // To suppress missing implicit constructor warnings.
+  factory MetaElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory MetaElement() => JS(
+      'returns:MetaElement;creates:MetaElement;new:true',
+      '#.createElement(#)',
+      document,
+      "meta");
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  MetaElement.created() : super.created();
+
+  String content;
+
+  String httpEquiv;
+
+  String name;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("Metadata")
+class Metadata extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory Metadata._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  DateTime get modificationTime =>
+      convertNativeToDart_DateTime(this._get_modificationTime);
+  @JSName('modificationTime')
+  @Creates('Null')
+  final dynamic _get_modificationTime;
+
+  final int size;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+typedef void MetadataCallback(Metadata metadata);
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.FIREFOX)
+@SupportedBrowser(SupportedBrowser.SAFARI)
+@Unstable()
+@Native("HTMLMeterElement")
+class MeterElement extends HtmlElement {
+  // To suppress missing implicit constructor warnings.
+  factory MeterElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory MeterElement() => document.createElement("meter");
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  MeterElement.created() : super.created();
+
+  /// Checks if this type is supported on the current platform.
+  static bool get supported => Element.isTagSupported('meter');
+
+  num high;
+
+  @Unstable()
+  @Returns('NodeList|Null')
+  @Creates('NodeList')
+  final List<Node> labels;
+
+  num low;
+
+  num max;
+
+  num min;
+
+  num optimum;
+
+  num value;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("MIDIAccess")
+class MidiAccess extends EventTarget {
+  // To suppress missing implicit constructor warnings.
+  factory MidiAccess._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final MidiInputMap inputs;
+
+  final MidiOutputMap outputs;
+
+  final bool sysexEnabled;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("MIDIConnectionEvent")
+class MidiConnectionEvent extends Event {
+  // To suppress missing implicit constructor warnings.
+  factory MidiConnectionEvent._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory MidiConnectionEvent(String type, [Map eventInitDict]) {
+    if (eventInitDict != null) {
+      var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+      return MidiConnectionEvent._create_1(type, eventInitDict_1);
+    }
+    return MidiConnectionEvent._create_2(type);
+  }
+  static MidiConnectionEvent _create_1(type, eventInitDict) => JS(
+      'MidiConnectionEvent',
+      'new MIDIConnectionEvent(#,#)',
+      type,
+      eventInitDict);
+  static MidiConnectionEvent _create_2(type) =>
+      JS('MidiConnectionEvent', 'new MIDIConnectionEvent(#)', type);
+
+  final MidiPort port;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("MIDIInput")
+class MidiInput extends MidiPort {
+  // To suppress missing implicit constructor warnings.
+  factory MidiInput._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  /**
+   * Static factory designed to expose `midimessage` events to event
+   * handlers that are not necessarily instances of [MidiInput].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<MidiMessageEvent> midiMessageEvent =
+      const EventStreamProvider<MidiMessageEvent>('midimessage');
+
+  /// Stream of `midimessage` events handled by this [MidiInput].
+  Stream<MidiMessageEvent> get onMidiMessage =>
+      midiMessageEvent.forTarget(this);
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("MIDIInputMap")
+class MidiInputMap extends Interceptor with MapMixin<String, dynamic> {
+  // To suppress missing implicit constructor warnings.
+  factory MidiInputMap._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  Map _getItem(String key) =>
+      convertNativeToDart_Dictionary(JS('', '#.get(#)', this, key));
+
+  void addAll(Map<String, dynamic> other) {
+    throw new UnsupportedError("Not supported");
+  }
+
+  bool containsValue(dynamic value) => values.any((e) => e == value);
+
+  bool containsKey(dynamic key) => _getItem(key) != null;
+
+  Map operator [](dynamic key) => _getItem(key);
+
+  void forEach(void f(String key, dynamic value)) {
+    var entries = JS('', '#.entries()', this);
+    while (true) {
+      var entry = JS('', '#.next()', entries);
+      if (JS('bool', '#.done', entry)) return;
+      f(JS('String', '#.value[0]', entry),
+          convertNativeToDart_Dictionary(JS('', '#.value[1]', entry)));
+    }
+  }
+
+  Iterable<String> get keys {
+    final keys = <String>[];
+    forEach((k, v) => keys.add(k));
+    return keys;
+  }
+
+  Iterable<Map> get values {
+    final values = <Map>[];
+    forEach((k, v) => values.add(v));
+    return values;
+  }
+
+  int get length => JS('int', '#.size', this);
+
+  bool get isEmpty => length == 0;
+
+  bool get isNotEmpty => !isEmpty;
+
+  void operator []=(String key, dynamic value) {
+    throw new UnsupportedError("Not supported");
+  }
+
+  dynamic putIfAbsent(String key, dynamic ifAbsent()) {
+    throw new UnsupportedError("Not supported");
+  }
+
+  String remove(dynamic key) {
+    throw new UnsupportedError("Not supported");
+  }
+
+  void clear() {
+    throw new UnsupportedError("Not supported");
+  }
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("MIDIMessageEvent")
+class MidiMessageEvent extends Event {
+  // To suppress missing implicit constructor warnings.
+  factory MidiMessageEvent._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory MidiMessageEvent(String type, [Map eventInitDict]) {
+    if (eventInitDict != null) {
+      var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+      return MidiMessageEvent._create_1(type, eventInitDict_1);
+    }
+    return MidiMessageEvent._create_2(type);
+  }
+  static MidiMessageEvent _create_1(type, eventInitDict) =>
+      JS('MidiMessageEvent', 'new MIDIMessageEvent(#,#)', type, eventInitDict);
+  static MidiMessageEvent _create_2(type) =>
+      JS('MidiMessageEvent', 'new MIDIMessageEvent(#)', type);
+
+  final Uint8List data;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("MIDIOutput")
+class MidiOutput extends MidiPort {
+  // To suppress missing implicit constructor warnings.
+  factory MidiOutput._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  void send(Uint8List data, [num timestamp]) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("MIDIOutputMap")
+class MidiOutputMap extends Interceptor with MapMixin<String, dynamic> {
+  // To suppress missing implicit constructor warnings.
+  factory MidiOutputMap._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  Map _getItem(String key) =>
+      convertNativeToDart_Dictionary(JS('', '#.get(#)', this, key));
+
+  void addAll(Map<String, dynamic> other) {
+    throw new UnsupportedError("Not supported");
+  }
+
+  bool containsValue(dynamic value) => values.any((e) => e == value);
+
+  bool containsKey(dynamic key) => _getItem(key) != null;
+
+  Map operator [](dynamic key) => _getItem(key);
+
+  void forEach(void f(String key, dynamic value)) {
+    var entries = JS('', '#.entries()', this);
+    while (true) {
+      var entry = JS('', '#.next()', entries);
+      if (JS('bool', '#.done', entry)) return;
+      f(JS('String', '#.value[0]', entry),
+          convertNativeToDart_Dictionary(JS('', '#.value[1]', entry)));
+    }
+  }
+
+  Iterable<String> get keys {
+    final keys = <String>[];
+    forEach((k, v) => keys.add(k));
+    return keys;
+  }
+
+  Iterable<Map> get values {
+    final values = <Map>[];
+    forEach((k, v) => values.add(v));
+    return values;
+  }
+
+  int get length => JS('int', '#.size', this);
+
+  bool get isEmpty => length == 0;
+
+  bool get isNotEmpty => !isEmpty;
+
+  void operator []=(String key, dynamic value) {
+    throw new UnsupportedError("Not supported");
+  }
+
+  dynamic putIfAbsent(String key, dynamic ifAbsent()) {
+    throw new UnsupportedError("Not supported");
+  }
+
+  String remove(dynamic key) {
+    throw new UnsupportedError("Not supported");
+  }
+
+  void clear() {
+    throw new UnsupportedError("Not supported");
+  }
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("MIDIPort")
+class MidiPort extends EventTarget {
+  // To suppress missing implicit constructor warnings.
+  factory MidiPort._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final String connection;
+
+  final String id;
+
+  final String manufacturer;
+
+  final String name;
+
+  final String state;
+
+  final String type;
+
+  final String version;
+
+  Future close() => promiseToFuture(JS("", "#.close()", this));
+
+  Future open() => promiseToFuture(JS("", "#.open()", this));
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("MimeType")
+class MimeType extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory MimeType._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final String description;
+
+  final Plugin enabledPlugin;
+
+  final String suffixes;
+
+  final String type;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("MimeTypeArray")
+class MimeTypeArray extends Interceptor
+    with ListMixin<MimeType>, ImmutableListMixin<MimeType>
+    implements List<MimeType>, JavaScriptIndexingBehavior<MimeType> {
+  // To suppress missing implicit constructor warnings.
+  factory MimeTypeArray._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  int get length => JS("int", "#.length", this);
+
+  MimeType operator [](int index) {
+    if (JS("bool", "# >>> 0 !== # || # >= #", index, index, index, length))
+      throw new RangeError.index(index, this);
+    return JS("MimeType", "#[#]", this, index);
+  }
+
+  void operator []=(int index, MimeType value) {
+    throw new UnsupportedError("Cannot assign element of immutable List.");
+  }
+  // -- start List<MimeType> mixins.
+  // MimeType is the element type.
+
+  set length(int value) {
+    throw new UnsupportedError("Cannot resize immutable List.");
+  }
+
+  MimeType get first {
+    if (this.length > 0) {
+      return JS('MimeType', '#[0]', this);
+    }
+    throw new StateError("No elements");
+  }
+
+  MimeType get last {
+    int len = this.length;
+    if (len > 0) {
+      return JS('MimeType', '#[#]', this, len - 1);
+    }
+    throw new StateError("No elements");
+  }
+
+  MimeType get single {
+    int len = this.length;
+    if (len == 1) {
+      return JS('MimeType', '#[0]', this);
+    }
+    if (len == 0) throw new StateError("No elements");
+    throw new StateError("More than one element");
+  }
+
+  MimeType elementAt(int index) => this[index];
+  // -- end List<MimeType> mixins.
+
+  MimeType item(int index) native;
+
+  MimeType namedItem(String name) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("HTMLModElement")
+class ModElement extends HtmlElement {
+  // To suppress missing implicit constructor warnings.
+  factory ModElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  ModElement.created() : super.created();
+
+  String cite;
+
+  String dateTime;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+typedef void MojoWatchCallback(int result);
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("MouseEvent,DragEvent")
+class MouseEvent extends UIEvent {
+  factory MouseEvent(String type,
+      {Window view,
+      int detail: 0,
+      int screenX: 0,
+      int screenY: 0,
+      int clientX: 0,
+      int clientY: 0,
+      int button: 0,
+      bool canBubble: true,
+      bool cancelable: true,
+      bool ctrlKey: false,
+      bool altKey: false,
+      bool shiftKey: false,
+      bool metaKey: false,
+      EventTarget relatedTarget}) {
+    if (view == null) {
+      view = window;
+    }
+    MouseEvent event = document._createEvent('MouseEvent');
+    event._initMouseEvent(
+        type,
+        canBubble,
+        cancelable,
+        view,
+        detail,
+        screenX,
+        screenY,
+        clientX,
+        clientY,
+        ctrlKey,
+        altKey,
+        shiftKey,
+        metaKey,
+        button,
+        relatedTarget);
+    return event;
+  }
+
+  factory MouseEvent._(String type, [Map eventInitDict]) {
+    if (eventInitDict != null) {
+      var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+      return MouseEvent._create_1(type, eventInitDict_1);
+    }
+    return MouseEvent._create_2(type);
+  }
+  static MouseEvent _create_1(type, eventInitDict) =>
+      JS('MouseEvent', 'new MouseEvent(#,#)', type, eventInitDict);
+  static MouseEvent _create_2(type) =>
+      JS('MouseEvent', 'new MouseEvent(#)', type);
+
+  final bool altKey;
+
+  final int button;
+
+  final int buttons;
+
+  @JSName('clientX')
+  final num _clientX;
+
+  @JSName('clientY')
+  final num _clientY;
+
+  final bool ctrlKey;
+
+  /**
+   * The nonstandard way to access the element that the mouse comes
+   * from in the case of a `mouseover` event.
+   *
+   * This member is deprecated and not cross-browser compatible; use
+   * relatedTarget to get the same information in the standard way.
+   */
+  @deprecated
+  final Node fromElement;
+
+  @JSName('layerX')
+  final int _layerX;
+
+  @JSName('layerY')
+  final int _layerY;
+
+  final bool metaKey;
+
+  @JSName('movementX')
+  final int _movementX;
+
+  @JSName('movementY')
+  final int _movementY;
+
+  @JSName('pageX')
+  final num _pageX;
+
+  @JSName('pageY')
+  final num _pageY;
+
+  final String region;
+
+  EventTarget get relatedTarget =>
+      _convertNativeToDart_EventTarget(this._get_relatedTarget);
+  @JSName('relatedTarget')
+  @Creates('Node')
+  @Returns('EventTarget|=Object|Null')
+  final dynamic _get_relatedTarget;
+
+  @JSName('screenX')
+  final num _screenX;
+
+  @JSName('screenY')
+  final num _screenY;
+
+  final bool shiftKey;
+
+  /**
+   * The nonstandard way to access the element that the mouse goes
+   * to in the case of a `mouseout` event.
+   *
+   * This member is deprecated and not cross-browser compatible; use
+   * relatedTarget to get the same information in the standard way.
+   */
+  @deprecated
+  final Node toElement;
+
+  bool getModifierState(String keyArg) native;
+
+  void _initMouseEvent(
+      String type,
+      bool bubbles,
+      bool cancelable,
+      Window view,
+      int detail,
+      int screenX,
+      int screenY,
+      int clientX,
+      int clientY,
+      bool ctrlKey,
+      bool altKey,
+      bool shiftKey,
+      bool metaKey,
+      int button,
+      EventTarget relatedTarget) {
+    var relatedTarget_1 = _convertDartToNative_EventTarget(relatedTarget);
+    _initMouseEvent_1(
+        type,
+        bubbles,
+        cancelable,
+        view,
+        detail,
+        screenX,
+        screenY,
+        clientX,
+        clientY,
+        ctrlKey,
+        altKey,
+        shiftKey,
+        metaKey,
+        button,
+        relatedTarget_1);
+    return;
+  }
+
+  @JSName('initMouseEvent')
+  void _initMouseEvent_1(
+      type,
+      bubbles,
+      cancelable,
+      Window view,
+      detail,
+      screenX,
+      screenY,
+      clientX,
+      clientY,
+      ctrlKey,
+      altKey,
+      shiftKey,
+      metaKey,
+      button,
+      relatedTarget) native;
+
+  Point get client => new Point(_clientX, _clientY);
+
+  @SupportedBrowser(SupportedBrowser.CHROME)
+  @SupportedBrowser(SupportedBrowser.FIREFOX)
+  Point get movement => new Point(_movementX, _movementY);
+
+  /**
+   * The coordinates of the mouse pointer in target node coordinates.
+   *
+   * This value may vary between platforms if the target node moves
+   * after the event has fired or if the element has CSS transforms affecting
+   * it.
+   */
+  Point get offset {
+    if (JS('bool', '!!#.offsetX', this)) {
+      var x = JS('int', '#.offsetX', this);
+      var y = JS('int', '#.offsetY', this);
+      return new Point(x, y);
+    } else {
+      // Firefox does not support offsetX.
+      if (!(this.target is Element)) {
+        throw new UnsupportedError('offsetX is only supported on elements');
+      }
+      Element target = this.target;
+      var point = (this.client - target.getBoundingClientRect().topLeft);
+      return new Point(point.x.toInt(), point.y.toInt());
+    }
+  }
+
+  Point get screen => new Point(_screenX, _screenY);
+
+  Point get layer => new Point(_layerX, _layerY);
+
+  Point get page => new Point(_pageX, _pageY);
+
+  DataTransfer get dataTransfer =>
+      JS('DataTransfer', "#['dataTransfer']", this);
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+typedef void MutationCallback(List mutations, MutationObserver observer);
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// http://www.w3.org/TR/DOM-Level-3-Events/#events-mutationevents
+@deprecated
+@Native("MutationEvent")
+class MutationEvent extends Event {
+  // To suppress missing implicit constructor warnings.
+  factory MutationEvent._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  static const int ADDITION = 2;
+
+  static const int MODIFICATION = 1;
+
+  static const int REMOVAL = 3;
+
+  final int attrChange;
+
+  final String attrName;
+
+  final String newValue;
+
+  final String prevValue;
+
+  final Node relatedNode;
+
+  void initMutationEvent(
+      String type,
+      bool bubbles,
+      bool cancelable,
+      Node relatedNode,
+      String prevValue,
+      String newValue,
+      String attrName,
+      int attrChange) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.FIREFOX)
+@SupportedBrowser(SupportedBrowser.SAFARI)
+@Native("MutationObserver,WebKitMutationObserver")
+class MutationObserver extends Interceptor {
+  void disconnect() native;
+
+  void _observe(Node target, [Map options]) {
+    if (options != null) {
+      var options_1 = convertDartToNative_Dictionary(options);
+      _observe_1(target, options_1);
+      return;
+    }
+    _observe_2(target);
+    return;
+  }
+
+  @JSName('observe')
+  void _observe_1(Node target, options) native;
+  @JSName('observe')
+  void _observe_2(Node target) native;
+
+  List<MutationRecord> takeRecords() native;
+
+  /**
+   * Checks to see if the mutation observer API is supported on the current
+   * platform.
+   */
+  static bool get supported {
+    return JS(
+        'bool', '!!(window.MutationObserver || window.WebKitMutationObserver)');
+  }
+
+  /**
+   * Observes the target for the specified changes.
+   *
+   * Some requirements for the optional parameters:
+   *
+   * * Either childList, attributes or characterData must be true.
+   * * If attributeOldValue is true then attributes must also be true.
+   * * If attributeFilter is specified then attributes must be true.
+   * * If characterDataOldValue is true then characterData must be true.
+   */
+  void observe(Node target,
+      {bool childList,
+      bool attributes,
+      bool characterData,
+      bool subtree,
+      bool attributeOldValue,
+      bool characterDataOldValue,
+      List<String> attributeFilter}) {
+    // Parse options into map of known type.
+    var parsedOptions = _createDict();
+
+    // Override options passed in the map with named optional arguments.
+    override(key, value) {
+      if (value != null) _add(parsedOptions, key, value);
+    }
+
+    override('childList', childList);
+    override('attributes', attributes);
+    override('characterData', characterData);
+    override('subtree', subtree);
+    override('attributeOldValue', attributeOldValue);
+    override('characterDataOldValue', characterDataOldValue);
+    if (attributeFilter != null) {
+      override('attributeFilter', _fixupList(attributeFilter));
+    }
+
+    _call(target, parsedOptions);
+  }
+
+  // TODO: Change to a set when const Sets are available.
+  static final _boolKeys = const {
+    'childList': true,
+    'attributes': true,
+    'characterData': true,
+    'subtree': true,
+    'attributeOldValue': true,
+    'characterDataOldValue': true
+  };
+
+  static _createDict() => JS('var', '{}');
+  static _add(m, String key, value) {
+    JS('void', '#[#] = #', m, key, value);
+  }
+
+  static _fixupList(list) => list; // TODO: Ensure is a JavaScript Array.
+
+  // Call native function with no conversions.
+  @JSName('observe')
+  void _call(target, options) native;
+
+  factory MutationObserver(MutationCallback callback) {
+    // Dummy statement to mark types as instantiated.
+    JS('MutationObserver|MutationRecord', '0');
+
+    return JS(
+        'MutationObserver',
+        'new(window.MutationObserver||window.WebKitMutationObserver||'
+            'window.MozMutationObserver)(#)',
+        convertDartClosureToJS(_wrapBinaryZone(callback), 2));
+  }
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("MutationRecord")
+class MutationRecord extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory MutationRecord._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  @Returns('NodeList|Null')
+  @Creates('NodeList')
+  final List<Node> addedNodes;
+
+  final String attributeName;
+
+  final String attributeNamespace;
+
+  final Node nextSibling;
+
+  final String oldValue;
+
+  final Node previousSibling;
+
+  @Returns('NodeList|Null')
+  @Creates('NodeList')
+  final List<Node> removedNodes;
+
+  final Node target;
+
+  final String type;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("NavigationPreloadManager")
+class NavigationPreloadManager extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory NavigationPreloadManager._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  Future disable() => promiseToFuture(JS("", "#.disable()", this));
+
+  Future enable() => promiseToFuture(JS("", "#.enable()", this));
+
+  Future<Map<String, dynamic>> getState() =>
+      promiseToFutureAsMap(JS("", "#.getState()", this));
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("Navigator")
+class Navigator extends NavigatorConcurrentHardware
+    implements
+        NavigatorCookies,
+        NavigatorLanguage,
+        NavigatorOnLine,
+        NavigatorAutomationInformation,
+        NavigatorID {
+  List<Gamepad> getGamepads() {
+    var gamepadList = _getGamepads();
+
+    // If no prototype we need one for the world to hookup to the proper Dart class.
+    var jsProto = JS('', '#.prototype', gamepadList);
+    if (jsProto == null) {
+      JS('', '#.prototype = Object.create(null)', gamepadList);
+    }
+
+    applyExtension('GamepadList', gamepadList);
+    return gamepadList;
+  }
+
+  String get language =>
+      JS('String', '#.language || #.userLanguage', this, this);
+
+  /**
+   * Gets a stream (video and or audio) from the local computer.
+   *
+   * Use [MediaStream.supported] to check if this is supported by the current
+   * platform. The arguments `audio` and `video` default to `false` (stream does
+   * not use audio or video, respectively).
+   *
+   * Simple example usage:
+   *
+   *     window.navigator.getUserMedia(audio: true, video: true).then((stream) {
+   *       var video = new VideoElement()
+   *         ..autoplay = true
+   *         ..src = Url.createObjectUrlFromStream(stream);
+   *       document.body.append(video);
+   *     });
+   *
+   * The user can also pass in Maps to the audio or video parameters to specify
+   * mandatory and optional constraints for the media stream. Not passing in a
+   * map, but passing in `true` will provide a MediaStream with audio or
+   * video capabilities, but without any additional constraints. The particular
+   * constraint names for audio and video are still in flux, but as of this
+   * writing, here is an example providing more constraints.
+   *
+   *     window.navigator.getUserMedia(
+   *         audio: true,
+   *         video: {'mandatory':
+   *                    { 'minAspectRatio': 1.333, 'maxAspectRatio': 1.334 },
+   *                 'optional':
+   *                    [{ 'minFrameRate': 60 },
+   *                     { 'maxWidth': 640 }]
+   *     });
+   *
+   * See also:
+   * * [MediaStream.supported]
+   */
+  @SupportedBrowser(SupportedBrowser.CHROME)
+  Future<MediaStream> getUserMedia({audio: false, video: false}) {
+    var completer = new Completer<MediaStream>();
+    var options = {'audio': audio, 'video': video};
+    _ensureGetUserMedia();
+    this._getUserMedia(convertDartToNative_SerializedScriptValue(options),
+        (stream) {
+      completer.complete(stream);
+    }, (error) {
+      completer.completeError(error);
+    });
+    return completer.future;
+  }
+
+  _ensureGetUserMedia() {
+    if (JS('bool', '!(#.getUserMedia)', this)) {
+      JS(
+          'void',
+          '#.getUserMedia = '
+              '(#.getUserMedia || #.webkitGetUserMedia || #.mozGetUserMedia ||'
+              '#.msGetUserMedia)',
+          this,
+          this,
+          this,
+          this,
+          this);
+    }
+  }
+
+  @JSName('getUserMedia')
+  void _getUserMedia(options, _NavigatorUserMediaSuccessCallback success,
+      _NavigatorUserMediaErrorCallback error) native;
+
+  // To suppress missing implicit constructor warnings.
+  factory Navigator._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final _BudgetService budget;
+
+  final _Clipboard clipboard;
+
+  final NetworkInformation connection;
+
+  final CredentialsContainer credentials;
+
+  final num deviceMemory;
+
+  final String doNotTrack;
+
+  @Unstable()
+  final Geolocation geolocation;
+
+  final int maxTouchPoints;
+
+  final MediaCapabilities mediaCapabilities;
+
+  final MediaDevices mediaDevices;
+
+  final MediaSession mediaSession;
+
+  final MimeTypeArray mimeTypes;
+
+  final _NFC nfc;
+
+  final Permissions permissions;
+
+  final Presentation presentation;
+
+  @Unstable()
+  final String productSub;
+
+  final ServiceWorkerContainer serviceWorker;
+
+  final StorageManager storage;
+
+  @Unstable()
+  final String vendor;
+
+  @Unstable()
+  final String vendorSub;
+
+  final VR vr;
+
+  @JSName('webkitPersistentStorage')
+  @SupportedBrowser(SupportedBrowser.CHROME)
+  @SupportedBrowser(SupportedBrowser.SAFARI)
+  final DeprecatedStorageQuota persistentStorage;
+
+  @JSName('webkitTemporaryStorage')
+  @SupportedBrowser(SupportedBrowser.CHROME)
+  @SupportedBrowser(SupportedBrowser.SAFARI)
+  final DeprecatedStorageQuota temporaryStorage;
+
+  void cancelKeyboardLock() native;
+
+  Future getBattery() => promiseToFuture(JS("", "#.getBattery()", this));
+
+  @JSName('getGamepads')
+  @Returns('_GamepadList|Null')
+  @Creates('_GamepadList')
+  List<Gamepad> _getGamepads() native;
+
+  Future<RelatedApplication> getInstalledRelatedApps() =>
+      promiseToFuture<RelatedApplication>(
+          JS("", "#.getInstalledRelatedApps()", this));
+
+  Future getVRDisplays() => promiseToFuture(JS("", "#.getVRDisplays()", this));
+
+  @Unstable()
+  void registerProtocolHandler(String scheme, String url, String title) native;
+
+  Future requestKeyboardLock([List<String> keyCodes]) {
+    if (keyCodes != null) {
+      List keyCodes_1 = convertDartToNative_StringArray(keyCodes);
+      return _requestKeyboardLock_1(keyCodes_1);
+    }
+    return _requestKeyboardLock_2();
+  }
+
+  @JSName('requestKeyboardLock')
+  Future _requestKeyboardLock_1(List keyCodes) =>
+      promiseToFuture(JS("", "#.requestKeyboardLock(#)", this, keyCodes));
+  @JSName('requestKeyboardLock')
+  Future _requestKeyboardLock_2() =>
+      promiseToFuture(JS("", "#.requestKeyboardLock()", this));
+
+  @JSName('requestMIDIAccess')
+  Future requestMidiAccess([Map options]) {
+    var options_dict = null;
+    if (options != null) {
+      options_dict = convertDartToNative_Dictionary(options);
+    }
+    return promiseToFuture(
+        JS("", "#.requestMidiAccess(#)", this, options_dict));
+  }
+
+  Future requestMediaKeySystemAccess(
+          String keySystem, List<Map> supportedConfigurations) =>
+      promiseToFuture(JS("", "#.requestMediaKeySystemAccess(#, #)", this,
+          keySystem, supportedConfigurations));
+
+  bool sendBeacon(String url, Object data) native;
+
+  Future share([Map data]) {
+    var data_dict = null;
+    if (data != null) {
+      data_dict = convertDartToNative_Dictionary(data);
+    }
+    return promiseToFuture(JS("", "#.share(#)", this, data_dict));
+  }
+
+  // From NavigatorAutomationInformation
+
+  final bool webdriver;
+
+  // From NavigatorCookies
+
+  @Unstable()
+  final bool cookieEnabled;
+
+  // From NavigatorID
+
+  final String appCodeName;
+
+  final String appName;
+
+  final String appVersion;
+
+  final bool dartEnabled;
+
+  final String platform;
+
+  @Unstable()
+  final String product;
+
+  final String userAgent;
+
+  // From NavigatorLanguage
+
+  final List<String> languages;
+
+  // From NavigatorOnLine
+
+  @Unstable()
+  final bool onLine;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("NavigatorAutomationInformation")
+class NavigatorAutomationInformation extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory NavigatorAutomationInformation._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final bool webdriver;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("NavigatorConcurrentHardware")
+class NavigatorConcurrentHardware extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory NavigatorConcurrentHardware._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final int hardwareConcurrency;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("NavigatorCookies")
+class NavigatorCookies extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory NavigatorCookies._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final bool cookieEnabled;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+abstract class NavigatorID extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory NavigatorID._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final String appCodeName;
+
+  final String appName;
+
+  final String appVersion;
+
+  final bool dartEnabled;
+
+  final String platform;
+
+  final String product;
+
+  final String userAgent;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+abstract class NavigatorLanguage extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory NavigatorLanguage._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final String language;
+
+  final List<String> languages;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+abstract class NavigatorOnLine extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory NavigatorOnLine._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final bool onLine;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("NavigatorUserMediaError")
+class NavigatorUserMediaError extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory NavigatorUserMediaError._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final String constraintName;
+
+  final String message;
+
+  final String name;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+typedef void _NavigatorUserMediaErrorCallback(NavigatorUserMediaError error);
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+typedef void _NavigatorUserMediaSuccessCallback(MediaStream stream);
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("NetworkInformation")
+class NetworkInformation extends EventTarget {
+  // To suppress missing implicit constructor warnings.
+  factory NetworkInformation._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  static const EventStreamProvider<Event> changeEvent =
+      const EventStreamProvider<Event>('change');
+
+  final num downlink;
+
+  final num downlinkMax;
+
+  final String effectiveType;
+
+  final int rtt;
+
+  final String type;
+
+  Stream<Event> get onChange => changeEvent.forTarget(this);
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/**
+ * Lazy implementation of the child nodes of an element that does not request
+ * the actual child nodes of an element until strictly necessary greatly
+ * improving performance for the typical cases where it is not required.
+ */
+class _ChildNodeListLazy extends ListBase<Node> implements NodeListWrapper {
+  final Node _this;
+
+  _ChildNodeListLazy(this._this);
+
+  Node get first {
+    Node result = JS('Node|Null', '#.firstChild', _this);
+    if (result == null) throw new StateError("No elements");
+    return result;
+  }
+
+  Node get last {
+    Node result = JS('Node|Null', '#.lastChild', _this);
+    if (result == null) throw new StateError("No elements");
+    return result;
+  }
+
+  Node get single {
+    int l = this.length;
+    if (l == 0) throw new StateError("No elements");
+    if (l > 1) throw new StateError("More than one element");
+    return JS('Node|Null', '#.firstChild', _this);
+  }
+
+  void add(Node value) {
+    _this.append(value);
+  }
+
+  void addAll(Iterable<Node> iterable) {
+    if (iterable is _ChildNodeListLazy) {
+      _ChildNodeListLazy otherList = iterable;
+      if (!identical(otherList._this, _this)) {
+        // Optimized route for copying between nodes.
+        for (var i = 0, len = otherList.length; i < len; ++i) {
+          _this.append(otherList._this.firstChild);
+        }
+      }
+      return;
+    }
+    for (Node node in iterable) {
+      _this.append(node);
+    }
+  }
+
+  void insert(int index, Node node) {
+    if (index < 0 || index > length) {
+      throw new RangeError.range(index, 0, length);
+    }
+    if (index == length) {
+      _this.append(node);
+    } else {
+      _this.insertBefore(node, this[index]);
+    }
+  }
+
+  void insertAll(int index, Iterable<Node> iterable) {
+    if (index == length) {
+      addAll(iterable);
+    } else {
+      var item = this[index];
+      _this.insertAllBefore(iterable, item);
+    }
+  }
+
+  void setAll(int index, Iterable<Node> iterable) {
+    throw new UnsupportedError("Cannot setAll on Node list");
+  }
+
+  Node removeLast() {
+    final result = last;
+    if (result != null) {
+      _this._removeChild(result);
+    }
+    return result;
+  }
+
+  Node removeAt(int index) {
+    var result = this[index];
+    if (result != null) {
+      _this._removeChild(result);
+    }
+    return result;
+  }
+
+  bool remove(Object object) {
+    if (object is! Node) return false;
+    Node node = object;
+    if (!identical(_this, node.parentNode)) return false;
+    _this._removeChild(node);
+    return true;
+  }
+
+  void _filter(bool test(Node node), bool removeMatching) {
+    // This implementation of removeWhere/retainWhere is more efficient
+    // than the default in ListBase. Child nodes can be removed in constant
+    // time.
+    Node child = _this.firstChild;
+    while (child != null) {
+      Node nextChild = child.nextNode;
+      if (test(child) == removeMatching) {
+        _this._removeChild(child);
+      }
+      child = nextChild;
+    }
+  }
+
+  void removeWhere(bool test(Node node)) {
+    _filter(test, true);
+  }
+
+  void retainWhere(bool test(Node node)) {
+    _filter(test, false);
+  }
+
+  void clear() {
+    _this._clearChildren();
+  }
+
+  void operator []=(int index, Node value) {
+    _this._replaceChild(value, this[index]);
+  }
+
+  Iterator<Node> get iterator => _this.childNodes.iterator;
+
+  // From List<Node>:
+
+  // TODO(jacobr): this could be implemented for child node lists.
+  // The exception we throw here is misleading.
+  void sort([Comparator<Node> compare]) {
+    throw new UnsupportedError("Cannot sort Node list");
+  }
+
+  void shuffle([Random random]) {
+    throw new UnsupportedError("Cannot shuffle Node list");
+  }
+
+  // FIXME: implement these.
+  void setRange(int start, int end, Iterable<Node> iterable,
+      [int skipCount = 0]) {
+    throw new UnsupportedError("Cannot setRange on Node list");
+  }
+
+  void fillRange(int start, int end, [Node fill]) {
+    throw new UnsupportedError("Cannot fillRange on Node list");
+  }
+
+  void removeRange(int start, int end) {
+    throw new UnsupportedError("Cannot removeRange on Node list");
+  }
+  // -- end List<Node> mixins.
+
+  // TODO(jacobr): benchmark whether this is more efficient or whether caching
+  // a local copy of childNodes is more efficient.
+  int get length => _this.childNodes.length;
+
+  set length(int value) {
+    throw new UnsupportedError("Cannot set length on immutable List.");
+  }
+
+  Node operator [](int index) => _this.childNodes[index];
+
+  List<Node> get rawList => _this.childNodes;
+}
+
+@Native("Node")
+class Node extends EventTarget {
+  // Custom element created callback.
+  Node._created() : super._created();
+
+  /**
+   * A modifiable list of this node's children.
+   */
+  List<Node> get nodes {
+    return new _ChildNodeListLazy(this);
+  }
+
+  set nodes(Iterable<Node> value) {
+    // Copy list first since we don't want liveness during iteration.
+    // TODO(jacobr): there is a better way to do this.
+    var copy = value.toList();
+    text = '';
+    for (Node node in copy) {
+      append(node);
+    }
+  }
+
+  /**
+   * Removes this node from the DOM.
+   */
+  void remove() {
+    // TODO(jacobr): should we throw an exception if parent is already null?
+    // TODO(vsm): Use the native remove when available.
+    if (this.parentNode != null) {
+      final Node parent = this.parentNode;
+      parentNode._removeChild(this);
+    }
+  }
+
+  /**
+   * Replaces this node with another node.
+   */
+  Node replaceWith(Node otherNode) {
+    try {
+      final Node parent = this.parentNode;
+      parent._replaceChild(otherNode, this);
+    } catch (e) {}
+    ;
+    return this;
+  }
+
+  /**
+   * Inserts all of the nodes into this node directly before refChild.
+   *
+   * See also:
+   *
+   * * [insertBefore]
+   */
+  Node insertAllBefore(Iterable<Node> newNodes, Node refChild) {
+    if (newNodes is _ChildNodeListLazy) {
+      _ChildNodeListLazy otherList = newNodes;
+      if (identical(otherList._this, this)) {
+        throw new ArgumentError(newNodes);
+      }
+
+      // Optimized route for copying between nodes.
+      for (var i = 0, len = otherList.length; i < len; ++i) {
+        this.insertBefore(otherList._this.firstChild, refChild);
+      }
+    } else {
+      for (var node in newNodes) {
+        this.insertBefore(node, refChild);
+      }
+    }
+  }
+
+  void _clearChildren() {
+    while (firstChild != null) {
+      _removeChild(firstChild);
+    }
+  }
+
+  /**
+   * Print out a String representation of this Node.
+   */
+  String toString() {
+    String value = nodeValue; // Fetch DOM Node property once.
+    return value == null ? super.toString() : value;
+  }
+
+  /**
+   * A list of this node's children.
+   *
+   * ## Other resources
+   *
+   * * [Node.childNodes](https://developer.mozilla.org/en-US/docs/Web/API/Node.childNodes)
+   *   from MDN.
+   */
+  @Returns('NodeList')
+  @Creates('NodeList')
+  final List<Node> childNodes;
+
+  // To suppress missing implicit constructor warnings.
+  factory Node._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  static const int ATTRIBUTE_NODE = 2;
+
+  static const int CDATA_SECTION_NODE = 4;
+
+  static const int COMMENT_NODE = 8;
+
+  static const int DOCUMENT_FRAGMENT_NODE = 11;
+
+  static const int DOCUMENT_NODE = 9;
+
+  static const int DOCUMENT_TYPE_NODE = 10;
+
+  static const int ELEMENT_NODE = 1;
+
+  static const int ENTITY_NODE = 6;
+
+  static const int ENTITY_REFERENCE_NODE = 5;
+
+  static const int NOTATION_NODE = 12;
+
+  static const int PROCESSING_INSTRUCTION_NODE = 7;
+
+  static const int TEXT_NODE = 3;
+
+  @JSName('baseURI')
+  final String baseUri;
+
+  /**
+   * The first child of this node.
+   *
+   * ## Other resources
+   *
+   * * [Node.firstChild](https://developer.mozilla.org/en-US/docs/Web/API/Node.firstChild)
+   *   from MDN.
+   */
+  final Node firstChild;
+
+  final bool isConnected;
+
+  /**
+   * The last child of this node.
+   *
+   * ## Other resources
+   *
+   * * [Node.lastChild](https://developer.mozilla.org/en-US/docs/Web/API/Node.lastChild)
+   *   from MDN.
+   */
+  final Node lastChild;
+
+  @JSName('nextSibling')
+  /**
+   * The next sibling node.
+   *
+   * ## Other resources
+   *
+   * * [Node.nextSibling](https://developer.mozilla.org/en-US/docs/Web/API/Node.nextSibling)
+   *   from MDN.
+   */
+  final Node nextNode;
+
+  /**
+   * The name of this node.
+   *
+   * This varies by this node's [nodeType].
+   *
+   * ## Other resources
+   *
+   * * [Node.nodeName](https://developer.mozilla.org/en-US/docs/Web/API/Node.nodeName)
+   *   from MDN. This page contains a table of [nodeName] values for each
+   *   [nodeType].
+   */
+  final String nodeName;
+
+  /**
+   * The type of node.
+   *
+   * This value is one of:
+   *
+   * * [ATTRIBUTE_NODE] if this node is an attribute.
+   * * [CDATA_SECTION_NODE] if this node is a [CDataSection].
+   * * [COMMENT_NODE] if this node is a [Comment].
+   * * [DOCUMENT_FRAGMENT_NODE] if this node is a [DocumentFragment].
+   * * [DOCUMENT_NODE] if this node is a [Document].
+   * * [DOCUMENT_TYPE_NODE] if this node is a [DocumentType] node.
+   * * [ELEMENT_NODE] if this node is an [Element].
+   * * [ENTITY_NODE] if this node is an entity.
+   * * [ENTITY_REFERENCE_NODE] if this node is an entity reference.
+   * * [NOTATION_NODE] if this node is a notation.
+   * * [PROCESSING_INSTRUCTION_NODE] if this node is a [ProcessingInstruction].
+   * * [TEXT_NODE] if this node is a [Text] node.
+   *
+   * ## Other resources
+   *
+   * * [Node.nodeType](https://developer.mozilla.org/en-US/docs/Web/API/Node.nodeType)
+   *   from MDN.
+   */
+  final int nodeType;
+
+  /**
+   * The value of this node.
+   *
+   * This varies by this type's [nodeType].
+   *
+   * ## Other resources
+   *
+   * * [Node.nodeValue](https://developer.mozilla.org/en-US/docs/Web/API/Node.nodeValue)
+   *   from MDN. This page contains a table of [nodeValue] values for each
+   *   [nodeType].
+   */
+  final String nodeValue;
+
+  /**
+   * The document this node belongs to.
+   *
+   * Returns null if this node does not belong to any document.
+   *
+   * ## Other resources
+   *
+   * * [Node.ownerDocument](https://developer.mozilla.org/en-US/docs/Web/API/Node.ownerDocument)
+   *   from MDN.
+   */
+  final Document ownerDocument;
+
+  @JSName('parentElement')
+  /**
+   * The parent element of this node.
+   *
+   * Returns null if this node either does not have a parent or its parent is
+   * not an element.
+   *
+   * ## Other resources
+   *
+   * * [Node.parentElement](https://developer.mozilla.org/en-US/docs/Web/API/Node.parentElement)
+   *   from W3C.
+   */
+  final Element parent;
+
+  /**
+   * The parent node of this node.
+   *
+   * ## Other resources
+   *
+   * * [Node.parentNode](https://developer.mozilla.org/en-US/docs/Web/API/Node.parentNode)
+   *   from MDN.
+   */
+  final Node parentNode;
+
+  @JSName('previousSibling')
+  /**
+   * The previous sibling node.
+   *
+   * ## Other resources
+   *
+   * * [Node.previousSibling](https://developer.mozilla.org/en-US/docs/Web/API/Node.previousSibling)
+   *   from MDN.
+   */
+  final Node previousNode;
+
+  @JSName('textContent')
+  /**
+   * All text within this node and its descendents.
+   *
+   * ## Other resources
+   *
+   * * [Node.textContent](https://developer.mozilla.org/en-US/docs/Web/API/Node.textContent)
+   *   from MDN.
+   */
+  String text;
+
+  @JSName('appendChild')
+  /**
+   * Adds a node to the end of the child [nodes] list of this node.
+   *
+   * If the node already exists in this document, it will be removed from its
+   * current parent node, then added to this node.
+   *
+   * This method is more efficient than `nodes.add`, and is the preferred
+   * way of appending a child node.
+   */
+  Node append(Node node) native;
+
+  @JSName('cloneNode')
+  /**
+   * Returns a copy of this node.
+   *
+   * If [deep] is `true`, then all of this node's children and descendents are
+   * copied as well. If [deep] is `false`, then only this node is copied.
+   *
+   * ## Other resources
+   *
+   * * [Node.cloneNode](https://developer.mozilla.org/en-US/docs/Web/API/Node.cloneNode)
+   *   from MDN.
+   */
+  Node clone(bool deep) native;
+
+  /**
+   * Returns true if this node contains the specified node.
+   *
+   * ## Other resources
+   *
+   * * [Node.contains](https://developer.mozilla.org/en-US/docs/Web/API/Node.contains)
+   *   from MDN.
+   */
+  bool contains(Node other) native;
+
+  Node getRootNode([Map options]) {
+    if (options != null) {
+      var options_1 = convertDartToNative_Dictionary(options);
+      return _getRootNode_1(options_1);
+    }
+    return _getRootNode_2();
+  }
+
+  @JSName('getRootNode')
+  Node _getRootNode_1(options) native;
+  @JSName('getRootNode')
+  Node _getRootNode_2() native;
+
+  /**
+   * Returns true if this node has any children.
+   *
+   * ## Other resources
+   *
+   * * [Node.hasChildNodes](https://developer.mozilla.org/en-US/docs/Web/API/Node.hasChildNodes)
+   *   from MDN.
+   */
+  bool hasChildNodes() native;
+
+  /**
+   * Inserts all of the nodes into this node directly before refChild.
+   *
+   * ## Other resources
+   *
+   * * [Node.insertBefore](https://developer.mozilla.org/en-US/docs/Web/API/Node.insertBefore)
+   *   from MDN.
+   */
+  Node insertBefore(Node node, Node child) native;
+
+  @JSName('removeChild')
+  Node _removeChild(Node child) native;
+
+  @JSName('replaceChild')
+  Node _replaceChild(Node node, Node child) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("NodeFilter")
+class NodeFilter extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory NodeFilter._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  static const int FILTER_ACCEPT = 1;
+
+  static const int FILTER_REJECT = 2;
+
+  static const int FILTER_SKIP = 3;
+
+  static const int SHOW_ALL = 0xFFFFFFFF;
+
+  static const int SHOW_COMMENT = 0x80;
+
+  static const int SHOW_DOCUMENT = 0x100;
+
+  static const int SHOW_DOCUMENT_FRAGMENT = 0x400;
+
+  static const int SHOW_DOCUMENT_TYPE = 0x200;
+
+  static const int SHOW_ELEMENT = 0x1;
+
+  static const int SHOW_PROCESSING_INSTRUCTION = 0x40;
+
+  static const int SHOW_TEXT = 0x4;
+}
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("NodeIterator")
+class NodeIterator extends Interceptor {
+  factory NodeIterator(Node root, int whatToShow) {
+    return document._createNodeIterator(root, whatToShow, null);
+  }
+  // To suppress missing implicit constructor warnings.
+  factory NodeIterator._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final bool pointerBeforeReferenceNode;
+
+  final Node referenceNode;
+
+  final Node root;
+
+  final int whatToShow;
+
+  void detach() native;
+
+  Node nextNode() native;
+
+  Node previousNode() native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("NodeList,RadioNodeList")
+class NodeList extends Interceptor
+    with ListMixin<Node>, ImmutableListMixin<Node>
+    implements JavaScriptIndexingBehavior<Node>, List<Node> {
+  // To suppress missing implicit constructor warnings.
+  factory NodeList._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  int get length => JS("int", "#.length", this);
+
+  Node operator [](int index) {
+    if (JS("bool", "# >>> 0 !== # || # >= #", index, index, index, length))
+      throw new RangeError.index(index, this);
+    return JS("Node", "#[#]", this, index);
+  }
+
+  void operator []=(int index, Node value) {
+    throw new UnsupportedError("Cannot assign element of immutable List.");
+  }
+  // -- start List<Node> mixins.
+  // Node is the element type.
+
+  set length(int value) {
+    throw new UnsupportedError("Cannot resize immutable List.");
+  }
+
+  Node get first {
+    if (this.length > 0) {
+      return JS('Node', '#[0]', this);
+    }
+    throw new StateError("No elements");
+  }
+
+  Node get last {
+    int len = this.length;
+    if (len > 0) {
+      return JS('Node', '#[#]', this, len - 1);
+    }
+    throw new StateError("No elements");
+  }
+
+  Node get single {
+    int len = this.length;
+    if (len == 1) {
+      return JS('Node', '#[0]', this);
+    }
+    if (len == 0) throw new StateError("No elements");
+    throw new StateError("More than one element");
+  }
+
+  Node elementAt(int index) => this[index];
+  // -- end List<Node> mixins.
+
+  @JSName('item')
+  Node _item(int index) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("NonDocumentTypeChildNode")
+class NonDocumentTypeChildNode extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory NonDocumentTypeChildNode._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final Element nextElementSibling;
+
+  final Element previousElementSibling;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("NonElementParentNode")
+class NonElementParentNode extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory NonElementParentNode._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  Element getElementById(String elementId) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("NoncedElement")
+class NoncedElement extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory NoncedElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  String nonce;
+}
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("Notification")
+class Notification extends EventTarget {
+  factory Notification(String title,
+      {String dir: null,
+      String body: null,
+      String lang: null,
+      String tag: null,
+      String icon: null}) {
+    var parsedOptions = {};
+    if (dir != null) parsedOptions['dir'] = dir;
+    if (body != null) parsedOptions['body'] = body;
+    if (lang != null) parsedOptions['lang'] = lang;
+    if (tag != null) parsedOptions['tag'] = tag;
+    if (icon != null) parsedOptions['icon'] = icon;
+    return Notification._factoryNotification(title, parsedOptions);
+  }
+  // To suppress missing implicit constructor warnings.
+  factory Notification._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  /**
+   * Static factory designed to expose `click` events to event
+   * handlers that are not necessarily instances of [Notification].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<Event> clickEvent =
+      const EventStreamProvider<Event>('click');
+
+  /**
+   * Static factory designed to expose `close` events to event
+   * handlers that are not necessarily instances of [Notification].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<Event> closeEvent =
+      const EventStreamProvider<Event>('close');
+
+  /**
+   * Static factory designed to expose `error` events to event
+   * handlers that are not necessarily instances of [Notification].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<Event> errorEvent =
+      const EventStreamProvider<Event>('error');
+
+  /**
+   * Static factory designed to expose `show` events to event
+   * handlers that are not necessarily instances of [Notification].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<Event> showEvent =
+      const EventStreamProvider<Event>('show');
+
+  static Notification _factoryNotification(String title, [Map options]) {
+    if (options != null) {
+      var options_1 = convertDartToNative_Dictionary(options);
+      return Notification._create_1(title, options_1);
+    }
+    return Notification._create_2(title);
+  }
+
+  static Notification _create_1(title, options) =>
+      JS('Notification', 'new Notification(#,#)', title, options);
+  static Notification _create_2(title) =>
+      JS('Notification', 'new Notification(#)', title);
+
+  /// Checks if this type is supported on the current platform.
+  static bool get supported => JS('bool', '!!(window.Notification)');
+
+  final List actions;
+
+  final String badge;
+
+  final String body;
+
+  @annotation_Creates_SerializedScriptValue
+  @annotation_Returns_SerializedScriptValue
+  final Object data;
+
+  final String dir;
+
+  final String icon;
+
+  final String image;
+
+  final String lang;
+
+  static final int maxActions;
+
+  static final String permission;
+
+  final bool renotify;
+
+  final bool requireInteraction;
+
+  final bool silent;
+
+  final String tag;
+
+  final int timestamp;
+
+  final String title;
+
+  final List<int> vibrate;
+
+  void close() native;
+
+  @JSName('requestPermission')
+  static Future _requestPermission(
+      [_NotificationPermissionCallback deprecatedCallback]) native;
+
+  @JSName('requestPermission')
+  static Future<String> requestPermission() {
+    var completer = new Completer<String>();
+    _requestPermission((value) {
+      completer.complete(value);
+    });
+    return completer.future;
+  }
+
+  /// Stream of `click` events handled by this [Notification].
+  Stream<Event> get onClick => clickEvent.forTarget(this);
+
+  /// Stream of `close` events handled by this [Notification].
+  Stream<Event> get onClose => closeEvent.forTarget(this);
+
+  /// Stream of `error` events handled by this [Notification].
+  Stream<Event> get onError => errorEvent.forTarget(this);
+
+  /// Stream of `show` events handled by this [Notification].
+  Stream<Event> get onShow => showEvent.forTarget(this);
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("NotificationEvent")
+class NotificationEvent extends ExtendableEvent {
+  // To suppress missing implicit constructor warnings.
+  factory NotificationEvent._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory NotificationEvent(String type, Map eventInitDict) {
+    var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+    return NotificationEvent._create_1(type, eventInitDict_1);
+  }
+  static NotificationEvent _create_1(type, eventInitDict) => JS(
+      'NotificationEvent', 'new NotificationEvent(#,#)', type, eventInitDict);
+
+  final String action;
+
+  final Notification notification;
+
+  final String reply;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+typedef void _NotificationPermissionCallback(String permission);
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("HTMLOListElement")
+class OListElement extends HtmlElement {
+  // To suppress missing implicit constructor warnings.
+  factory OListElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory OListElement() => JS(
+      'returns:OListElement;creates:OListElement;new:true',
+      '#.createElement(#)',
+      document,
+      "ol");
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  OListElement.created() : super.created();
+
+  bool reversed;
+
+  int start;
+
+  String type;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.IE)
+@SupportedBrowser(SupportedBrowser.SAFARI)
+@Unstable()
+@Native("HTMLObjectElement")
+class ObjectElement extends HtmlElement {
+  // To suppress missing implicit constructor warnings.
+  factory ObjectElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory ObjectElement() => document.createElement("object");
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  ObjectElement.created() : super.created();
+
+  /// Checks if this type is supported on the current platform.
+  static bool get supported => Element.isTagSupported('object');
+
+  WindowBase get contentWindow =>
+      _convertNativeToDart_Window(this._get_contentWindow);
+  @JSName('contentWindow')
+  @Creates('Window|=Object')
+  @Returns('Window|=Object')
+  final dynamic _get_contentWindow;
+
+  String data;
+
+  final FormElement form;
+
+  String height;
+
+  String name;
+
+  String type;
+
+  String useMap;
+
+  final String validationMessage;
+
+  final ValidityState validity;
+
+  String width;
+
+  final bool willValidate;
+
+  Node __getter__(String name) native;
+
+  void __setter__(String name, Node value) native;
+
+  bool checkValidity() native;
+
+  bool reportValidity() native;
+
+  void setCustomValidity(String error) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("OffscreenCanvas")
+class OffscreenCanvas extends EventTarget {
+  // To suppress missing implicit constructor warnings.
+  factory OffscreenCanvas._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory OffscreenCanvas(int width, int height) {
+    return OffscreenCanvas._create_1(width, height);
+  }
+  static OffscreenCanvas _create_1(width, height) =>
+      JS('OffscreenCanvas', 'new OffscreenCanvas(#,#)', width, height);
+
+  int height;
+
+  int width;
+
+  Future<Blob> convertToBlob([Map options]) {
+    var options_dict = null;
+    if (options != null) {
+      options_dict = convertDartToNative_Dictionary(options);
+    }
+    return promiseToFuture<Blob>(
+        JS("", "#.convertToBlob(#)", this, options_dict));
+  }
+
+  Object getContext(String contextType, [Map attributes]) {
+    if (attributes != null) {
+      var attributes_1 = convertDartToNative_Dictionary(attributes);
+      return _getContext_1(contextType, attributes_1);
+    }
+    return _getContext_2(contextType);
+  }
+
+  @JSName('getContext')
+  Object _getContext_1(contextType, attributes) native;
+  @JSName('getContext')
+  Object _getContext_2(contextType) native;
+
+  ImageBitmap transferToImageBitmap() native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("OffscreenCanvasRenderingContext2D")
+class OffscreenCanvasRenderingContext2D extends Interceptor
+    implements _CanvasPath {
+  // To suppress missing implicit constructor warnings.
+  factory OffscreenCanvasRenderingContext2D._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final OffscreenCanvas canvas;
+
+  String direction;
+
+  Object fillStyle;
+
+  String filter;
+
+  String font;
+
+  num globalAlpha;
+
+  String globalCompositeOperation;
+
+  bool imageSmoothingEnabled;
+
+  String imageSmoothingQuality;
+
+  String lineCap;
+
+  num lineDashOffset;
+
+  String lineJoin;
+
+  num lineWidth;
+
+  num miterLimit;
+
+  num shadowBlur;
+
+  String shadowColor;
+
+  num shadowOffsetX;
+
+  num shadowOffsetY;
+
+  Object strokeStyle;
+
+  String textAlign;
+
+  String textBaseline;
+
+  void beginPath() native;
+
+  void clearRect(num x, num y, num width, num height) native;
+
+  void clip([Path2D path]) native;
+
+  Future commit() => promiseToFuture(JS("", "#.commit()", this));
+
+  ImageData createImageData(data_OR_imagedata_OR_sw,
+      [int sh_OR_sw,
+      imageDataColorSettings_OR_sh,
+      Map imageDataColorSettings]) {
+    if ((data_OR_imagedata_OR_sw is ImageData) &&
+        sh_OR_sw == null &&
+        imageDataColorSettings_OR_sh == null &&
+        imageDataColorSettings == null) {
+      var imagedata_1 = convertDartToNative_ImageData(data_OR_imagedata_OR_sw);
+      return convertNativeToDart_ImageData(_createImageData_1(imagedata_1));
+    }
+    if (sh_OR_sw != null &&
+        (data_OR_imagedata_OR_sw is int) &&
+        imageDataColorSettings_OR_sh == null &&
+        imageDataColorSettings == null) {
+      return convertNativeToDart_ImageData(
+          _createImageData_2(data_OR_imagedata_OR_sw, sh_OR_sw));
+    }
+    if ((imageDataColorSettings_OR_sh is Map) &&
+        sh_OR_sw != null &&
+        (data_OR_imagedata_OR_sw is int) &&
+        imageDataColorSettings == null) {
+      var imageDataColorSettings_1 =
+          convertDartToNative_Dictionary(imageDataColorSettings_OR_sh);
+      return convertNativeToDart_ImageData(_createImageData_3(
+          data_OR_imagedata_OR_sw, sh_OR_sw, imageDataColorSettings_1));
+    }
+    if (imageDataColorSettings != null &&
+        (imageDataColorSettings_OR_sh is int) &&
+        sh_OR_sw != null &&
+        data_OR_imagedata_OR_sw != null) {
+      var imageDataColorSettings_1 =
+          convertDartToNative_Dictionary(imageDataColorSettings);
+      return convertNativeToDart_ImageData(_createImageData_4(
+          data_OR_imagedata_OR_sw,
+          sh_OR_sw,
+          imageDataColorSettings_OR_sh,
+          imageDataColorSettings_1));
+    }
+    throw new ArgumentError("Incorrect number or type of arguments");
+  }
+
+  @JSName('createImageData')
+  _createImageData_1(imagedata) native;
+  @JSName('createImageData')
+  _createImageData_2(int sw, sh) native;
+  @JSName('createImageData')
+  _createImageData_3(int sw, sh, imageDataColorSettings) native;
+  @JSName('createImageData')
+  _createImageData_4(data, sw, int sh, imageDataColorSettings) native;
+
+  CanvasGradient createLinearGradient(num x0, num y0, num x1, num y1) native;
+
+  CanvasPattern createPattern(
+      /*CanvasImageSource*/ image, String repetitionType) native;
+
+  CanvasGradient createRadialGradient(
+      num x0, num y0, num r0, num x1, num y1, num r1) native;
+
+  void drawImage(/*CanvasImageSource*/ image, num sx_OR_x, num sy_OR_y,
+      [num sw_OR_width,
+      num height_OR_sh,
+      num dx,
+      num dy,
+      num dw,
+      num dh]) native;
+
+  void fill([path_OR_winding, String winding]) native;
+
+  void fillRect(num x, num y, num width, num height) native;
+
+  void fillText(String text, num x, num y, [num maxWidth]) native;
+
+  ImageData getImageData(int sx, int sy, int sw, int sh) {
+    return convertNativeToDart_ImageData(_getImageData_1(sx, sy, sw, sh));
+  }
+
+  @JSName('getImageData')
+  _getImageData_1(sx, sy, sw, sh) native;
+
+  List<num> getLineDash() native;
+
+  bool isPointInPath(path_OR_x, num x_OR_y, [winding_OR_y, String winding])
+      native;
+
+  bool isPointInStroke(path_OR_x, num x_OR_y, [num y]) native;
+
+  TextMetrics measureText(String text) native;
+
+  void putImageData(ImageData imagedata, int dx, int dy,
+      [int dirtyX, int dirtyY, int dirtyWidth, int dirtyHeight]) {
+    if (dirtyX == null &&
+        dirtyY == null &&
+        dirtyWidth == null &&
+        dirtyHeight == null) {
+      var imagedata_1 = convertDartToNative_ImageData(imagedata);
+      _putImageData_1(imagedata_1, dx, dy);
+      return;
+    }
+    if (dirtyHeight != null &&
+        dirtyWidth != null &&
+        dirtyY != null &&
+        dirtyX != null) {
+      var imagedata_1 = convertDartToNative_ImageData(imagedata);
+      _putImageData_2(
+          imagedata_1, dx, dy, dirtyX, dirtyY, dirtyWidth, dirtyHeight);
+      return;
+    }
+    throw new ArgumentError("Incorrect number or type of arguments");
+  }
+
+  @JSName('putImageData')
+  void _putImageData_1(imagedata, dx, dy) native;
+  @JSName('putImageData')
+  void _putImageData_2(
+      imagedata, dx, dy, dirtyX, dirtyY, dirtyWidth, dirtyHeight) native;
+
+  void resetTransform() native;
+
+  void restore() native;
+
+  void rotate(num angle) native;
+
+  void save() native;
+
+  void scale(num x, num y) native;
+
+  void setLineDash(List<num> dash) native;
+
+  void setTransform(num a, num b, num c, num d, num e, num f) native;
+
+  void stroke([Path2D path]) native;
+
+  void strokeRect(num x, num y, num width, num height) native;
+
+  void strokeText(String text, num x, num y, [num maxWidth]) native;
+
+  void transform(num a, num b, num c, num d, num e, num f) native;
+
+  void translate(num x, num y) native;
+
+  // From CanvasPath
+
+  void arc(num x, num y, num radius, num startAngle, num endAngle,
+      bool anticlockwise) native;
+
+  void arcTo(num x1, num y1, num x2, num y2, num radius) native;
+
+  void bezierCurveTo(num cp1x, num cp1y, num cp2x, num cp2y, num x, num y)
+      native;
+
+  void closePath() native;
+
+  void ellipse(num x, num y, num radiusX, num radiusY, num rotation,
+      num startAngle, num endAngle, bool anticlockwise) native;
+
+  void lineTo(num x, num y) native;
+
+  void moveTo(num x, num y) native;
+
+  void quadraticCurveTo(num cpx, num cpy, num x, num y) native;
+
+  void rect(num x, num y, num width, num height) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("HTMLOptGroupElement")
+class OptGroupElement extends HtmlElement {
+  // To suppress missing implicit constructor warnings.
+  factory OptGroupElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory OptGroupElement() => JS(
+      'returns:OptGroupElement;creates:OptGroupElement;new:true',
+      '#.createElement(#)',
+      document,
+      "optgroup");
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  OptGroupElement.created() : super.created();
+
+  bool disabled;
+
+  String label;
+}
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("HTMLOptionElement")
+class OptionElement extends HtmlElement {
+  factory OptionElement(
+      {String data: '', String value: '', bool selected: false}) {
+    return new OptionElement._(data, value, null, selected);
+  }
+
+  factory OptionElement._(
+      [String data, String value, bool defaultSelected, bool selected]) {
+    if (selected != null) {
+      return OptionElement._create_1(data, value, defaultSelected, selected);
+    }
+    if (defaultSelected != null) {
+      return OptionElement._create_2(data, value, defaultSelected);
+    }
+    if (value != null) {
+      return OptionElement._create_3(data, value);
+    }
+    if (data != null) {
+      return OptionElement._create_4(data);
+    }
+    return OptionElement._create_5();
+  }
+  static OptionElement _create_1(data, value, defaultSelected, selected) => JS(
+      'OptionElement',
+      'new Option(#,#,#,#)',
+      data,
+      value,
+      defaultSelected,
+      selected);
+  static OptionElement _create_2(data, value, defaultSelected) =>
+      JS('OptionElement', 'new Option(#,#,#)', data, value, defaultSelected);
+  static OptionElement _create_3(data, value) =>
+      JS('OptionElement', 'new Option(#,#)', data, value);
+  static OptionElement _create_4(data) =>
+      JS('OptionElement', 'new Option(#)', data);
+  static OptionElement _create_5() => JS('OptionElement', 'new Option()');
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  OptionElement.created() : super.created();
+
+  bool defaultSelected;
+
+  bool disabled;
+
+  final FormElement form;
+
+  final int index;
+
+  String label;
+
+  bool selected;
+
+  String value;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("OrientationSensor")
+class OrientationSensor extends Sensor {
+  // To suppress missing implicit constructor warnings.
+  factory OrientationSensor._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final List<num> quaternion;
+
+  void populateMatrix(Object targetBuffer) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.FIREFOX)
+@SupportedBrowser(SupportedBrowser.SAFARI)
+@Native("HTMLOutputElement")
+class OutputElement extends HtmlElement {
+  // To suppress missing implicit constructor warnings.
+  factory OutputElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory OutputElement() => document.createElement("output");
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  OutputElement.created() : super.created();
+
+  /// Checks if this type is supported on the current platform.
+  static bool get supported => Element.isTagSupported('output');
+
+  String defaultValue;
+
+  final FormElement form;
+
+  final DomTokenList htmlFor;
+
+  @Unstable()
+  @Returns('NodeList|Null')
+  @Creates('NodeList')
+  final List<Node> labels;
+
+  String name;
+
+  final String type;
+
+  final String validationMessage;
+
+  final ValidityState validity;
+
+  String value;
+
+  final bool willValidate;
+
+  bool checkValidity() native;
+
+  bool reportValidity() native;
+
+  void setCustomValidity(String error) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("OverconstrainedError")
+class OverconstrainedError extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory OverconstrainedError._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory OverconstrainedError(String constraint, String message) {
+    return OverconstrainedError._create_1(constraint, message);
+  }
+  static OverconstrainedError _create_1(constraint, message) => JS(
+      'OverconstrainedError',
+      'new OverconstrainedError(#,#)',
+      constraint,
+      message);
+
+  final String constraint;
+
+  final String message;
+
+  final String name;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("PageTransitionEvent")
+class PageTransitionEvent extends Event {
+  // To suppress missing implicit constructor warnings.
+  factory PageTransitionEvent._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory PageTransitionEvent(String type, [Map eventInitDict]) {
+    if (eventInitDict != null) {
+      var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+      return PageTransitionEvent._create_1(type, eventInitDict_1);
+    }
+    return PageTransitionEvent._create_2(type);
+  }
+  static PageTransitionEvent _create_1(type, eventInitDict) => JS(
+      'PageTransitionEvent',
+      'new PageTransitionEvent(#,#)',
+      type,
+      eventInitDict);
+  static PageTransitionEvent _create_2(type) =>
+      JS('PageTransitionEvent', 'new PageTransitionEvent(#)', type);
+
+  final bool persisted;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("PaintRenderingContext2D")
+class PaintRenderingContext2D extends Interceptor implements _CanvasPath {
+  // To suppress missing implicit constructor warnings.
+  factory PaintRenderingContext2D._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  Matrix currentTransform;
+
+  Object fillStyle;
+
+  String filter;
+
+  num globalAlpha;
+
+  String globalCompositeOperation;
+
+  bool imageSmoothingEnabled;
+
+  String imageSmoothingQuality;
+
+  String lineCap;
+
+  num lineDashOffset;
+
+  String lineJoin;
+
+  num lineWidth;
+
+  num miterLimit;
+
+  num shadowBlur;
+
+  String shadowColor;
+
+  num shadowOffsetX;
+
+  num shadowOffsetY;
+
+  Object strokeStyle;
+
+  void beginPath() native;
+
+  void clearRect(num x, num y, num width, num height) native;
+
+  void clip([path_OR_winding, String winding]) native;
+
+  CanvasGradient createLinearGradient(num x0, num y0, num x1, num y1) native;
+
+  CanvasPattern createPattern(
+      /*CanvasImageSource*/ image, String repetitionType) native;
+
+  CanvasGradient createRadialGradient(
+      num x0, num y0, num r0, num x1, num y1, num r1) native;
+
+  void drawImage(/*CanvasImageSource*/ image, num sx_OR_x, num sy_OR_y,
+      [num sw_OR_width,
+      num height_OR_sh,
+      num dx,
+      num dy,
+      num dw,
+      num dh]) native;
+
+  void fill([path_OR_winding, String winding]) native;
+
+  void fillRect(num x, num y, num width, num height) native;
+
+  List<num> getLineDash() native;
+
+  bool isPointInPath(path_OR_x, num x_OR_y, [winding_OR_y, String winding])
+      native;
+
+  bool isPointInStroke(path_OR_x, num x_OR_y, [num y]) native;
+
+  void resetTransform() native;
+
+  void restore() native;
+
+  void rotate(num angle) native;
+
+  void save() native;
+
+  void scale(num x, num y) native;
+
+  void setLineDash(List<num> dash) native;
+
+  void setTransform(num a, num b, num c, num d, num e, num f) native;
+
+  void stroke([Path2D path]) native;
+
+  void strokeRect(num x, num y, num width, num height) native;
+
+  void transform(num a, num b, num c, num d, num e, num f) native;
+
+  void translate(num x, num y) native;
+
+  // From CanvasPath
+
+  void arc(num x, num y, num radius, num startAngle, num endAngle,
+      bool anticlockwise) native;
+
+  void arcTo(num x1, num y1, num x2, num y2, num radius) native;
+
+  void bezierCurveTo(num cp1x, num cp1y, num cp2x, num cp2y, num x, num y)
+      native;
+
+  void closePath() native;
+
+  void ellipse(num x, num y, num radiusX, num radiusY, num rotation,
+      num startAngle, num endAngle, bool anticlockwise) native;
+
+  void lineTo(num x, num y) native;
+
+  void moveTo(num x, num y) native;
+
+  void quadraticCurveTo(num cpx, num cpy, num x, num y) native;
+
+  void rect(num x, num y, num width, num height) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("PaintSize")
+class PaintSize extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory PaintSize._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final num height;
+
+  final num width;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("PaintWorkletGlobalScope")
+class PaintWorkletGlobalScope extends WorkletGlobalScope {
+  // To suppress missing implicit constructor warnings.
+  factory PaintWorkletGlobalScope._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final num devicePixelRatio;
+
+  void registerPaint(String name, Object paintCtor) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("HTMLParagraphElement")
+class ParagraphElement extends HtmlElement {
+  // To suppress missing implicit constructor warnings.
+  factory ParagraphElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory ParagraphElement() => JS(
+      'returns:ParagraphElement;creates:ParagraphElement;new:true',
+      '#.createElement(#)',
+      document,
+      "p");
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  ParagraphElement.created() : super.created();
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("HTMLParamElement")
+class ParamElement extends HtmlElement {
+  // To suppress missing implicit constructor warnings.
+  factory ParamElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory ParamElement() => JS(
+      'returns:ParamElement;creates:ParamElement;new:true',
+      '#.createElement(#)',
+      document,
+      "param");
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  ParamElement.created() : super.created();
+
+  String name;
+
+  String value;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+abstract class ParentNode extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory ParentNode._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final int _childElementCount;
+
+  final List<Node> _children;
+
+  final Element _firstElementChild;
+
+  final Element _lastElementChild;
+
+  Element querySelector(String selectors);
+
+  List<Node> _querySelectorAll(String selectors);
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("PasswordCredential")
+class PasswordCredential extends Credential implements CredentialUserData {
+  // To suppress missing implicit constructor warnings.
+  factory PasswordCredential._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory PasswordCredential(data_OR_form) {
+    if ((data_OR_form is Map)) {
+      var data_1 = convertDartToNative_Dictionary(data_OR_form);
+      return PasswordCredential._create_1(data_1);
+    }
+    if ((data_OR_form is FormElement)) {
+      return PasswordCredential._create_2(data_OR_form);
+    }
+    throw new ArgumentError("Incorrect number or type of arguments");
+  }
+  static PasswordCredential _create_1(data_OR_form) =>
+      JS('PasswordCredential', 'new PasswordCredential(#)', data_OR_form);
+  static PasswordCredential _create_2(data_OR_form) =>
+      JS('PasswordCredential', 'new PasswordCredential(#)', data_OR_form);
+
+  Object additionalData;
+
+  String idName;
+
+  final String password;
+
+  String passwordName;
+
+  // From CredentialUserData
+
+  @JSName('iconURL')
+  final String iconUrl;
+
+  final String name;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("Path2D")
+class Path2D extends Interceptor implements _CanvasPath {
+  // To suppress missing implicit constructor warnings.
+  factory Path2D._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory Path2D([path_OR_text]) {
+    if (path_OR_text == null) {
+      return Path2D._create_1();
+    }
+    if ((path_OR_text is Path2D)) {
+      return Path2D._create_2(path_OR_text);
+    }
+    if ((path_OR_text is String)) {
+      return Path2D._create_3(path_OR_text);
+    }
+    throw new ArgumentError("Incorrect number or type of arguments");
+  }
+  static Path2D _create_1() => JS('Path2D', 'new Path2D()');
+  static Path2D _create_2(path_OR_text) =>
+      JS('Path2D', 'new Path2D(#)', path_OR_text);
+  static Path2D _create_3(path_OR_text) =>
+      JS('Path2D', 'new Path2D(#)', path_OR_text);
+
+  void addPath(Path2D path, [Matrix transform]) native;
+
+  // From CanvasPath
+
+  void arc(num x, num y, num radius, num startAngle, num endAngle,
+      bool anticlockwise) native;
+
+  void arcTo(num x1, num y1, num x2, num y2, num radius) native;
+
+  void bezierCurveTo(num cp1x, num cp1y, num cp2x, num cp2y, num x, num y)
+      native;
+
+  void closePath() native;
+
+  void ellipse(num x, num y, num radiusX, num radiusY, num rotation,
+      num startAngle, num endAngle, bool anticlockwise) native;
+
+  void lineTo(num x, num y) native;
+
+  void moveTo(num x, num y) native;
+
+  void quadraticCurveTo(num cpx, num cpy, num x, num y) native;
+
+  void rect(num x, num y, num width, num height) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("PaymentAddress")
+class PaymentAddress extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory PaymentAddress._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final List<String> addressLine;
+
+  final String city;
+
+  final String country;
+
+  final String dependentLocality;
+
+  final String languageCode;
+
+  final String organization;
+
+  final String phone;
+
+  final String postalCode;
+
+  final String recipient;
+
+  final String region;
+
+  final String sortingCode;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("PaymentInstruments")
+class PaymentInstruments extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory PaymentInstruments._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  Future clear() => promiseToFuture(JS("", "#.clear()", this));
+
+  Future<bool> delete(String instrumentKey) =>
+      promiseToFuture<bool>(JS("", "#.delete(#)", this, instrumentKey));
+
+  Future<Map<String, dynamic>> get(String instrumentKey) =>
+      promiseToFutureAsMap(JS("", "#.get(#)", this, instrumentKey));
+
+  Future has(String instrumentKey) =>
+      promiseToFuture(JS("", "#.has(#)", this, instrumentKey));
+
+  Future<List<String>> keys() =>
+      promiseToFuture<List<String>>(JS("", "#.keys()", this));
+
+  Future set(String instrumentKey, Map details) {
+    var details_dict = convertDartToNative_Dictionary(details);
+    return promiseToFuture(
+        JS("", "#.set(#, #)", this, instrumentKey, details_dict));
+  }
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("PaymentManager")
+class PaymentManager extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory PaymentManager._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final PaymentInstruments instruments;
+
+  String userHint;
+}
+// Copyright (c) 2015, 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.
+
+@Native("PaymentRequest")
+class PaymentRequest extends EventTarget {
+  factory PaymentRequest(List<Map> methodData, Map details, [Map options]) {
+    var methodData_1 = [];
+    for (var i in methodData) {
+      methodData_1.add(convertDartToNative_Dictionary(i));
+    }
+    if (options != null) {
+      var details_1 = convertDartToNative_Dictionary(details);
+      var options_2 = convertDartToNative_Dictionary(options);
+      return PaymentRequest._create_1(methodData_1, details_1, options_2);
+    }
+    var details_1 = convertDartToNative_Dictionary(details);
+    return PaymentRequest._create_2(methodData_1, details_1);
+  }
+
+  static PaymentRequest _create_1(methodData, details, options) => JS(
+      'PaymentRequest',
+      'new PaymentRequest(#,#,#)',
+      methodData,
+      details,
+      options);
+  static PaymentRequest _create_2(methodData, details) =>
+      JS('PaymentRequest', 'new PaymentRequest(#,#)', methodData, details);
+
+  // To suppress missing implicit constructor warnings.
+  factory PaymentRequest._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final String id;
+
+  final PaymentAddress shippingAddress;
+
+  final String shippingOption;
+
+  final String shippingType;
+
+  Future abort() => promiseToFuture(JS("", "#.abort()", this));
+
+  Future<bool> canMakePayment() =>
+      promiseToFuture<bool>(JS("", "#.canMakePayment()", this));
+
+  Future<PaymentResponse> show() =>
+      promiseToFuture<PaymentResponse>(JS("", "#.show()", this));
+}
+
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("PaymentRequestEvent")
+class PaymentRequestEvent extends ExtendableEvent {
+  // To suppress missing implicit constructor warnings.
+  factory PaymentRequestEvent._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory PaymentRequestEvent(String type, Map eventInitDict) {
+    var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+    return PaymentRequestEvent._create_1(type, eventInitDict_1);
+  }
+  static PaymentRequestEvent _create_1(type, eventInitDict) => JS(
+      'PaymentRequestEvent',
+      'new PaymentRequestEvent(#,#)',
+      type,
+      eventInitDict);
+
+  final String instrumentKey;
+
+  final List methodData;
+
+  final List modifiers;
+
+  final String paymentRequestId;
+
+  final String paymentRequestOrigin;
+
+  final String topLevelOrigin;
+
+  final Object total;
+
+  Future<WindowClient> openWindow(String url) =>
+      promiseToFuture<WindowClient>(JS("", "#.openWindow(#)", this, url));
+
+  void respondWith(Future response) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("PaymentRequestUpdateEvent")
+class PaymentRequestUpdateEvent extends Event {
+  // To suppress missing implicit constructor warnings.
+  factory PaymentRequestUpdateEvent._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory PaymentRequestUpdateEvent(String type, [Map eventInitDict]) {
+    if (eventInitDict != null) {
+      var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+      return PaymentRequestUpdateEvent._create_1(type, eventInitDict_1);
+    }
+    return PaymentRequestUpdateEvent._create_2(type);
+  }
+  static PaymentRequestUpdateEvent _create_1(type, eventInitDict) => JS(
+      'PaymentRequestUpdateEvent',
+      'new PaymentRequestUpdateEvent(#,#)',
+      type,
+      eventInitDict);
+  static PaymentRequestUpdateEvent _create_2(type) =>
+      JS('PaymentRequestUpdateEvent', 'new PaymentRequestUpdateEvent(#)', type);
+
+  void updateWith(Future detailsPromise) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("PaymentResponse")
+class PaymentResponse extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory PaymentResponse._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final Object details;
+
+  final String methodName;
+
+  final String payerEmail;
+
+  final String payerName;
+
+  final String payerPhone;
+
+  final String requestId;
+
+  final PaymentAddress shippingAddress;
+
+  final String shippingOption;
+
+  Future complete([String paymentResult]) =>
+      promiseToFuture(JS("", "#.complete(#)", this, paymentResult));
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.FIREFOX)
+@SupportedBrowser(SupportedBrowser.IE)
+@Native("Performance")
+class Performance extends EventTarget {
+  // To suppress missing implicit constructor warnings.
+  factory Performance._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  /// Checks if this type is supported on the current platform.
+  static bool get supported => JS('bool', '!!(window.performance)');
+
+  final MemoryInfo memory;
+
+  final PerformanceNavigation navigation;
+
+  final num timeOrigin;
+
+  final PerformanceTiming timing;
+
+  void clearMarks(String markName) native;
+
+  void clearMeasures(String measureName) native;
+
+  void clearResourceTimings() native;
+
+  List<PerformanceEntry> getEntries() native;
+
+  List<PerformanceEntry> getEntriesByName(String name, String entryType) native;
+
+  List<PerformanceEntry> getEntriesByType(String entryType) native;
+
+  void mark(String markName) native;
+
+  void measure(String measureName, String startMark, String endMark) native;
+
+  double now() native;
+
+  void setResourceTimingBufferSize(int maxSize) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("PerformanceEntry")
+class PerformanceEntry extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory PerformanceEntry._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final num duration;
+
+  final String entryType;
+
+  final String name;
+
+  final num startTime;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("PerformanceLongTaskTiming")
+class PerformanceLongTaskTiming extends PerformanceEntry {
+  // To suppress missing implicit constructor warnings.
+  factory PerformanceLongTaskTiming._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final List<TaskAttributionTiming> attribution;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("PerformanceMark")
+class PerformanceMark extends PerformanceEntry {
+  // To suppress missing implicit constructor warnings.
+  factory PerformanceMark._() {
+    throw new UnsupportedError("Not supported");
+  }
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("PerformanceMeasure")
+class PerformanceMeasure extends PerformanceEntry {
+  // To suppress missing implicit constructor warnings.
+  factory PerformanceMeasure._() {
+    throw new UnsupportedError("Not supported");
+  }
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("PerformanceNavigation")
+class PerformanceNavigation extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory PerformanceNavigation._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  static const int TYPE_BACK_FORWARD = 2;
+
+  static const int TYPE_NAVIGATE = 0;
+
+  static const int TYPE_RELOAD = 1;
+
+  static const int TYPE_RESERVED = 255;
+
+  final int redirectCount;
+
+  final int type;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("PerformanceNavigationTiming")
+class PerformanceNavigationTiming extends PerformanceResourceTiming {
+  // To suppress missing implicit constructor warnings.
+  factory PerformanceNavigationTiming._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final num domComplete;
+
+  final num domContentLoadedEventEnd;
+
+  final num domContentLoadedEventStart;
+
+  final num domInteractive;
+
+  final num loadEventEnd;
+
+  final num loadEventStart;
+
+  final int redirectCount;
+
+  final String type;
+
+  final num unloadEventEnd;
+
+  final num unloadEventStart;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("PerformanceObserver")
+class PerformanceObserver extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory PerformanceObserver._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory PerformanceObserver(PerformanceObserverCallback callback) {
+    var callback_1 = convertDartClosureToJS(callback, 2);
+    return PerformanceObserver._create_1(callback_1);
+  }
+  static PerformanceObserver _create_1(callback) =>
+      JS('PerformanceObserver', 'new PerformanceObserver(#)', callback);
+
+  void disconnect() native;
+
+  void observe(Map options) {
+    var options_1 = convertDartToNative_Dictionary(options);
+    _observe_1(options_1);
+    return;
+  }
+
+  @JSName('observe')
+  void _observe_1(options) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+typedef void PerformanceObserverCallback(
+    PerformanceObserverEntryList entries, PerformanceObserver observer);
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("PerformanceObserverEntryList")
+class PerformanceObserverEntryList extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory PerformanceObserverEntryList._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  List<PerformanceEntry> getEntries() native;
+
+  List<PerformanceEntry> getEntriesByName(String name, String entryType) native;
+
+  List<PerformanceEntry> getEntriesByType(String entryType) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("PerformancePaintTiming")
+class PerformancePaintTiming extends PerformanceEntry {
+  // To suppress missing implicit constructor warnings.
+  factory PerformancePaintTiming._() {
+    throw new UnsupportedError("Not supported");
+  }
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("PerformanceResourceTiming")
+class PerformanceResourceTiming extends PerformanceEntry {
+  // To suppress missing implicit constructor warnings.
+  factory PerformanceResourceTiming._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final num connectEnd;
+
+  final num connectStart;
+
+  final int decodedBodySize;
+
+  final num domainLookupEnd;
+
+  final num domainLookupStart;
+
+  final int encodedBodySize;
+
+  final num fetchStart;
+
+  final String initiatorType;
+
+  final String nextHopProtocol;
+
+  final num redirectEnd;
+
+  final num redirectStart;
+
+  final num requestStart;
+
+  final num responseEnd;
+
+  final num responseStart;
+
+  final num secureConnectionStart;
+
+  final List<PerformanceServerTiming> serverTiming;
+
+  final int transferSize;
+
+  final num workerStart;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("PerformanceServerTiming")
+class PerformanceServerTiming extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory PerformanceServerTiming._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final String description;
+
+  final num duration;
+
+  final String name;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("PerformanceTiming")
+class PerformanceTiming extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory PerformanceTiming._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final int connectEnd;
+
+  final int connectStart;
+
+  final int domComplete;
+
+  final int domContentLoadedEventEnd;
+
+  final int domContentLoadedEventStart;
+
+  final int domInteractive;
+
+  final int domLoading;
+
+  final int domainLookupEnd;
+
+  final int domainLookupStart;
+
+  final int fetchStart;
+
+  final int loadEventEnd;
+
+  final int loadEventStart;
+
+  final int navigationStart;
+
+  final int redirectEnd;
+
+  final int redirectStart;
+
+  final int requestStart;
+
+  final int responseEnd;
+
+  final int responseStart;
+
+  final int secureConnectionStart;
+
+  final int unloadEventEnd;
+
+  final int unloadEventStart;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("PermissionStatus")
+class PermissionStatus extends EventTarget {
+  // To suppress missing implicit constructor warnings.
+  factory PermissionStatus._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  static const EventStreamProvider<Event> changeEvent =
+      const EventStreamProvider<Event>('change');
+
+  final String state;
+
+  Stream<Event> get onChange => changeEvent.forTarget(this);
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("Permissions")
+class Permissions extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory Permissions._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  Future<PermissionStatus> query(Map permission) {
+    var permission_dict = convertDartToNative_Dictionary(permission);
+    return promiseToFuture<PermissionStatus>(
+        JS("", "#.query(#)", this, permission_dict));
+  }
+
+  Future<PermissionStatus> request(Map permissions) {
+    var permissions_dict = convertDartToNative_Dictionary(permissions);
+    return promiseToFuture<PermissionStatus>(
+        JS("", "#.request(#)", this, permissions_dict));
+  }
+
+  Future<PermissionStatus> requestAll(List<Map> permissions) =>
+      promiseToFuture<PermissionStatus>(
+          JS("", "#.requestAll(#)", this, permissions));
+
+  Future<PermissionStatus> revoke(Map permission) {
+    var permission_dict = convertDartToNative_Dictionary(permission);
+    return promiseToFuture<PermissionStatus>(
+        JS("", "#.revoke(#)", this, permission_dict));
+  }
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("PhotoCapabilities")
+class PhotoCapabilities extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory PhotoCapabilities._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final List fillLightMode;
+
+  final MediaSettingsRange imageHeight;
+
+  final MediaSettingsRange imageWidth;
+
+  final String redEyeReduction;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("HTMLPictureElement")
+class PictureElement extends HtmlElement {
+  // To suppress missing implicit constructor warnings.
+  factory PictureElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  PictureElement.created() : super.created();
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("Plugin")
+class Plugin extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory Plugin._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final String description;
+
+  final String filename;
+
+  final int length;
+
+  final String name;
+
+  MimeType item(int index) native;
+
+  MimeType namedItem(String name) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("PluginArray")
+class PluginArray extends Interceptor
+    with ListMixin<Plugin>, ImmutableListMixin<Plugin>
+    implements JavaScriptIndexingBehavior<Plugin>, List<Plugin> {
+  // To suppress missing implicit constructor warnings.
+  factory PluginArray._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  int get length => JS("int", "#.length", this);
+
+  Plugin operator [](int index) {
+    if (JS("bool", "# >>> 0 !== # || # >= #", index, index, index, length))
+      throw new RangeError.index(index, this);
+    return JS("Plugin", "#[#]", this, index);
+  }
+
+  void operator []=(int index, Plugin value) {
+    throw new UnsupportedError("Cannot assign element of immutable List.");
+  }
+  // -- start List<Plugin> mixins.
+  // Plugin is the element type.
+
+  set length(int value) {
+    throw new UnsupportedError("Cannot resize immutable List.");
+  }
+
+  Plugin get first {
+    if (this.length > 0) {
+      return JS('Plugin', '#[0]', this);
+    }
+    throw new StateError("No elements");
+  }
+
+  Plugin get last {
+    int len = this.length;
+    if (len > 0) {
+      return JS('Plugin', '#[#]', this, len - 1);
+    }
+    throw new StateError("No elements");
+  }
+
+  Plugin get single {
+    int len = this.length;
+    if (len == 1) {
+      return JS('Plugin', '#[0]', this);
+    }
+    if (len == 0) throw new StateError("No elements");
+    throw new StateError("More than one element");
+  }
+
+  Plugin elementAt(int index) => this[index];
+  // -- end List<Plugin> mixins.
+
+  Plugin item(int index) native;
+
+  Plugin namedItem(String name) native;
+
+  void refresh(bool reload) native;
+}
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+@Native("PointerEvent")
+class PointerEvent extends MouseEvent {
+  // To suppress missing implicit constructor warnings.
+  factory PointerEvent._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory PointerEvent(String type, [Map eventInitDict]) {
+    if (eventInitDict != null) {
+      var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+      return PointerEvent._create_1(type, eventInitDict_1);
+    }
+    return PointerEvent._create_2(type);
+  }
+  static PointerEvent _create_1(type, eventInitDict) =>
+      JS('PointerEvent', 'new PointerEvent(#,#)', type, eventInitDict);
+  static PointerEvent _create_2(type) =>
+      JS('PointerEvent', 'new PointerEvent(#)', type);
+
+  final num height;
+
+  final bool isPrimary;
+
+  final int pointerId;
+
+  final String pointerType;
+
+  final num pressure;
+
+  final num tangentialPressure;
+
+  final int tiltX;
+
+  final int tiltY;
+
+  final int twist;
+
+  final num width;
+
+  List<PointerEvent> getCoalescedEvents() native;
+
+  /**
+   * PointerEvent used for both touch and mouse.  To check if touch is supported
+   * call the property TouchEvent.supported
+   */
+  static bool get supported {
+    try {
+      return PointerEvent('pointerover') is PointerEvent;
+    } catch (_) {}
+    return false;
+  }
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.FIREFOX)
+@SupportedBrowser(SupportedBrowser.IE, '10')
+@SupportedBrowser(SupportedBrowser.SAFARI)
+@Native("PopStateEvent")
+class PopStateEvent extends Event {
+  // To suppress missing implicit constructor warnings.
+  factory PopStateEvent._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory PopStateEvent(String type, [Map eventInitDict]) {
+    if (eventInitDict != null) {
+      var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+      return PopStateEvent._create_1(type, eventInitDict_1);
+    }
+    return PopStateEvent._create_2(type);
+  }
+  static PopStateEvent _create_1(type, eventInitDict) =>
+      JS('PopStateEvent', 'new PopStateEvent(#,#)', type, eventInitDict);
+  static PopStateEvent _create_2(type) =>
+      JS('PopStateEvent', 'new PopStateEvent(#)', type);
+
+  dynamic get state =>
+      convertNativeToDart_SerializedScriptValue(this._get_state);
+  @JSName('state')
+  @annotation_Creates_SerializedScriptValue
+  @annotation_Returns_SerializedScriptValue
+  final dynamic _get_state;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+@Unstable()
+typedef void _PositionCallback(Geoposition position);
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("PositionError")
+class PositionError extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory PositionError._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  static const int PERMISSION_DENIED = 1;
+
+  static const int POSITION_UNAVAILABLE = 2;
+
+  static const int TIMEOUT = 3;
+
+  final int code;
+
+  final String message;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+@Unstable()
+typedef void _PositionErrorCallback(PositionError error);
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("HTMLPreElement")
+class PreElement extends HtmlElement {
+  // To suppress missing implicit constructor warnings.
+  factory PreElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory PreElement() => JS('returns:PreElement;creates:PreElement;new:true',
+      '#.createElement(#)', document, "pre");
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  PreElement.created() : super.created();
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("Presentation")
+class Presentation extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory Presentation._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  PresentationRequest defaultRequest;
+
+  final PresentationReceiver receiver;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("PresentationAvailability")
+class PresentationAvailability extends EventTarget {
+  // To suppress missing implicit constructor warnings.
+  factory PresentationAvailability._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  static const EventStreamProvider<Event> changeEvent =
+      const EventStreamProvider<Event>('change');
+
+  final bool value;
+
+  Stream<Event> get onChange => changeEvent.forTarget(this);
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("PresentationConnection")
+class PresentationConnection extends EventTarget {
+  // To suppress missing implicit constructor warnings.
+  factory PresentationConnection._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  static const EventStreamProvider<MessageEvent> messageEvent =
+      const EventStreamProvider<MessageEvent>('message');
+
+  String binaryType;
+
+  final String id;
+
+  final String state;
+
+  final String url;
+
+  void close() native;
+
+  void send(data_OR_message) native;
+
+  void terminate() native;
+
+  Stream<MessageEvent> get onMessage => messageEvent.forTarget(this);
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("PresentationConnectionAvailableEvent")
+class PresentationConnectionAvailableEvent extends Event {
+  // To suppress missing implicit constructor warnings.
+  factory PresentationConnectionAvailableEvent._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory PresentationConnectionAvailableEvent(String type, Map eventInitDict) {
+    var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+    return PresentationConnectionAvailableEvent._create_1(
+        type, eventInitDict_1);
+  }
+  static PresentationConnectionAvailableEvent _create_1(type, eventInitDict) =>
+      JS('PresentationConnectionAvailableEvent',
+          'new PresentationConnectionAvailableEvent(#,#)', type, eventInitDict);
+
+  final PresentationConnection connection;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("PresentationConnectionCloseEvent")
+class PresentationConnectionCloseEvent extends Event {
+  // To suppress missing implicit constructor warnings.
+  factory PresentationConnectionCloseEvent._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory PresentationConnectionCloseEvent(String type, Map eventInitDict) {
+    var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+    return PresentationConnectionCloseEvent._create_1(type, eventInitDict_1);
+  }
+  static PresentationConnectionCloseEvent _create_1(type, eventInitDict) => JS(
+      'PresentationConnectionCloseEvent',
+      'new PresentationConnectionCloseEvent(#,#)',
+      type,
+      eventInitDict);
+
+  final String message;
+
+  final String reason;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("PresentationConnectionList")
+class PresentationConnectionList extends EventTarget {
+  // To suppress missing implicit constructor warnings.
+  factory PresentationConnectionList._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final List<PresentationConnection> connections;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("PresentationReceiver")
+class PresentationReceiver extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory PresentationReceiver._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  Future<PresentationConnectionList> get connectionList =>
+      promiseToFuture<PresentationConnectionList>(
+          JS("", "#.connectionList", this));
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("PresentationRequest")
+class PresentationRequest extends EventTarget {
+  // To suppress missing implicit constructor warnings.
+  factory PresentationRequest._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory PresentationRequest(url_OR_urls) {
+    if ((url_OR_urls is String)) {
+      return PresentationRequest._create_1(url_OR_urls);
+    }
+    if ((url_OR_urls is List<String>)) {
+      List urls_1 = convertDartToNative_StringArray(url_OR_urls);
+      return PresentationRequest._create_2(urls_1);
+    }
+    throw new ArgumentError("Incorrect number or type of arguments");
+  }
+  static PresentationRequest _create_1(url_OR_urls) =>
+      JS('PresentationRequest', 'new PresentationRequest(#)', url_OR_urls);
+  static PresentationRequest _create_2(url_OR_urls) =>
+      JS('PresentationRequest', 'new PresentationRequest(#)', url_OR_urls);
+
+  Future<PresentationAvailability> getAvailability() =>
+      promiseToFuture<PresentationAvailability>(
+          JS("", "#.getAvailability()", this));
+
+  Future<PresentationConnection> reconnect(String id) =>
+      promiseToFuture<PresentationConnection>(
+          JS("", "#.reconnect(#)", this, id));
+
+  Future<PresentationConnection> start() =>
+      promiseToFuture<PresentationConnection>(JS("", "#.start()", this));
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("ProcessingInstruction")
+class ProcessingInstruction extends CharacterData {
+  // To suppress missing implicit constructor warnings.
+  factory ProcessingInstruction._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final StyleSheet sheet;
+
+  final String target;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.FIREFOX)
+@SupportedBrowser(SupportedBrowser.IE, '10')
+@SupportedBrowser(SupportedBrowser.SAFARI)
+@Native("HTMLProgressElement")
+class ProgressElement extends HtmlElement {
+  // To suppress missing implicit constructor warnings.
+  factory ProgressElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory ProgressElement() => document.createElement("progress");
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  ProgressElement.created() : super.created();
+
+  /// Checks if this type is supported on the current platform.
+  static bool get supported => Element.isTagSupported('progress');
+
+  @Unstable()
+  @Returns('NodeList|Null')
+  @Creates('NodeList')
+  final List<Node> labels;
+
+  num max;
+
+  final num position;
+
+  num value;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("ProgressEvent")
+class ProgressEvent extends Event {
+  // To suppress missing implicit constructor warnings.
+  factory ProgressEvent._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory ProgressEvent(String type, [Map eventInitDict]) {
+    if (eventInitDict != null) {
+      var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+      return ProgressEvent._create_1(type, eventInitDict_1);
+    }
+    return ProgressEvent._create_2(type);
+  }
+  static ProgressEvent _create_1(type, eventInitDict) =>
+      JS('ProgressEvent', 'new ProgressEvent(#,#)', type, eventInitDict);
+  static ProgressEvent _create_2(type) =>
+      JS('ProgressEvent', 'new ProgressEvent(#)', type);
+
+  final bool lengthComputable;
+
+  final int loaded;
+
+  final int total;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("PromiseRejectionEvent")
+class PromiseRejectionEvent extends Event {
+  // To suppress missing implicit constructor warnings.
+  factory PromiseRejectionEvent._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory PromiseRejectionEvent(String type, Map eventInitDict) {
+    var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+    return PromiseRejectionEvent._create_1(type, eventInitDict_1);
+  }
+  static PromiseRejectionEvent _create_1(type, eventInitDict) => JS(
+      'PromiseRejectionEvent',
+      'new PromiseRejectionEvent(#,#)',
+      type,
+      eventInitDict);
+
+  Future get promise => promiseToFuture(JS("", "#.promise", this));
+
+  final Object reason;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("PublicKeyCredential")
+class PublicKeyCredential extends Credential {
+  // To suppress missing implicit constructor warnings.
+  factory PublicKeyCredential._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final ByteBuffer rawId;
+
+  final AuthenticatorResponse response;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("PushEvent")
+class PushEvent extends ExtendableEvent {
+  // To suppress missing implicit constructor warnings.
+  factory PushEvent._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory PushEvent(String type, [Map eventInitDict]) {
+    if (eventInitDict != null) {
+      var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+      return PushEvent._create_1(type, eventInitDict_1);
+    }
+    return PushEvent._create_2(type);
+  }
+  static PushEvent _create_1(type, eventInitDict) =>
+      JS('PushEvent', 'new PushEvent(#,#)', type, eventInitDict);
+  static PushEvent _create_2(type) => JS('PushEvent', 'new PushEvent(#)', type);
+
+  final PushMessageData data;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("PushManager")
+class PushManager extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory PushManager._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  static final List<String> supportedContentEncodings;
+
+  Future<PushSubscription> getSubscription() =>
+      promiseToFuture<PushSubscription>(JS("", "#.getSubscription()", this));
+
+  Future permissionState([Map options]) {
+    var options_dict = null;
+    if (options != null) {
+      options_dict = convertDartToNative_Dictionary(options);
+    }
+    return promiseToFuture(JS("", "#.permissionState(#)", this, options_dict));
+  }
+
+  Future<PushSubscription> subscribe([Map options]) {
+    var options_dict = null;
+    if (options != null) {
+      options_dict = convertDartToNative_Dictionary(options);
+    }
+    return promiseToFuture<PushSubscription>(
+        JS("", "#.subscribe(#)", this, options_dict));
+  }
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("PushMessageData")
+class PushMessageData extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory PushMessageData._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  ByteBuffer arrayBuffer() native;
+
+  Blob blob() native;
+
+  Object json() native;
+
+  String text() native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("PushSubscription")
+class PushSubscription extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory PushSubscription._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final String endpoint;
+
+  final int expirationTime;
+
+  final PushSubscriptionOptions options;
+
+  ByteBuffer getKey(String name) native;
+
+  Future<bool> unsubscribe() =>
+      promiseToFuture<bool>(JS("", "#.unsubscribe()", this));
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("PushSubscriptionOptions")
+class PushSubscriptionOptions extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory PushSubscriptionOptions._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final ByteBuffer applicationServerKey;
+
+  final bool userVisibleOnly;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("HTMLQuoteElement")
+class QuoteElement extends HtmlElement {
+  // To suppress missing implicit constructor warnings.
+  factory QuoteElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory QuoteElement() => JS(
+      'returns:QuoteElement;creates:QuoteElement;new:true',
+      '#.createElement(#)',
+      document,
+      "q");
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  QuoteElement.created() : super.created();
+
+  String cite;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+typedef void RtcPeerConnectionErrorCallback(DomException exception);
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+typedef void _RtcSessionDescriptionCallback(RtcSessionDescription sdp);
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+typedef void RtcStatsCallback(RtcStatsResponse response);
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+@Unstable()
+@Native("Range")
+class Range extends Interceptor {
+  factory Range() => document.createRange();
+
+  factory Range.fromPoint(Point point) =>
+      document._caretRangeFromPoint(point.x, point.y);
+  // To suppress missing implicit constructor warnings.
+  factory Range._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  static const int END_TO_END = 2;
+
+  static const int END_TO_START = 3;
+
+  static const int START_TO_END = 1;
+
+  static const int START_TO_START = 0;
+
+  final bool collapsed;
+
+  final Node commonAncestorContainer;
+
+  final Node endContainer;
+
+  final int endOffset;
+
+  final Node startContainer;
+
+  final int startOffset;
+
+  DocumentFragment cloneContents() native;
+
+  Range cloneRange() native;
+
+  void collapse([bool toStart]) native;
+
+  int compareBoundaryPoints(int how, Range sourceRange) native;
+
+  int comparePoint(Node node, int offset) native;
+
+  DocumentFragment createContextualFragment(String fragment) native;
+
+  void deleteContents() native;
+
+  void detach() native;
+
+  void expand(String unit) native;
+
+  DocumentFragment extractContents() native;
+
+  Rectangle getBoundingClientRect() native;
+
+  @JSName('getClientRects')
+  @Returns('DomRectList|Null')
+  @Creates('DomRectList')
+  List<Rectangle> _getClientRects() native;
+
+  void insertNode(Node node) native;
+
+  bool isPointInRange(Node node, int offset) native;
+
+  void selectNode(Node node) native;
+
+  void selectNodeContents(Node node) native;
+
+  void setEnd(Node node, int offset) native;
+
+  void setEndAfter(Node node) native;
+
+  void setEndBefore(Node node) native;
+
+  void setStart(Node node, int offset) native;
+
+  void setStartAfter(Node node) native;
+
+  void setStartBefore(Node node) native;
+
+  void surroundContents(Node newParent) native;
+
+  List<Rectangle> getClientRects() {
+    var value = _getClientRects();
+
+    // If no prototype we need one for the world to hookup to the proper Dart class.
+    var jsProto = JS('', '#.prototype', value);
+    if (jsProto == null) {
+      JS('', '#.prototype = Object.create(null)', value);
+    }
+
+    applyExtension('DOMRectList', value);
+
+    return value;
+  }
+
+  /**
+   * Checks if createContextualFragment is supported.
+   *
+   * See also:
+   *
+   * * [createContextualFragment]
+   */
+  static bool get supportsCreateContextualFragment =>
+      JS('bool', '("createContextualFragment" in window.Range.prototype)');
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("RelatedApplication")
+class RelatedApplication extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory RelatedApplication._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final String id;
+
+  final String platform;
+
+  final String url;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("RelativeOrientationSensor")
+class RelativeOrientationSensor extends OrientationSensor {
+  // To suppress missing implicit constructor warnings.
+  factory RelativeOrientationSensor._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory RelativeOrientationSensor([Map sensorOptions]) {
+    if (sensorOptions != null) {
+      var sensorOptions_1 = convertDartToNative_Dictionary(sensorOptions);
+      return RelativeOrientationSensor._create_1(sensorOptions_1);
+    }
+    return RelativeOrientationSensor._create_2();
+  }
+  static RelativeOrientationSensor _create_1(sensorOptions) => JS(
+      'RelativeOrientationSensor',
+      'new RelativeOrientationSensor(#)',
+      sensorOptions);
+  static RelativeOrientationSensor _create_2() =>
+      JS('RelativeOrientationSensor', 'new RelativeOrientationSensor()');
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("RemotePlayback")
+class RemotePlayback extends EventTarget {
+  // To suppress missing implicit constructor warnings.
+  factory RemotePlayback._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final String state;
+
+  Future cancelWatchAvailability([int id]) =>
+      promiseToFuture(JS("", "#.cancelWatchAvailability(#)", this, id));
+
+  Future prompt() => promiseToFuture(JS("", "#.prompt()", this));
+
+  Future<int> watchAvailability(RemotePlaybackAvailabilityCallback callback) =>
+      promiseToFuture<int>(JS("", "#.watchAvailability(#)", this, callback));
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+typedef void RemotePlaybackAvailabilityCallback(bool available);
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("ReportBody")
+class ReportBody extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory ReportBody._() {
+    throw new UnsupportedError("Not supported");
+  }
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("ReportingObserver")
+class ReportingObserver extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory ReportingObserver._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory ReportingObserver(ReportingObserverCallback callback) {
+    var callback_1 = convertDartClosureToJS(callback, 2);
+    return ReportingObserver._create_1(callback_1);
+  }
+  static ReportingObserver _create_1(callback) =>
+      JS('ReportingObserver', 'new ReportingObserver(#)', callback);
+
+  void disconnect() native;
+
+  void observe() native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+typedef void ReportingObserverCallback(
+    List reports, ReportingObserver observer);
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+typedef void RequestAnimationFrameCallback(num highResTime);
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("ResizeObserver")
+class ResizeObserver extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory ResizeObserver._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory ResizeObserver(ResizeObserverCallback callback) {
+    var callback_1 = convertDartClosureToJS(callback, 2);
+    return ResizeObserver._create_1(callback_1);
+  }
+  static ResizeObserver _create_1(callback) =>
+      JS('ResizeObserver', 'new ResizeObserver(#)', callback);
+
+  void disconnect() native;
+
+  void observe(Element target) native;
+
+  void unobserve(Element target) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+typedef void ResizeObserverCallback(
+    List<ResizeObserverEntry> entries, ResizeObserver observer);
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("ResizeObserverEntry")
+class ResizeObserverEntry extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory ResizeObserverEntry._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final DomRectReadOnly contentRect;
+
+  final Element target;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("RTCCertificate")
+class RtcCertificate extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory RtcCertificate._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final int expires;
+
+  List<Map> getFingerprints() native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("RTCDataChannel,DataChannel")
+class RtcDataChannel extends EventTarget {
+  // To suppress missing implicit constructor warnings.
+  factory RtcDataChannel._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  /**
+   * Static factory designed to expose `close` events to event
+   * handlers that are not necessarily instances of [RtcDataChannel].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<Event> closeEvent =
+      const EventStreamProvider<Event>('close');
+
+  /**
+   * Static factory designed to expose `error` events to event
+   * handlers that are not necessarily instances of [RtcDataChannel].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<Event> errorEvent =
+      const EventStreamProvider<Event>('error');
+
+  /**
+   * Static factory designed to expose `message` events to event
+   * handlers that are not necessarily instances of [RtcDataChannel].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<MessageEvent> messageEvent =
+      const EventStreamProvider<MessageEvent>('message');
+
+  /**
+   * Static factory designed to expose `open` events to event
+   * handlers that are not necessarily instances of [RtcDataChannel].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<Event> openEvent =
+      const EventStreamProvider<Event>('open');
+
+  String binaryType;
+
+  final int bufferedAmount;
+
+  int bufferedAmountLowThreshold;
+
+  final int id;
+
+  final String label;
+
+  final int maxRetransmitTime;
+
+  final int maxRetransmits;
+
+  final bool negotiated;
+
+  final bool ordered;
+
+  final String protocol;
+
+  final String readyState;
+
+  final bool reliable;
+
+  void close() native;
+
+  void send(data) native;
+
+  @JSName('send')
+  void sendBlob(Blob data) native;
+
+  @JSName('send')
+  void sendByteBuffer(ByteBuffer data) native;
+
+  @JSName('send')
+  void sendString(String data) native;
+
+  @JSName('send')
+  void sendTypedData(TypedData data) native;
+
+  /// Stream of `close` events handled by this [RtcDataChannel].
+  Stream<Event> get onClose => closeEvent.forTarget(this);
+
+  /// Stream of `error` events handled by this [RtcDataChannel].
+  Stream<Event> get onError => errorEvent.forTarget(this);
+
+  /// Stream of `message` events handled by this [RtcDataChannel].
+  Stream<MessageEvent> get onMessage => messageEvent.forTarget(this);
+
+  /// Stream of `open` events handled by this [RtcDataChannel].
+  Stream<Event> get onOpen => openEvent.forTarget(this);
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("RTCDataChannelEvent")
+class RtcDataChannelEvent extends Event {
+  // To suppress missing implicit constructor warnings.
+  factory RtcDataChannelEvent._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory RtcDataChannelEvent(String type, Map eventInitDict) {
+    var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+    return RtcDataChannelEvent._create_1(type, eventInitDict_1);
+  }
+  static RtcDataChannelEvent _create_1(type, eventInitDict) => JS(
+      'RtcDataChannelEvent',
+      'new RTCDataChannelEvent(#,#)',
+      type,
+      eventInitDict);
+
+  final RtcDataChannel channel;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("RTCDTMFSender")
+class RtcDtmfSender extends EventTarget {
+  // To suppress missing implicit constructor warnings.
+  factory RtcDtmfSender._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  /**
+   * Static factory designed to expose `tonechange` events to event
+   * handlers that are not necessarily instances of [RtcDtmfSender].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<RtcDtmfToneChangeEvent> toneChangeEvent =
+      const EventStreamProvider<RtcDtmfToneChangeEvent>('tonechange');
+
+  @JSName('canInsertDTMF')
+  final bool canInsertDtmf;
+
+  final int duration;
+
+  final int interToneGap;
+
+  final String toneBuffer;
+
+  final MediaStreamTrack track;
+
+  @JSName('insertDTMF')
+  void insertDtmf(String tones, [int duration, int interToneGap]) native;
+
+  /// Stream of `tonechange` events handled by this [RtcDtmfSender].
+  Stream<RtcDtmfToneChangeEvent> get onToneChange =>
+      toneChangeEvent.forTarget(this);
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("RTCDTMFToneChangeEvent")
+class RtcDtmfToneChangeEvent extends Event {
+  // To suppress missing implicit constructor warnings.
+  factory RtcDtmfToneChangeEvent._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory RtcDtmfToneChangeEvent(String type, Map eventInitDict) {
+    var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+    return RtcDtmfToneChangeEvent._create_1(type, eventInitDict_1);
+  }
+  static RtcDtmfToneChangeEvent _create_1(type, eventInitDict) => JS(
+      'RtcDtmfToneChangeEvent',
+      'new RTCDTMFToneChangeEvent(#,#)',
+      type,
+      eventInitDict);
+
+  final String tone;
+}
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@Native("RTCIceCandidate,mozRTCIceCandidate")
+class RtcIceCandidate extends Interceptor {
+  factory RtcIceCandidate(Map dictionary) {
+    // TODO(efortuna): Remove this check if when you can actually construct with
+    // the unprefixed RTCIceCandidate in Firefox (currently both are defined,
+    // but one can't be used as a constructor).
+    var constructorName = JS(
+        '',
+        'window[#]',
+        Device.isFirefox
+            ? '${Device.propertyPrefix}RTCIceCandidate'
+            : 'RTCIceCandidate');
+    return JS('RtcIceCandidate', 'new #(#)', constructorName,
+        convertDartToNative_SerializedScriptValue(dictionary));
+  }
+  // To suppress missing implicit constructor warnings.
+  factory RtcIceCandidate._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  String candidate;
+
+  int sdpMLineIndex;
+
+  String sdpMid;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("RTCLegacyStatsReport")
+class RtcLegacyStatsReport extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory RtcLegacyStatsReport._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final String id;
+
+  DateTime get timestamp => convertNativeToDart_DateTime(this._get_timestamp);
+  @JSName('timestamp')
+  final dynamic _get_timestamp;
+
+  final String type;
+
+  List<String> names() native;
+
+  String stat(String name) native;
+}
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@Native("RTCPeerConnection,webkitRTCPeerConnection,mozRTCPeerConnection")
+class RtcPeerConnection extends EventTarget {
+  factory RtcPeerConnection(Map rtcIceServers, [Map mediaConstraints]) {
+    var constructorName = JS('RtcPeerConnection', 'window[#]',
+        '${Device.propertyPrefix}RTCPeerConnection');
+    if (mediaConstraints != null) {
+      return JS(
+          'RtcPeerConnection',
+          'new #(#,#)',
+          constructorName,
+          convertDartToNative_SerializedScriptValue(rtcIceServers),
+          convertDartToNative_SerializedScriptValue(mediaConstraints));
+    } else {
+      return JS('RtcPeerConnection', 'new #(#)', constructorName,
+          convertDartToNative_SerializedScriptValue(rtcIceServers));
+    }
+  }
+
+  /**
+   * Checks if Real Time Communication (RTC) APIs are supported and enabled on
+   * the current platform.
+   */
+  static bool get supported {
+    // Currently in Firefox some of the RTC elements are defined but throw an
+    // error unless the user has specifically enabled them in their
+    // about:config. So we have to construct an element to actually test if RTC
+    // is supported at the given time.
+    try {
+      new RtcPeerConnection({
+        "iceServers": [
+          {"url": "stun:localhost"}
+        ]
+      });
+      return true;
+    } catch (_) {
+      return false;
+    }
+    return false;
+  }
+
+  /**
+  * Temporarily exposes _getStats and old getStats as getLegacyStats until Chrome fully supports
+  * new getStats API.
+  */
+  Future<RtcStatsResponse> getLegacyStats([MediaStreamTrack selector]) {
+    var completer = new Completer<RtcStatsResponse>();
+    _getStats((value) {
+      completer.complete(value);
+    }, selector);
+    return completer.future;
+  }
+
+  @JSName('getStats')
+  Future _getStats(
+      [RtcStatsCallback successCallback, MediaStreamTrack selector]) native;
+
+  static Future generateCertificate(/*AlgorithmIdentifier*/ keygenAlgorithm) =>
+      JS('dynamic', 'generateCertificate(#)', keygenAlgorithm);
+
+  // To suppress missing implicit constructor warnings.
+  factory RtcPeerConnection._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  /**
+   * Static factory designed to expose `addstream` events to event
+   * handlers that are not necessarily instances of [RtcPeerConnection].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<MediaStreamEvent> addStreamEvent =
+      const EventStreamProvider<MediaStreamEvent>('addstream');
+
+  /**
+   * Static factory designed to expose `datachannel` events to event
+   * handlers that are not necessarily instances of [RtcPeerConnection].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<RtcDataChannelEvent> dataChannelEvent =
+      const EventStreamProvider<RtcDataChannelEvent>('datachannel');
+
+  /**
+   * Static factory designed to expose `icecandidate` events to event
+   * handlers that are not necessarily instances of [RtcPeerConnection].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<RtcPeerConnectionIceEvent>
+      iceCandidateEvent =
+      const EventStreamProvider<RtcPeerConnectionIceEvent>('icecandidate');
+
+  /**
+   * Static factory designed to expose `iceconnectionstatechange` events to event
+   * handlers that are not necessarily instances of [RtcPeerConnection].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<Event> iceConnectionStateChangeEvent =
+      const EventStreamProvider<Event>('iceconnectionstatechange');
+
+  /**
+   * Static factory designed to expose `negotiationneeded` events to event
+   * handlers that are not necessarily instances of [RtcPeerConnection].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<Event> negotiationNeededEvent =
+      const EventStreamProvider<Event>('negotiationneeded');
+
+  /**
+   * Static factory designed to expose `removestream` events to event
+   * handlers that are not necessarily instances of [RtcPeerConnection].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<MediaStreamEvent> removeStreamEvent =
+      const EventStreamProvider<MediaStreamEvent>('removestream');
+
+  /**
+   * Static factory designed to expose `signalingstatechange` events to event
+   * handlers that are not necessarily instances of [RtcPeerConnection].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<Event> signalingStateChangeEvent =
+      const EventStreamProvider<Event>('signalingstatechange');
+
+  final String iceConnectionState;
+
+  final String iceGatheringState;
+
+  final RtcSessionDescription localDescription;
+
+  final RtcSessionDescription remoteDescription;
+
+  final String signalingState;
+
+  Future addIceCandidate(Object candidate,
+          [VoidCallback successCallback,
+          RtcPeerConnectionErrorCallback failureCallback]) =>
+      promiseToFuture(JS("", "#.addIceCandidate(#, #, #)", this, candidate,
+          successCallback, failureCallback));
+
+  void addStream(MediaStream stream, [Map mediaConstraints]) {
+    if (mediaConstraints != null) {
+      var mediaConstraints_1 = convertDartToNative_Dictionary(mediaConstraints);
+      _addStream_1(stream, mediaConstraints_1);
+      return;
+    }
+    _addStream_2(stream);
+    return;
+  }
+
+  @JSName('addStream')
+  void _addStream_1(MediaStream stream, mediaConstraints) native;
+  @JSName('addStream')
+  void _addStream_2(MediaStream stream) native;
+
+  RtcRtpSender addTrack(MediaStreamTrack track, MediaStream streams) native;
+
+  void close() native;
+
+  Future<RtcSessionDescription> createAnswer([Map options]) {
+    var options_dict = null;
+    if (options != null) {
+      options_dict = convertDartToNative_Dictionary(options);
+    }
+    return promiseToFuture<RtcSessionDescription>(
+        JS("", "#.createAnswer(#)", this, options_dict));
+  }
+
+  @JSName('createDTMFSender')
+  RtcDtmfSender createDtmfSender(MediaStreamTrack track) native;
+
+  RtcDataChannel createDataChannel(String label, [Map dataChannelDict]) {
+    if (dataChannelDict != null) {
+      var dataChannelDict_1 = convertDartToNative_Dictionary(dataChannelDict);
+      return _createDataChannel_1(label, dataChannelDict_1);
+    }
+    return _createDataChannel_2(label);
+  }
+
+  @JSName('createDataChannel')
+  RtcDataChannel _createDataChannel_1(label, dataChannelDict) native;
+  @JSName('createDataChannel')
+  RtcDataChannel _createDataChannel_2(label) native;
+
+  Future<RtcSessionDescription> createOffer([Map options]) {
+    var options_dict = null;
+    if (options != null) {
+      options_dict = convertDartToNative_Dictionary(options);
+    }
+    return promiseToFuture<RtcSessionDescription>(
+        JS("", "#.createOffer(#)", this, options_dict));
+  }
+
+  List<MediaStream> getLocalStreams() native;
+
+  List<RtcRtpReceiver> getReceivers() native;
+
+  List<MediaStream> getRemoteStreams() native;
+
+  List<RtcRtpSender> getSenders() native;
+
+  Future<RtcStatsReport> getStats() =>
+      promiseToFuture<RtcStatsReport>(JS("", "#.getStats()", this));
+
+  void removeStream(MediaStream stream) native;
+
+  void removeTrack(RtcRtpSender sender) native;
+
+  void setConfiguration(Map configuration) {
+    var configuration_1 = convertDartToNative_Dictionary(configuration);
+    _setConfiguration_1(configuration_1);
+    return;
+  }
+
+  @JSName('setConfiguration')
+  void _setConfiguration_1(configuration) native;
+
+  Future setLocalDescription(Map description) {
+    var description_dict = convertDartToNative_Dictionary(description);
+    return promiseToFuture(
+        JS("", "#.setLocalDescription(#)", this, description_dict));
+  }
+
+  Future setRemoteDescription(Map description) {
+    var description_dict = convertDartToNative_Dictionary(description);
+    return promiseToFuture(
+        JS("", "#.setRemoteDescription(#)", this, description_dict));
+  }
+
+  /// Stream of `addstream` events handled by this [RtcPeerConnection].
+  Stream<MediaStreamEvent> get onAddStream => addStreamEvent.forTarget(this);
+
+  /// Stream of `datachannel` events handled by this [RtcPeerConnection].
+  Stream<RtcDataChannelEvent> get onDataChannel =>
+      dataChannelEvent.forTarget(this);
+
+  /// Stream of `icecandidate` events handled by this [RtcPeerConnection].
+  Stream<RtcPeerConnectionIceEvent> get onIceCandidate =>
+      iceCandidateEvent.forTarget(this);
+
+  /// Stream of `iceconnectionstatechange` events handled by this [RtcPeerConnection].
+  Stream<Event> get onIceConnectionStateChange =>
+      iceConnectionStateChangeEvent.forTarget(this);
+
+  /// Stream of `negotiationneeded` events handled by this [RtcPeerConnection].
+  Stream<Event> get onNegotiationNeeded =>
+      negotiationNeededEvent.forTarget(this);
+
+  /// Stream of `removestream` events handled by this [RtcPeerConnection].
+  Stream<MediaStreamEvent> get onRemoveStream =>
+      removeStreamEvent.forTarget(this);
+
+  /// Stream of `signalingstatechange` events handled by this [RtcPeerConnection].
+  Stream<Event> get onSignalingStateChange =>
+      signalingStateChangeEvent.forTarget(this);
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("RTCPeerConnectionIceEvent")
+class RtcPeerConnectionIceEvent extends Event {
+  // To suppress missing implicit constructor warnings.
+  factory RtcPeerConnectionIceEvent._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory RtcPeerConnectionIceEvent(String type, [Map eventInitDict]) {
+    if (eventInitDict != null) {
+      var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+      return RtcPeerConnectionIceEvent._create_1(type, eventInitDict_1);
+    }
+    return RtcPeerConnectionIceEvent._create_2(type);
+  }
+  static RtcPeerConnectionIceEvent _create_1(type, eventInitDict) => JS(
+      'RtcPeerConnectionIceEvent',
+      'new RTCPeerConnectionIceEvent(#,#)',
+      type,
+      eventInitDict);
+  static RtcPeerConnectionIceEvent _create_2(type) =>
+      JS('RtcPeerConnectionIceEvent', 'new RTCPeerConnectionIceEvent(#)', type);
+
+  final RtcIceCandidate candidate;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("RTCRtpContributingSource")
+class RtcRtpContributingSource extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory RtcRtpContributingSource._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final int source;
+
+  final num timestamp;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("RTCRtpReceiver")
+class RtcRtpReceiver extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory RtcRtpReceiver._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final MediaStreamTrack track;
+
+  List<RtcRtpContributingSource> getContributingSources() native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("RTCRtpSender")
+class RtcRtpSender extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory RtcRtpSender._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final MediaStreamTrack track;
+}
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@Native("RTCSessionDescription,mozRTCSessionDescription")
+class RtcSessionDescription extends Interceptor {
+  factory RtcSessionDescription(Map dictionary) {
+    // TODO(efortuna): Remove this check if when you can actually construct with
+    // the unprefixed RTCIceCandidate in Firefox (currently both are defined,
+    // but one can't be used as a constructor).
+    var constructorName = JS(
+        '',
+        'window[#]',
+        Device.isFirefox
+            ? '${Device.propertyPrefix}RTCSessionDescription'
+            : 'RTCSessionDescription');
+    return JS('RtcSessionDescription', 'new #(#)', constructorName,
+        convertDartToNative_SerializedScriptValue(dictionary));
+  }
+  // To suppress missing implicit constructor warnings.
+  factory RtcSessionDescription._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  String sdp;
+
+  String type;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("RTCStatsReport")
+class RtcStatsReport extends Interceptor with MapMixin<String, dynamic> {
+  // To suppress missing implicit constructor warnings.
+  factory RtcStatsReport._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  Map _getItem(String key) =>
+      convertNativeToDart_Dictionary(JS('', '#.get(#)', this, key));
+
+  void addAll(Map<String, dynamic> other) {
+    throw new UnsupportedError("Not supported");
+  }
+
+  bool containsValue(dynamic value) => values.any((e) => e == value);
+
+  bool containsKey(dynamic key) => _getItem(key) != null;
+
+  Map operator [](dynamic key) => _getItem(key);
+
+  void forEach(void f(String key, dynamic value)) {
+    var entries = JS('', '#.entries()', this);
+    while (true) {
+      var entry = JS('', '#.next()', entries);
+      if (JS('bool', '#.done', entry)) return;
+      f(JS('String', '#.value[0]', entry),
+          convertNativeToDart_Dictionary(JS('', '#.value[1]', entry)));
+    }
+  }
+
+  Iterable<String> get keys {
+    final keys = <String>[];
+    forEach((k, v) => keys.add(k));
+    return keys;
+  }
+
+  Iterable<Map> get values {
+    final values = <Map>[];
+    forEach((k, v) => values.add(v));
+    return values;
+  }
+
+  int get length => JS('int', '#.size', this);
+
+  bool get isEmpty => length == 0;
+
+  bool get isNotEmpty => !isEmpty;
+
+  void operator []=(String key, dynamic value) {
+    throw new UnsupportedError("Not supported");
+  }
+
+  dynamic putIfAbsent(String key, dynamic ifAbsent()) {
+    throw new UnsupportedError("Not supported");
+  }
+
+  String remove(dynamic key) {
+    throw new UnsupportedError("Not supported");
+  }
+
+  void clear() {
+    throw new UnsupportedError("Not supported");
+  }
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("RTCStatsResponse")
+class RtcStatsResponse extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory RtcStatsResponse._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  RtcLegacyStatsReport namedItem(String name) native;
+
+  List<RtcLegacyStatsReport> result() native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("RTCTrackEvent")
+class RtcTrackEvent extends Event {
+  // To suppress missing implicit constructor warnings.
+  factory RtcTrackEvent._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory RtcTrackEvent(String type, Map eventInitDict) {
+    var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+    return RtcTrackEvent._create_1(type, eventInitDict_1);
+  }
+  static RtcTrackEvent _create_1(type, eventInitDict) =>
+      JS('RtcTrackEvent', 'new RTCTrackEvent(#,#)', type, eventInitDict);
+
+  final RtcRtpReceiver receiver;
+
+  final List<MediaStream> streams;
+
+  final MediaStreamTrack track;
+}
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("Screen")
+class Screen extends Interceptor {
+  Rectangle get available =>
+      new Rectangle(_availLeft, _availTop, _availWidth, _availHeight);
+  // To suppress missing implicit constructor warnings.
+  factory Screen._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  @JSName('availHeight')
+  final int _availHeight;
+
+  @JSName('availLeft')
+  final int _availLeft;
+
+  @JSName('availTop')
+  final int _availTop;
+
+  @JSName('availWidth')
+  final int _availWidth;
+
+  final int colorDepth;
+
+  final int height;
+
+  bool keepAwake;
+
+  final ScreenOrientation orientation;
+
+  final int pixelDepth;
+
+  final int width;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("ScreenOrientation")
+class ScreenOrientation extends EventTarget {
+  // To suppress missing implicit constructor warnings.
+  factory ScreenOrientation._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  static const EventStreamProvider<Event> changeEvent =
+      const EventStreamProvider<Event>('change');
+
+  final int angle;
+
+  final String type;
+
+  Future lock(String orientation) =>
+      promiseToFuture(JS("", "#.lock(#)", this, orientation));
+
+  void unlock() native;
+
+  Stream<Event> get onChange => changeEvent.forTarget(this);
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("HTMLScriptElement")
+class ScriptElement extends HtmlElement {
+  // To suppress missing implicit constructor warnings.
+  factory ScriptElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory ScriptElement() => JS(
+      'returns:ScriptElement;creates:ScriptElement;new:true',
+      '#.createElement(#)',
+      document,
+      "script");
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  ScriptElement.created() : super.created();
+
+  bool async;
+
+  String charset;
+
+  String crossOrigin;
+
+  bool defer;
+
+  String integrity;
+
+  bool noModule;
+
+  String src;
+
+  String type;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("ScrollState")
+class ScrollState extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory ScrollState._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory ScrollState([Map scrollStateInit]) {
+    if (scrollStateInit != null) {
+      var scrollStateInit_1 = convertDartToNative_Dictionary(scrollStateInit);
+      return ScrollState._create_1(scrollStateInit_1);
+    }
+    return ScrollState._create_2();
+  }
+  static ScrollState _create_1(scrollStateInit) =>
+      JS('ScrollState', 'new ScrollState(#)', scrollStateInit);
+  static ScrollState _create_2() => JS('ScrollState', 'new ScrollState()');
+
+  final num deltaGranularity;
+
+  final num deltaX;
+
+  final num deltaY;
+
+  final bool fromUserInput;
+
+  final bool inInertialPhase;
+
+  final bool isBeginning;
+
+  final bool isDirectManipulation;
+
+  final bool isEnding;
+
+  final int positionX;
+
+  final int positionY;
+
+  final num velocityX;
+
+  final num velocityY;
+
+  void consumeDelta(num x, num y) native;
+
+  void distributeToScrollChainDescendant() native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+typedef void ScrollStateCallback(ScrollState scrollState);
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("ScrollTimeline")
+class ScrollTimeline extends AnimationTimeline {
+  // To suppress missing implicit constructor warnings.
+  factory ScrollTimeline._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory ScrollTimeline([Map options]) {
+    if (options != null) {
+      var options_1 = convertDartToNative_Dictionary(options);
+      return ScrollTimeline._create_1(options_1);
+    }
+    return ScrollTimeline._create_2();
+  }
+  static ScrollTimeline _create_1(options) =>
+      JS('ScrollTimeline', 'new ScrollTimeline(#)', options);
+  static ScrollTimeline _create_2() =>
+      JS('ScrollTimeline', 'new ScrollTimeline()');
+
+  final String orientation;
+
+  final Element scrollSource;
+
+  final Object timeRange;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("SecurityPolicyViolationEvent")
+class SecurityPolicyViolationEvent extends Event {
+  // To suppress missing implicit constructor warnings.
+  factory SecurityPolicyViolationEvent._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory SecurityPolicyViolationEvent(String type, [Map eventInitDict]) {
+    if (eventInitDict != null) {
+      var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+      return SecurityPolicyViolationEvent._create_1(type, eventInitDict_1);
+    }
+    return SecurityPolicyViolationEvent._create_2(type);
+  }
+  static SecurityPolicyViolationEvent _create_1(type, eventInitDict) => JS(
+      'SecurityPolicyViolationEvent',
+      'new SecurityPolicyViolationEvent(#,#)',
+      type,
+      eventInitDict);
+  static SecurityPolicyViolationEvent _create_2(type) => JS(
+      'SecurityPolicyViolationEvent',
+      'new SecurityPolicyViolationEvent(#)',
+      type);
+
+  @JSName('blockedURI')
+  final String blockedUri;
+
+  final int columnNumber;
+
+  final String disposition;
+
+  @JSName('documentURI')
+  final String documentUri;
+
+  final String effectiveDirective;
+
+  final int lineNumber;
+
+  final String originalPolicy;
+
+  final String referrer;
+
+  final String sample;
+
+  final String sourceFile;
+
+  final int statusCode;
+
+  final String violatedDirective;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("HTMLSelectElement")
+class SelectElement extends HtmlElement {
+  // To suppress missing implicit constructor warnings.
+  factory SelectElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory SelectElement() => JS(
+      'returns:SelectElement;creates:SelectElement;new:true',
+      '#.createElement(#)',
+      document,
+      "select");
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  SelectElement.created() : super.created();
+
+  bool autofocus;
+
+  bool disabled;
+
+  final FormElement form;
+
+  @Unstable()
+  @Returns('NodeList|Null')
+  @Creates('NodeList')
+  final List<Node> labels;
+
+  int length;
+
+  bool multiple;
+
+  String name;
+
+  bool required;
+
+  int selectedIndex;
+
+  int size;
+
+  final String type;
+
+  final String validationMessage;
+
+  final ValidityState validity;
+
+  String value;
+
+  final bool willValidate;
+
+  void __setter__(int index, OptionElement option) native;
+
+  void add(Object element, Object before) native;
+
+  bool checkValidity() native;
+
+  Element item(int index) native;
+
+  OptionElement namedItem(String name) native;
+
+  bool reportValidity() native;
+
+  void setCustomValidity(String error) native;
+
+  // Override default options, since IE returns SelectElement itself and it
+  // does not operate as a List.
+  List<OptionElement> get options {
+    dynamic options = this.querySelectorAll<OptionElement>('option');
+    return new UnmodifiableListView(options.toList());
+  }
+
+  List<OptionElement> get selectedOptions {
+    // IE does not change the selected flag for single-selection items.
+    if (this.multiple) {
+      var options = this.options.where((o) => o.selected).toList();
+      return new UnmodifiableListView(options);
+    } else {
+      return [this.options[this.selectedIndex]];
+    }
+  }
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("Selection")
+class Selection extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory Selection._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final Node anchorNode;
+
+  final int anchorOffset;
+
+  final Node baseNode;
+
+  final int baseOffset;
+
+  final Node extentNode;
+
+  final int extentOffset;
+
+  final Node focusNode;
+
+  final int focusOffset;
+
+  final bool isCollapsed;
+
+  final int rangeCount;
+
+  final String type;
+
+  void addRange(Range range) native;
+
+  void collapse(Node node, [int offset]) native;
+
+  void collapseToEnd() native;
+
+  void collapseToStart() native;
+
+  bool containsNode(Node node, [bool allowPartialContainment]) native;
+
+  void deleteFromDocument() native;
+
+  void empty() native;
+
+  void extend(Node node, [int offset]) native;
+
+  Range getRangeAt(int index) native;
+
+  void modify(String alter, String direction, String granularity) native;
+
+  void removeAllRanges() native;
+
+  void removeRange(Range range) native;
+
+  void selectAllChildren(Node node) native;
+
+  void setBaseAndExtent(
+      Node baseNode, int baseOffset, Node extentNode, int extentOffset) native;
+
+  void setPosition(Node node, [int offset]) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("Sensor")
+class Sensor extends EventTarget {
+  // To suppress missing implicit constructor warnings.
+  factory Sensor._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  static const EventStreamProvider<Event> errorEvent =
+      const EventStreamProvider<Event>('error');
+
+  final bool activated;
+
+  final bool hasReading;
+
+  final num timestamp;
+
+  void start() native;
+
+  void stop() native;
+
+  Stream<Event> get onError => errorEvent.forTarget(this);
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("SensorErrorEvent")
+class SensorErrorEvent extends Event {
+  // To suppress missing implicit constructor warnings.
+  factory SensorErrorEvent._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory SensorErrorEvent(String type, Map eventInitDict) {
+    var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+    return SensorErrorEvent._create_1(type, eventInitDict_1);
+  }
+  static SensorErrorEvent _create_1(type, eventInitDict) =>
+      JS('SensorErrorEvent', 'new SensorErrorEvent(#,#)', type, eventInitDict);
+
+  final DomException error;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("ServiceWorker")
+class ServiceWorker extends EventTarget implements AbstractWorker {
+  // To suppress missing implicit constructor warnings.
+  factory ServiceWorker._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  static const EventStreamProvider<Event> errorEvent =
+      const EventStreamProvider<Event>('error');
+
+  @JSName('scriptURL')
+  final String scriptUrl;
+
+  final String state;
+
+  void postMessage(/*any*/ message, [List<Object> transfer]) {
+    if (transfer != null) {
+      var message_1 = convertDartToNative_SerializedScriptValue(message);
+      _postMessage_1(message_1, transfer);
+      return;
+    }
+    var message_1 = convertDartToNative_SerializedScriptValue(message);
+    _postMessage_2(message_1);
+    return;
+  }
+
+  @JSName('postMessage')
+  void _postMessage_1(message, List<Object> transfer) native;
+  @JSName('postMessage')
+  void _postMessage_2(message) native;
+
+  Stream<Event> get onError => errorEvent.forTarget(this);
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("ServiceWorkerContainer")
+class ServiceWorkerContainer extends EventTarget {
+  // To suppress missing implicit constructor warnings.
+  factory ServiceWorkerContainer._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  static const EventStreamProvider<MessageEvent> messageEvent =
+      const EventStreamProvider<MessageEvent>('message');
+
+  final ServiceWorker controller;
+
+  Future<ServiceWorkerRegistration> get ready =>
+      promiseToFuture<ServiceWorkerRegistration>(JS("", "#.ready", this));
+
+  Future<ServiceWorkerRegistration> getRegistration([String documentURL]) =>
+      promiseToFuture<ServiceWorkerRegistration>(
+          JS("", "#.getRegistration(#)", this, documentURL));
+
+  Future<List<ServiceWorkerRegistration>> getRegistrations() =>
+      promiseToFuture<List<ServiceWorkerRegistration>>(
+          JS("", "#.getRegistrations()", this));
+
+  Future<ServiceWorkerRegistration> register(String url, [Map options]) {
+    var options_dict = null;
+    if (options != null) {
+      options_dict = convertDartToNative_Dictionary(options);
+    }
+    return promiseToFuture<ServiceWorkerRegistration>(
+        JS("", "#.register(#, #)", this, url, options_dict));
+  }
+
+  Stream<MessageEvent> get onMessage => messageEvent.forTarget(this);
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("ServiceWorkerGlobalScope")
+class ServiceWorkerGlobalScope extends WorkerGlobalScope {
+  // To suppress missing implicit constructor warnings.
+  factory ServiceWorkerGlobalScope._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  static const EventStreamProvider<Event> activateEvent =
+      const EventStreamProvider<Event>('activate');
+
+  static const EventStreamProvider<Event> fetchEvent =
+      const EventStreamProvider<Event>('fetch');
+
+  static const EventStreamProvider<ForeignFetchEvent> foreignfetchEvent =
+      const EventStreamProvider<ForeignFetchEvent>('foreignfetch');
+
+  static const EventStreamProvider<Event> installEvent =
+      const EventStreamProvider<Event>('install');
+
+  static const EventStreamProvider<MessageEvent> messageEvent =
+      const EventStreamProvider<MessageEvent>('message');
+
+  final Clients clients;
+
+  final ServiceWorkerRegistration registration;
+
+  Future skipWaiting() => promiseToFuture(JS("", "#.skipWaiting()", this));
+
+  Stream<Event> get onActivate => activateEvent.forTarget(this);
+
+  Stream<Event> get onFetch => fetchEvent.forTarget(this);
+
+  Stream<ForeignFetchEvent> get onForeignfetch =>
+      foreignfetchEvent.forTarget(this);
+
+  Stream<Event> get onInstall => installEvent.forTarget(this);
+
+  Stream<MessageEvent> get onMessage => messageEvent.forTarget(this);
+
+  static ServiceWorkerGlobalScope get instance {
+    return _workerSelf as ServiceWorkerGlobalScope;
+  }
+}
+
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("ServiceWorkerRegistration")
+class ServiceWorkerRegistration extends EventTarget {
+  // To suppress missing implicit constructor warnings.
+  factory ServiceWorkerRegistration._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final ServiceWorker active;
+
+  final BackgroundFetchManager backgroundFetch;
+
+  final ServiceWorker installing;
+
+  final NavigationPreloadManager navigationPreload;
+
+  final PaymentManager paymentManager;
+
+  final PushManager pushManager;
+
+  final String scope;
+
+  final SyncManager sync;
+
+  final ServiceWorker waiting;
+
+  Future<List<Notification>> getNotifications([Map filter]) {
+    var filter_dict = null;
+    if (filter != null) {
+      filter_dict = convertDartToNative_Dictionary(filter);
+    }
+    return promiseToFuture<List<Notification>>(
+        JS("", "#.getNotifications(#)", this, filter_dict));
+  }
+
+  Future showNotification(String title, [Map options]) {
+    var options_dict = null;
+    if (options != null) {
+      options_dict = convertDartToNative_Dictionary(options);
+    }
+    return promiseToFuture(
+        JS("", "#.showNotification(#, #)", this, title, options_dict));
+  }
+
+  Future<bool> unregister() =>
+      promiseToFuture<bool>(JS("", "#.unregister()", this));
+
+  Future update() => promiseToFuture(JS("", "#.update()", this));
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME, '26')
+@Native("HTMLShadowElement")
+class ShadowElement extends HtmlElement {
+  // To suppress missing implicit constructor warnings.
+  factory ShadowElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory ShadowElement() => document.createElement("shadow");
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  ShadowElement.created() : super.created();
+
+  /// Checks if this type is supported on the current platform.
+  static bool get supported => Element.isTagSupported('shadow');
+
+  @Returns('NodeList|Null')
+  @Creates('NodeList')
+  List<Node> getDistributedNodes() native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+@SupportedBrowser(SupportedBrowser.CHROME, '26')
+@Native("ShadowRoot")
+class ShadowRoot extends DocumentFragment implements DocumentOrShadowRoot {
+  // To suppress missing implicit constructor warnings.
+  factory ShadowRoot._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final bool delegatesFocus;
+
+  final Element host;
+
+  @JSName('innerHTML')
+  String innerHtml;
+
+  final String mode;
+
+  final ShadowRoot olderShadowRoot;
+
+  // From DocumentOrShadowRoot
+
+  final Element activeElement;
+
+  final Element fullscreenElement;
+
+  final Element pointerLockElement;
+
+  @Returns('_StyleSheetList|Null')
+  @Creates('_StyleSheetList')
+  final List<StyleSheet> styleSheets;
+
+  Element elementFromPoint(int x, int y) native;
+
+  List<Element> elementsFromPoint(int x, int y) native;
+
+  Selection getSelection() native;
+
+  static bool get supported => JS(
+      'bool',
+      '!!(Element.prototype.createShadowRoot||'
+          'Element.prototype.webkitCreateShadowRoot)');
+
+  static bool _shadowRootDeprecationReported = false;
+  static void _shadowRootDeprecationReport() {
+    if (!_shadowRootDeprecationReported) {
+      window.console.warn('''
+ShadowRoot.resetStyleInheritance and ShadowRoot.applyAuthorStyles now deprecated in dart:html.
+Please remove them from your code.
+''');
+      _shadowRootDeprecationReported = true;
+    }
+  }
+
+  @deprecated
+  bool get resetStyleInheritance {
+    _shadowRootDeprecationReport();
+    // Default value from when it was specified.
+    return false;
+  }
+
+  @deprecated
+  set resetStyleInheritance(bool value) {
+    _shadowRootDeprecationReport();
+  }
+
+  @deprecated
+  bool get applyAuthorStyles {
+    _shadowRootDeprecationReport();
+    // Default value from when it was specified.
+    return false;
+  }
+
+  @deprecated
+  set applyAuthorStyles(bool value) {
+    _shadowRootDeprecationReport();
+  }
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("SharedArrayBuffer")
+class SharedArrayBuffer extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory SharedArrayBuffer._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final int byteLength;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("SharedWorker")
+class SharedWorker extends EventTarget implements AbstractWorker {
+  // To suppress missing implicit constructor warnings.
+  factory SharedWorker._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  static const EventStreamProvider<Event> errorEvent =
+      const EventStreamProvider<Event>('error');
+
+  factory SharedWorker(String scriptURL, [String name]) {
+    if (name != null) {
+      return SharedWorker._create_1(scriptURL, name);
+    }
+    return SharedWorker._create_2(scriptURL);
+  }
+  static SharedWorker _create_1(scriptURL, name) =>
+      JS('SharedWorker', 'new SharedWorker(#,#)', scriptURL, name);
+  static SharedWorker _create_2(scriptURL) =>
+      JS('SharedWorker', 'new SharedWorker(#)', scriptURL);
+
+  final MessagePort port;
+
+  Stream<Event> get onError => errorEvent.forTarget(this);
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("SharedWorkerGlobalScope")
+class SharedWorkerGlobalScope extends WorkerGlobalScope {
+  // To suppress missing implicit constructor warnings.
+  factory SharedWorkerGlobalScope._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  /**
+   * Static factory designed to expose `connect` events to event
+   * handlers that are not necessarily instances of [SharedWorkerGlobalScope].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<Event> connectEvent =
+      const EventStreamProvider<Event>('connect');
+
+  static const int PERSISTENT = 1;
+
+  static const int TEMPORARY = 0;
+
+  final String name;
+
+  void close() native;
+
+  @JSName('webkitRequestFileSystem')
+  @SupportedBrowser(SupportedBrowser.CHROME)
+  @SupportedBrowser(SupportedBrowser.SAFARI)
+  void _webkitRequestFileSystem(int type, int size,
+      [_FileSystemCallback successCallback,
+      _ErrorCallback errorCallback]) native;
+
+  @JSName('webkitRequestFileSystemSync')
+  @SupportedBrowser(SupportedBrowser.CHROME)
+  @SupportedBrowser(SupportedBrowser.SAFARI)
+  _DOMFileSystemSync requestFileSystemSync(int type, int size) native;
+
+  @JSName('webkitResolveLocalFileSystemSyncURL')
+  @SupportedBrowser(SupportedBrowser.CHROME)
+  @SupportedBrowser(SupportedBrowser.SAFARI)
+  _EntrySync resolveLocalFileSystemSyncUrl(String url) native;
+
+  @JSName('webkitResolveLocalFileSystemURL')
+  @SupportedBrowser(SupportedBrowser.CHROME)
+  @SupportedBrowser(SupportedBrowser.SAFARI)
+  void _webkitResolveLocalFileSystemUrl(
+      String url, _EntryCallback successCallback,
+      [_ErrorCallback errorCallback]) native;
+
+  /// Stream of `connect` events handled by this [SharedWorkerGlobalScope].
+  Stream<Event> get onConnect => connectEvent.forTarget(this);
+
+  static SharedWorkerGlobalScope get instance {
+    return _workerSelf as SharedWorkerGlobalScope;
+  }
+}
+
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("HTMLSlotElement")
+class SlotElement extends HtmlElement {
+  // To suppress missing implicit constructor warnings.
+  factory SlotElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  SlotElement.created() : super.created();
+
+  String name;
+
+  List<Node> assignedNodes([Map options]) {
+    if (options != null) {
+      var options_1 = convertDartToNative_Dictionary(options);
+      return _assignedNodes_1(options_1);
+    }
+    return _assignedNodes_2();
+  }
+
+  @JSName('assignedNodes')
+  List<Node> _assignedNodes_1(options) native;
+  @JSName('assignedNodes')
+  List<Node> _assignedNodes_2() native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("SourceBuffer")
+class SourceBuffer extends EventTarget {
+  // To suppress missing implicit constructor warnings.
+  factory SourceBuffer._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  static const EventStreamProvider<Event> abortEvent =
+      const EventStreamProvider<Event>('abort');
+
+  static const EventStreamProvider<Event> errorEvent =
+      const EventStreamProvider<Event>('error');
+
+  num appendWindowEnd;
+
+  num appendWindowStart;
+
+  final AudioTrackList audioTracks;
+
+  final TimeRanges buffered;
+
+  String mode;
+
+  num timestampOffset;
+
+  TrackDefaultList trackDefaults;
+
+  final bool updating;
+
+  final VideoTrackList videoTracks;
+
+  void abort() native;
+
+  void appendBuffer(ByteBuffer data) native;
+
+  @JSName('appendBuffer')
+  void appendTypedData(TypedData data) native;
+
+  void remove(num start, num end) native;
+
+  Stream<Event> get onAbort => abortEvent.forTarget(this);
+
+  Stream<Event> get onError => errorEvent.forTarget(this);
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("SourceBufferList")
+class SourceBufferList extends EventTarget
+    with ListMixin<SourceBuffer>, ImmutableListMixin<SourceBuffer>
+    implements JavaScriptIndexingBehavior<SourceBuffer>, List<SourceBuffer> {
+  // To suppress missing implicit constructor warnings.
+  factory SourceBufferList._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  int get length => JS("int", "#.length", this);
+
+  SourceBuffer operator [](int index) {
+    if (JS("bool", "# >>> 0 !== # || # >= #", index, index, index, length))
+      throw new RangeError.index(index, this);
+    return JS("SourceBuffer", "#[#]", this, index);
+  }
+
+  void operator []=(int index, SourceBuffer value) {
+    throw new UnsupportedError("Cannot assign element of immutable List.");
+  }
+  // -- start List<SourceBuffer> mixins.
+  // SourceBuffer is the element type.
+
+  set length(int value) {
+    throw new UnsupportedError("Cannot resize immutable List.");
+  }
+
+  SourceBuffer get first {
+    if (this.length > 0) {
+      return JS('SourceBuffer', '#[0]', this);
+    }
+    throw new StateError("No elements");
+  }
+
+  SourceBuffer get last {
+    int len = this.length;
+    if (len > 0) {
+      return JS('SourceBuffer', '#[#]', this, len - 1);
+    }
+    throw new StateError("No elements");
+  }
+
+  SourceBuffer get single {
+    int len = this.length;
+    if (len == 1) {
+      return JS('SourceBuffer', '#[0]', this);
+    }
+    if (len == 0) throw new StateError("No elements");
+    throw new StateError("More than one element");
+  }
+
+  SourceBuffer elementAt(int index) => this[index];
+  // -- end List<SourceBuffer> mixins.
+
+  SourceBuffer item(int index) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("HTMLSourceElement")
+class SourceElement extends HtmlElement {
+  // To suppress missing implicit constructor warnings.
+  factory SourceElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory SourceElement() => JS(
+      'returns:SourceElement;creates:SourceElement;new:true',
+      '#.createElement(#)',
+      document,
+      "source");
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  SourceElement.created() : super.created();
+
+  String media;
+
+  String sizes;
+
+  String src;
+
+  String srcset;
+
+  String type;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("HTMLSpanElement")
+class SpanElement extends HtmlElement {
+  // To suppress missing implicit constructor warnings.
+  factory SpanElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory SpanElement() => JS(
+      'returns:SpanElement;creates:SpanElement;new:true',
+      '#.createElement(#)',
+      document,
+      "span");
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  SpanElement.created() : super.created();
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("SpeechGrammar")
+class SpeechGrammar extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory SpeechGrammar._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory SpeechGrammar() {
+    return SpeechGrammar._create_1();
+  }
+  static SpeechGrammar _create_1() =>
+      JS('SpeechGrammar', 'new SpeechGrammar()');
+
+  String src;
+
+  num weight;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("SpeechGrammarList")
+class SpeechGrammarList extends Interceptor
+    with ListMixin<SpeechGrammar>, ImmutableListMixin<SpeechGrammar>
+    implements JavaScriptIndexingBehavior<SpeechGrammar>, List<SpeechGrammar> {
+  // To suppress missing implicit constructor warnings.
+  factory SpeechGrammarList._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory SpeechGrammarList() {
+    return SpeechGrammarList._create_1();
+  }
+  static SpeechGrammarList _create_1() =>
+      JS('SpeechGrammarList', 'new SpeechGrammarList()');
+
+  int get length => JS("int", "#.length", this);
+
+  SpeechGrammar operator [](int index) {
+    if (JS("bool", "# >>> 0 !== # || # >= #", index, index, index, length))
+      throw new RangeError.index(index, this);
+    return JS("SpeechGrammar", "#[#]", this, index);
+  }
+
+  void operator []=(int index, SpeechGrammar value) {
+    throw new UnsupportedError("Cannot assign element of immutable List.");
+  }
+  // -- start List<SpeechGrammar> mixins.
+  // SpeechGrammar is the element type.
+
+  set length(int value) {
+    throw new UnsupportedError("Cannot resize immutable List.");
+  }
+
+  SpeechGrammar get first {
+    if (this.length > 0) {
+      return JS('SpeechGrammar', '#[0]', this);
+    }
+    throw new StateError("No elements");
+  }
+
+  SpeechGrammar get last {
+    int len = this.length;
+    if (len > 0) {
+      return JS('SpeechGrammar', '#[#]', this, len - 1);
+    }
+    throw new StateError("No elements");
+  }
+
+  SpeechGrammar get single {
+    int len = this.length;
+    if (len == 1) {
+      return JS('SpeechGrammar', '#[0]', this);
+    }
+    if (len == 0) throw new StateError("No elements");
+    throw new StateError("More than one element");
+  }
+
+  SpeechGrammar elementAt(int index) => this[index];
+  // -- end List<SpeechGrammar> mixins.
+
+  void addFromString(String string, [num weight]) native;
+
+  void addFromUri(String src, [num weight]) native;
+
+  SpeechGrammar item(int index) native;
+}
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME, '25')
+@Native("SpeechRecognition")
+class SpeechRecognition extends EventTarget {
+  // To suppress missing implicit constructor warnings.
+  factory SpeechRecognition._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  /**
+   * Static factory designed to expose `audioend` events to event
+   * handlers that are not necessarily instances of [SpeechRecognition].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<Event> audioEndEvent =
+      const EventStreamProvider<Event>('audioend');
+
+  /**
+   * Static factory designed to expose `audiostart` events to event
+   * handlers that are not necessarily instances of [SpeechRecognition].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<Event> audioStartEvent =
+      const EventStreamProvider<Event>('audiostart');
+
+  /**
+   * Static factory designed to expose `end` events to event
+   * handlers that are not necessarily instances of [SpeechRecognition].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<Event> endEvent =
+      const EventStreamProvider<Event>('end');
+
+  /**
+   * Static factory designed to expose `error` events to event
+   * handlers that are not necessarily instances of [SpeechRecognition].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<SpeechRecognitionError> errorEvent =
+      const EventStreamProvider<SpeechRecognitionError>('error');
+
+  /**
+   * Static factory designed to expose `nomatch` events to event
+   * handlers that are not necessarily instances of [SpeechRecognition].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<SpeechRecognitionEvent> noMatchEvent =
+      const EventStreamProvider<SpeechRecognitionEvent>('nomatch');
+
+  /**
+   * Static factory designed to expose `result` events to event
+   * handlers that are not necessarily instances of [SpeechRecognition].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<SpeechRecognitionEvent> resultEvent =
+      const EventStreamProvider<SpeechRecognitionEvent>('result');
+
+  /**
+   * Static factory designed to expose `soundend` events to event
+   * handlers that are not necessarily instances of [SpeechRecognition].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<Event> soundEndEvent =
+      const EventStreamProvider<Event>('soundend');
+
+  /**
+   * Static factory designed to expose `soundstart` events to event
+   * handlers that are not necessarily instances of [SpeechRecognition].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<Event> soundStartEvent =
+      const EventStreamProvider<Event>('soundstart');
+
+  /**
+   * Static factory designed to expose `speechend` events to event
+   * handlers that are not necessarily instances of [SpeechRecognition].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<Event> speechEndEvent =
+      const EventStreamProvider<Event>('speechend');
+
+  /**
+   * Static factory designed to expose `speechstart` events to event
+   * handlers that are not necessarily instances of [SpeechRecognition].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<Event> speechStartEvent =
+      const EventStreamProvider<Event>('speechstart');
+
+  /**
+   * Static factory designed to expose `start` events to event
+   * handlers that are not necessarily instances of [SpeechRecognition].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<Event> startEvent =
+      const EventStreamProvider<Event>('start');
+
+  /// Checks if this type is supported on the current platform.
+  static bool get supported => JS(
+      'bool', '!!(window.SpeechRecognition || window.webkitSpeechRecognition)');
+
+  MediaStreamTrack audioTrack;
+
+  bool continuous;
+
+  SpeechGrammarList grammars;
+
+  bool interimResults;
+
+  String lang;
+
+  int maxAlternatives;
+
+  void abort() native;
+
+  void start() native;
+
+  void stop() native;
+
+  /// Stream of `audioend` events handled by this [SpeechRecognition].
+  Stream<Event> get onAudioEnd => audioEndEvent.forTarget(this);
+
+  /// Stream of `audiostart` events handled by this [SpeechRecognition].
+  Stream<Event> get onAudioStart => audioStartEvent.forTarget(this);
+
+  /// Stream of `end` events handled by this [SpeechRecognition].
+  Stream<Event> get onEnd => endEvent.forTarget(this);
+
+  /// Stream of `error` events handled by this [SpeechRecognition].
+  Stream<SpeechRecognitionError> get onError => errorEvent.forTarget(this);
+
+  /// Stream of `nomatch` events handled by this [SpeechRecognition].
+  Stream<SpeechRecognitionEvent> get onNoMatch => noMatchEvent.forTarget(this);
+
+  /// Stream of `result` events handled by this [SpeechRecognition].
+  Stream<SpeechRecognitionEvent> get onResult => resultEvent.forTarget(this);
+
+  /// Stream of `soundend` events handled by this [SpeechRecognition].
+  Stream<Event> get onSoundEnd => soundEndEvent.forTarget(this);
+
+  /// Stream of `soundstart` events handled by this [SpeechRecognition].
+  Stream<Event> get onSoundStart => soundStartEvent.forTarget(this);
+
+  /// Stream of `speechend` events handled by this [SpeechRecognition].
+  Stream<Event> get onSpeechEnd => speechEndEvent.forTarget(this);
+
+  /// Stream of `speechstart` events handled by this [SpeechRecognition].
+  Stream<Event> get onSpeechStart => speechStartEvent.forTarget(this);
+
+  /// Stream of `start` events handled by this [SpeechRecognition].
+  Stream<Event> get onStart => startEvent.forTarget(this);
+
+  factory SpeechRecognition() {
+    return JS('SpeechRecognition',
+        'new (window.SpeechRecognition || window.webkitSpeechRecognition)()');
+  }
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME, '25')
+@Native("SpeechRecognitionAlternative")
+class SpeechRecognitionAlternative extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory SpeechRecognitionAlternative._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final num confidence;
+
+  final String transcript;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME, '25')
+@Native("SpeechRecognitionError")
+class SpeechRecognitionError extends Event {
+  // To suppress missing implicit constructor warnings.
+  factory SpeechRecognitionError._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory SpeechRecognitionError(String type, [Map initDict]) {
+    if (initDict != null) {
+      var initDict_1 = convertDartToNative_Dictionary(initDict);
+      return SpeechRecognitionError._create_1(type, initDict_1);
+    }
+    return SpeechRecognitionError._create_2(type);
+  }
+  static SpeechRecognitionError _create_1(type, initDict) => JS(
+      'SpeechRecognitionError',
+      'new SpeechRecognitionError(#,#)',
+      type,
+      initDict);
+  static SpeechRecognitionError _create_2(type) =>
+      JS('SpeechRecognitionError', 'new SpeechRecognitionError(#)', type);
+
+  final String error;
+
+  final String message;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME, '25')
+@Native("SpeechRecognitionEvent")
+class SpeechRecognitionEvent extends Event {
+  // To suppress missing implicit constructor warnings.
+  factory SpeechRecognitionEvent._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory SpeechRecognitionEvent(String type, [Map initDict]) {
+    if (initDict != null) {
+      var initDict_1 = convertDartToNative_Dictionary(initDict);
+      return SpeechRecognitionEvent._create_1(type, initDict_1);
+    }
+    return SpeechRecognitionEvent._create_2(type);
+  }
+  static SpeechRecognitionEvent _create_1(type, initDict) => JS(
+      'SpeechRecognitionEvent',
+      'new SpeechRecognitionEvent(#,#)',
+      type,
+      initDict);
+  static SpeechRecognitionEvent _create_2(type) =>
+      JS('SpeechRecognitionEvent', 'new SpeechRecognitionEvent(#)', type);
+
+  final Document emma;
+
+  final Document interpretation;
+
+  final int resultIndex;
+
+  @Returns('_SpeechRecognitionResultList|Null')
+  @Creates('_SpeechRecognitionResultList')
+  final List<SpeechRecognitionResult> results;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME, '25')
+@Native("SpeechRecognitionResult")
+class SpeechRecognitionResult extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory SpeechRecognitionResult._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final bool isFinal;
+
+  final int length;
+
+  SpeechRecognitionAlternative item(int index) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("SpeechSynthesis")
+class SpeechSynthesis extends EventTarget {
+  List<SpeechSynthesisVoice> getVoices() {
+    List<SpeechSynthesisVoice> voices = _getVoices();
+    if (voices.length > 0) applyExtension('SpeechSynthesisVoice', voices[0]);
+    return voices;
+  }
+
+  // To suppress missing implicit constructor warnings.
+  factory SpeechSynthesis._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final bool paused;
+
+  final bool pending;
+
+  final bool speaking;
+
+  void cancel() native;
+
+  @JSName('getVoices')
+  List<SpeechSynthesisVoice> _getVoices() native;
+
+  void pause() native;
+
+  void resume() native;
+
+  void speak(SpeechSynthesisUtterance utterance) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("SpeechSynthesisEvent")
+class SpeechSynthesisEvent extends Event {
+  // To suppress missing implicit constructor warnings.
+  factory SpeechSynthesisEvent._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final int charIndex;
+
+  final num elapsedTime;
+
+  final String name;
+
+  final SpeechSynthesisUtterance utterance;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("SpeechSynthesisUtterance")
+class SpeechSynthesisUtterance extends EventTarget {
+  // To suppress missing implicit constructor warnings.
+  factory SpeechSynthesisUtterance._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  /**
+   * Static factory designed to expose `boundary` events to event
+   * handlers that are not necessarily instances of [SpeechSynthesisUtterance].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<SpeechSynthesisEvent> boundaryEvent =
+      const EventStreamProvider<SpeechSynthesisEvent>('boundary');
+
+  /**
+   * Static factory designed to expose `end` events to event
+   * handlers that are not necessarily instances of [SpeechSynthesisUtterance].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<SpeechSynthesisEvent> endEvent =
+      const EventStreamProvider<SpeechSynthesisEvent>('end');
+
+  /**
+   * Static factory designed to expose `error` events to event
+   * handlers that are not necessarily instances of [SpeechSynthesisUtterance].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<Event> errorEvent =
+      const EventStreamProvider<Event>('error');
+
+  /**
+   * Static factory designed to expose `mark` events to event
+   * handlers that are not necessarily instances of [SpeechSynthesisUtterance].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<SpeechSynthesisEvent> markEvent =
+      const EventStreamProvider<SpeechSynthesisEvent>('mark');
+
+  /**
+   * Static factory designed to expose `pause` events to event
+   * handlers that are not necessarily instances of [SpeechSynthesisUtterance].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<Event> pauseEvent =
+      const EventStreamProvider<Event>('pause');
+
+  /**
+   * Static factory designed to expose `resume` events to event
+   * handlers that are not necessarily instances of [SpeechSynthesisUtterance].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<SpeechSynthesisEvent> resumeEvent =
+      const EventStreamProvider<SpeechSynthesisEvent>('resume');
+
+  /**
+   * Static factory designed to expose `start` events to event
+   * handlers that are not necessarily instances of [SpeechSynthesisUtterance].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<SpeechSynthesisEvent> startEvent =
+      const EventStreamProvider<SpeechSynthesisEvent>('start');
+
+  factory SpeechSynthesisUtterance([String text]) {
+    if (text != null) {
+      return SpeechSynthesisUtterance._create_1(text);
+    }
+    return SpeechSynthesisUtterance._create_2();
+  }
+  static SpeechSynthesisUtterance _create_1(text) =>
+      JS('SpeechSynthesisUtterance', 'new SpeechSynthesisUtterance(#)', text);
+  static SpeechSynthesisUtterance _create_2() =>
+      JS('SpeechSynthesisUtterance', 'new SpeechSynthesisUtterance()');
+
+  String lang;
+
+  num pitch;
+
+  num rate;
+
+  String text;
+
+  SpeechSynthesisVoice voice;
+
+  num volume;
+
+  /// Stream of `boundary` events handled by this [SpeechSynthesisUtterance].
+  Stream<SpeechSynthesisEvent> get onBoundary => boundaryEvent.forTarget(this);
+
+  /// Stream of `end` events handled by this [SpeechSynthesisUtterance].
+  Stream<SpeechSynthesisEvent> get onEnd => endEvent.forTarget(this);
+
+  /// Stream of `error` events handled by this [SpeechSynthesisUtterance].
+  Stream<Event> get onError => errorEvent.forTarget(this);
+
+  /// Stream of `mark` events handled by this [SpeechSynthesisUtterance].
+  Stream<SpeechSynthesisEvent> get onMark => markEvent.forTarget(this);
+
+  /// Stream of `pause` events handled by this [SpeechSynthesisUtterance].
+  Stream<Event> get onPause => pauseEvent.forTarget(this);
+
+  /// Stream of `resume` events handled by this [SpeechSynthesisUtterance].
+  Stream<SpeechSynthesisEvent> get onResume => resumeEvent.forTarget(this);
+
+  /// Stream of `start` events handled by this [SpeechSynthesisUtterance].
+  Stream<SpeechSynthesisEvent> get onStart => startEvent.forTarget(this);
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("SpeechSynthesisVoice")
+class SpeechSynthesisVoice extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory SpeechSynthesisVoice._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  @JSName('default')
+  final bool defaultValue;
+
+  final String lang;
+
+  final bool localService;
+
+  final String name;
+
+  @JSName('voiceURI')
+  final String voiceUri;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("StaticRange")
+class StaticRange extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory StaticRange._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final bool collapsed;
+
+  final Node endContainer;
+
+  final int endOffset;
+
+  final Node startContainer;
+
+  final int startOffset;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/**
+ * The type used by the
+ * [Window.localStorage] and [Window.sessionStorage] properties.
+ * Storage is implemented as a Map&lt;String, String>.
+ *
+ * To store and get values, use Dart's built-in map syntax:
+ *
+ *     window.localStorage['key1'] = 'val1';
+ *     window.localStorage['key2'] = 'val2';
+ *     window.localStorage['key3'] = 'val3';
+ *     assert(window.localStorage['key3'] == 'val3');
+ *
+ * You can use [Map](http://api.dartlang.org/dart_core/Map.html) APIs
+ * such as containsValue(), clear(), and length:
+ *
+ *     assert(window.localStorage.containsValue('does not exist') == false);
+ *     window.localStorage.clear();
+ *     assert(window.localStorage.length == 0);
+ *
+ * For more examples of using this API, see
+ * [localstorage_test.dart](http://code.google.com/p/dart/source/browse/branches/bleeding_edge/dart/tests/html/localstorage_test.dart).
+ * For details on using the Map API, see the
+ * [Maps](https://www.dartlang.org/guides/libraries/library-tour#maps)
+ * section of the library tour.
+ */
+@Unstable()
+@Native("Storage")
+class Storage extends Interceptor with MapMixin<String, String> {
+  void addAll(Map<String, String> other) {
+    other.forEach((k, v) {
+      this[k] = v;
+    });
+  }
+
+  // TODO(nweiz): update this when maps support lazy iteration
+  bool containsValue(Object value) => values.any((e) => e == value);
+
+  bool containsKey(Object key) => _getItem(key) != null;
+
+  String operator [](Object key) => _getItem(key);
+
+  void operator []=(String key, String value) {
+    _setItem(key, value);
+  }
+
+  String putIfAbsent(String key, String ifAbsent()) {
+    if (!containsKey(key)) this[key] = ifAbsent();
+    return this[key];
+  }
+
+  String remove(Object key) {
+    final value = this[key];
+    _removeItem(key);
+    return value;
+  }
+
+  void clear() => _clear();
+
+  void forEach(void f(String key, String value)) {
+    for (var i = 0; true; i++) {
+      final key = _key(i);
+      if (key == null) return;
+
+      f(key, this[key]);
+    }
+  }
+
+  Iterable<String> get keys {
+    final keys = <String>[];
+    forEach((k, v) => keys.add(k));
+    return keys;
+  }
+
+  Iterable<String> get values {
+    final values = <String>[];
+    forEach((k, v) => values.add(v));
+    return values;
+  }
+
+  int get length => _length;
+
+  bool get isEmpty => _key(0) == null;
+
+  bool get isNotEmpty => !isEmpty;
+  // To suppress missing implicit constructor warnings.
+  factory Storage._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  @JSName('length')
+  final int _length;
+
+  @JSName('clear')
+  void _clear() native;
+
+  @JSName('getItem')
+  String _getItem(String key) native;
+
+  @JSName('key')
+  String _key(int index) native;
+
+  @JSName('removeItem')
+  void _removeItem(String key) native;
+
+  @JSName('setItem')
+  void _setItem(String key, String value) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+typedef void StorageErrorCallback(DomError error);
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+@Unstable()
+@Native("StorageEvent")
+class StorageEvent extends Event {
+  factory StorageEvent(String type,
+      {bool canBubble: false,
+      bool cancelable: false,
+      String key,
+      String oldValue,
+      String newValue,
+      String url,
+      Storage storageArea}) {
+    StorageEvent e = document._createEvent("StorageEvent");
+    e._initStorageEvent(
+        type, canBubble, cancelable, key, oldValue, newValue, url, storageArea);
+    return e;
+  }
+
+  factory StorageEvent._(String type, [Map eventInitDict]) {
+    if (eventInitDict != null) {
+      var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+      return StorageEvent._create_1(type, eventInitDict_1);
+    }
+    return StorageEvent._create_2(type);
+  }
+  static StorageEvent _create_1(type, eventInitDict) =>
+      JS('StorageEvent', 'new StorageEvent(#,#)', type, eventInitDict);
+  static StorageEvent _create_2(type) =>
+      JS('StorageEvent', 'new StorageEvent(#)', type);
+
+  final String key;
+
+  final String newValue;
+
+  final String oldValue;
+
+  final Storage storageArea;
+
+  final String url;
+
+  @JSName('initStorageEvent')
+  void _initStorageEvent(
+      String typeArg,
+      bool canBubbleArg,
+      bool cancelableArg,
+      String keyArg,
+      String oldValueArg,
+      String newValueArg,
+      String urlArg,
+      Storage storageAreaArg) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("StorageManager")
+class StorageManager extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory StorageManager._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  Future<Map<String, dynamic>> estimate() =>
+      promiseToFutureAsMap(JS("", "#.estimate()", this));
+
+  Future<bool> persist() => promiseToFuture<bool>(JS("", "#.persist()", this));
+
+  Future<bool> persisted() =>
+      promiseToFuture<bool>(JS("", "#.persisted()", this));
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+typedef void StorageQuotaCallback(int grantedQuotaInBytes);
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+typedef void StorageUsageCallback(
+    int currentUsageInBytes, int currentQuotaInBytes);
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("HTMLStyleElement")
+class StyleElement extends HtmlElement {
+  // To suppress missing implicit constructor warnings.
+  factory StyleElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory StyleElement() => JS(
+      'returns:StyleElement;creates:StyleElement;new:true',
+      '#.createElement(#)',
+      document,
+      "style");
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  StyleElement.created() : super.created();
+
+  bool disabled;
+
+  String media;
+
+  final StyleSheet sheet;
+
+  String type;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("StyleMedia")
+class StyleMedia extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory StyleMedia._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final String type;
+
+  bool matchMedium(String mediaquery) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("StylePropertyMap")
+class StylePropertyMap extends StylePropertyMapReadonly {
+  // To suppress missing implicit constructor warnings.
+  factory StylePropertyMap._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  void append(String property, Object value) native;
+
+  void delete(String property) native;
+
+  void set(String property, Object value) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("StylePropertyMapReadonly")
+class StylePropertyMapReadonly extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory StylePropertyMapReadonly._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  CssStyleValue get(String property) native;
+
+  List<CssStyleValue> getAll(String property) native;
+
+  List<String> getProperties() native;
+
+  bool has(String property) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("StyleSheet")
+class StyleSheet extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory StyleSheet._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  bool disabled;
+
+  final String href;
+
+  final MediaList media;
+
+  final Node ownerNode;
+
+  final StyleSheet parentStyleSheet;
+
+  final String title;
+
+  final String type;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("SyncEvent")
+class SyncEvent extends ExtendableEvent {
+  // To suppress missing implicit constructor warnings.
+  factory SyncEvent._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory SyncEvent(String type, Map init) {
+    var init_1 = convertDartToNative_Dictionary(init);
+    return SyncEvent._create_1(type, init_1);
+  }
+  static SyncEvent _create_1(type, init) =>
+      JS('SyncEvent', 'new SyncEvent(#,#)', type, init);
+
+  final bool lastChance;
+
+  final String tag;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("SyncManager")
+class SyncManager extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory SyncManager._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  Future<List<String>> getTags() =>
+      promiseToFuture<List<String>>(JS("", "#.getTags()", this));
+
+  Future register(String tag) =>
+      promiseToFuture(JS("", "#.register(#)", this, tag));
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("HTMLTableCaptionElement")
+class TableCaptionElement extends HtmlElement {
+  // To suppress missing implicit constructor warnings.
+  factory TableCaptionElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory TableCaptionElement() => JS(
+      'returns:TableCaptionElement;creates:TableCaptionElement;new:true',
+      '#.createElement(#)',
+      document,
+      "caption");
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  TableCaptionElement.created() : super.created();
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native(
+    "HTMLTableCellElement,HTMLTableDataCellElement,HTMLTableHeaderCellElement")
+class TableCellElement extends HtmlElement {
+  // To suppress missing implicit constructor warnings.
+  factory TableCellElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory TableCellElement() => JS(
+      'returns:TableCellElement;creates:TableCellElement;new:true',
+      '#.createElement(#)',
+      document,
+      "td");
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  TableCellElement.created() : super.created();
+
+  final int cellIndex;
+
+  int colSpan;
+
+  String headers;
+
+  int rowSpan;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("HTMLTableColElement")
+class TableColElement extends HtmlElement {
+  // To suppress missing implicit constructor warnings.
+  factory TableColElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory TableColElement() => JS(
+      'returns:TableColElement;creates:TableColElement;new:true',
+      '#.createElement(#)',
+      document,
+      "col");
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  TableColElement.created() : super.created();
+
+  int span;
+}
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("HTMLTableElement")
+class TableElement extends HtmlElement {
+  List<TableSectionElement> get tBodies =>
+      new _WrappedList<TableSectionElement>(_tBodies);
+
+  List<TableRowElement> get rows => new _WrappedList<TableRowElement>(_rows);
+
+  TableRowElement addRow() {
+    return insertRow(-1);
+  }
+
+  TableCaptionElement createCaption() => _createCaption();
+  TableSectionElement createTBody() => _createTBody();
+  TableSectionElement createTFoot() => _createTFoot();
+  TableSectionElement createTHead() => _createTHead();
+  TableRowElement insertRow(int index) => _insertRow(index);
+
+  TableSectionElement _createTBody() {
+    if (JS('bool', '!!#.createTBody', this)) {
+      return this._nativeCreateTBody();
+    }
+    var tbody = new Element.tag('tbody');
+    this.children.add(tbody);
+    return tbody;
+  }
+
+  @JSName('createTBody')
+  TableSectionElement _nativeCreateTBody() native;
+
+  DocumentFragment createFragment(String html,
+      {NodeValidator validator, NodeTreeSanitizer treeSanitizer}) {
+    if (Range.supportsCreateContextualFragment) {
+      return super.createFragment(html,
+          validator: validator, treeSanitizer: treeSanitizer);
+    }
+    // IE9 workaround which does not support innerHTML on Table elements.
+    var contextualHtml = '<table>$html</table>';
+    var table = new Element.html(contextualHtml,
+        validator: validator, treeSanitizer: treeSanitizer);
+    var fragment = new DocumentFragment();
+    fragment.nodes.addAll(table.nodes);
+
+    return fragment;
+  }
+
+  // To suppress missing implicit constructor warnings.
+  factory TableElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory TableElement() => JS(
+      'returns:TableElement;creates:TableElement;new:true',
+      '#.createElement(#)',
+      document,
+      "table");
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  TableElement.created() : super.created();
+
+  TableCaptionElement caption;
+
+  @JSName('rows')
+  @Returns('HtmlCollection|Null')
+  @Creates('HtmlCollection')
+  final List<Node> _rows;
+
+  @JSName('tBodies')
+  @Returns('HtmlCollection|Null')
+  @Creates('HtmlCollection')
+  final List<Node> _tBodies;
+
+  TableSectionElement tFoot;
+
+  TableSectionElement tHead;
+
+  @JSName('createCaption')
+  TableCaptionElement _createCaption() native;
+
+  @JSName('createTFoot')
+  TableSectionElement _createTFoot() native;
+
+  @JSName('createTHead')
+  TableSectionElement _createTHead() native;
+
+  void deleteCaption() native;
+
+  void deleteRow(int index) native;
+
+  void deleteTFoot() native;
+
+  void deleteTHead() native;
+
+  @JSName('insertRow')
+  TableRowElement _insertRow([int index]) native;
+}
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("HTMLTableRowElement")
+class TableRowElement extends HtmlElement {
+  List<TableCellElement> get cells =>
+      new _WrappedList<TableCellElement>(_cells);
+
+  TableCellElement addCell() {
+    return insertCell(-1);
+  }
+
+  TableCellElement insertCell(int index) => _insertCell(index);
+
+  DocumentFragment createFragment(String html,
+      {NodeValidator validator, NodeTreeSanitizer treeSanitizer}) {
+    if (Range.supportsCreateContextualFragment) {
+      return super.createFragment(html,
+          validator: validator, treeSanitizer: treeSanitizer);
+    }
+    // IE9 workaround which does not support innerHTML on Table elements.
+    var fragment = new DocumentFragment();
+    var section = new TableElement()
+        .createFragment(html,
+            validator: validator, treeSanitizer: treeSanitizer)
+        .nodes
+        .single;
+    var row = section.nodes.single;
+    fragment.nodes.addAll(row.nodes);
+    return fragment;
+  }
+
+  // To suppress missing implicit constructor warnings.
+  factory TableRowElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory TableRowElement() => JS(
+      'returns:TableRowElement;creates:TableRowElement;new:true',
+      '#.createElement(#)',
+      document,
+      "tr");
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  TableRowElement.created() : super.created();
+
+  @JSName('cells')
+  @Returns('HtmlCollection|Null')
+  @Creates('HtmlCollection')
+  final List<Node> _cells;
+
+  final int rowIndex;
+
+  final int sectionRowIndex;
+
+  void deleteCell(int index) native;
+
+  @JSName('insertCell')
+  HtmlElement _insertCell([int index]) native;
+}
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("HTMLTableSectionElement")
+class TableSectionElement extends HtmlElement {
+  List<TableRowElement> get rows => new _WrappedList<TableRowElement>(_rows);
+
+  TableRowElement addRow() {
+    return insertRow(-1);
+  }
+
+  TableRowElement insertRow(int index) => _insertRow(index);
+
+  DocumentFragment createFragment(String html,
+      {NodeValidator validator, NodeTreeSanitizer treeSanitizer}) {
+    if (Range.supportsCreateContextualFragment) {
+      return super.createFragment(html,
+          validator: validator, treeSanitizer: treeSanitizer);
+    }
+    // IE9 workaround which does not support innerHTML on Table elements.
+    var fragment = new DocumentFragment();
+    var section = new TableElement()
+        .createFragment(html,
+            validator: validator, treeSanitizer: treeSanitizer)
+        .nodes
+        .single;
+    fragment.nodes.addAll(section.nodes);
+    return fragment;
+  }
+
+  // To suppress missing implicit constructor warnings.
+  factory TableSectionElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  TableSectionElement.created() : super.created();
+
+  @JSName('rows')
+  @Returns('HtmlCollection|Null')
+  @Creates('HtmlCollection')
+  final List<Node> _rows;
+
+  void deleteRow(int index) native;
+
+  @JSName('insertRow')
+  HtmlElement _insertRow([int index]) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("TaskAttributionTiming")
+class TaskAttributionTiming extends PerformanceEntry {
+  // To suppress missing implicit constructor warnings.
+  factory TaskAttributionTiming._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final String containerId;
+
+  final String containerName;
+
+  final String containerSrc;
+
+  final String containerType;
+
+  @JSName('scriptURL')
+  final String scriptUrl;
+}
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@Native("HTMLTemplateElement")
+class TemplateElement extends HtmlElement {
+  // To suppress missing implicit constructor warnings.
+  factory TemplateElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory TemplateElement() => document.createElement("template");
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  TemplateElement.created() : super.created();
+
+  /// Checks if this type is supported on the current platform.
+  static bool get supported => Element.isTagSupported('template');
+
+  final DocumentFragment content;
+
+  /**
+   * An override to place the contents into content rather than as child nodes.
+   *
+   * See also:
+   *
+   * * <https://w3c.github.io/DOM-Parsing/#the-innerhtml-mixin>
+   */
+  void setInnerHtml(String html,
+      {NodeValidator validator, NodeTreeSanitizer treeSanitizer}) {
+    text = null;
+    content.nodes.clear();
+    var fragment = createFragment(html,
+        validator: validator, treeSanitizer: treeSanitizer);
+
+    content.append(fragment);
+  }
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+@Native("Text")
+class Text extends CharacterData {
+  factory Text(String data) => JS(
+      'returns:Text;depends:none;effects:none;new:true',
+      '#.createTextNode(#)',
+      document,
+      data);
+  // To suppress missing implicit constructor warnings.
+  factory Text._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final SlotElement assignedSlot;
+
+  final String wholeText;
+
+  @Returns('NodeList|Null')
+  @Creates('NodeList')
+  List<Node> getDestinationInsertionPoints() native;
+
+  Text splitText(int offset) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("HTMLTextAreaElement")
+class TextAreaElement extends HtmlElement {
+  // To suppress missing implicit constructor warnings.
+  factory TextAreaElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory TextAreaElement() => JS(
+      'returns:TextAreaElement;creates:TextAreaElement;new:true',
+      '#.createElement(#)',
+      document,
+      "textarea");
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  TextAreaElement.created() : super.created();
+
+  String autocapitalize;
+
+  bool autofocus;
+
+  int cols;
+
+  String defaultValue;
+
+  String dirName;
+
+  bool disabled;
+
+  final FormElement form;
+
+  @Unstable()
+  @Returns('NodeList|Null')
+  @Creates('NodeList')
+  final List<Node> labels;
+
+  int maxLength;
+
+  int minLength;
+
+  String name;
+
+  String placeholder;
+
+  bool readOnly;
+
+  bool required;
+
+  int rows;
+
+  String selectionDirection;
+
+  int selectionEnd;
+
+  int selectionStart;
+
+  final int textLength;
+
+  final String type;
+
+  final String validationMessage;
+
+  final ValidityState validity;
+
+  String value;
+
+  final bool willValidate;
+
+  String wrap;
+
+  bool checkValidity() native;
+
+  bool reportValidity() native;
+
+  void select() native;
+
+  void setCustomValidity(String error) native;
+
+  void setRangeText(String replacement,
+      {int start, int end, String selectionMode}) native;
+
+  void setSelectionRange(int start, int end, [String direction]) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("TextDetector")
+class TextDetector extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory TextDetector._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory TextDetector() {
+    return TextDetector._create_1();
+  }
+  static TextDetector _create_1() => JS('TextDetector', 'new TextDetector()');
+
+  Future<List<DetectedText>> detect(/*ImageBitmapSource*/ image) =>
+      promiseToFuture<List<DetectedText>>(JS("", "#.detect(#)", this, image));
+}
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+@Unstable()
+@Native("TextEvent")
+class TextEvent extends UIEvent {
+  factory TextEvent(String type,
+      {bool canBubble: false,
+      bool cancelable: false,
+      Window view,
+      String data}) {
+    if (view == null) {
+      view = window;
+    }
+    TextEvent e = document._createEvent("TextEvent");
+    e._initTextEvent(type, canBubble, cancelable, view, data);
+    return e;
+  }
+  // To suppress missing implicit constructor warnings.
+  factory TextEvent._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final String data;
+
+  @JSName('initTextEvent')
+  void _initTextEvent(String type, bool bubbles, bool cancelable, Window view,
+      String data) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("TextMetrics")
+class TextMetrics extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory TextMetrics._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final num actualBoundingBoxAscent;
+
+  final num actualBoundingBoxDescent;
+
+  final num actualBoundingBoxLeft;
+
+  final num actualBoundingBoxRight;
+
+  final num alphabeticBaseline;
+
+  final num emHeightAscent;
+
+  final num emHeightDescent;
+
+  final num fontBoundingBoxAscent;
+
+  final num fontBoundingBoxDescent;
+
+  final num hangingBaseline;
+
+  final num ideographicBaseline;
+
+  final num width;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("TextTrack")
+class TextTrack extends EventTarget {
+  // To suppress missing implicit constructor warnings.
+  factory TextTrack._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  /**
+   * Static factory designed to expose `cuechange` events to event
+   * handlers that are not necessarily instances of [TextTrack].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<Event> cueChangeEvent =
+      const EventStreamProvider<Event>('cuechange');
+
+  final TextTrackCueList activeCues;
+
+  final TextTrackCueList cues;
+
+  final String id;
+
+  final String kind;
+
+  final String label;
+
+  final String language;
+
+  String mode;
+
+  void addCue(TextTrackCue cue) native;
+
+  void removeCue(TextTrackCue cue) native;
+
+  /// Stream of `cuechange` events handled by this [TextTrack].
+  Stream<Event> get onCueChange => cueChangeEvent.forTarget(this);
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("TextTrackCue")
+class TextTrackCue extends EventTarget {
+  // To suppress missing implicit constructor warnings.
+  factory TextTrackCue._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  /**
+   * Static factory designed to expose `enter` events to event
+   * handlers that are not necessarily instances of [TextTrackCue].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<Event> enterEvent =
+      const EventStreamProvider<Event>('enter');
+
+  /**
+   * Static factory designed to expose `exit` events to event
+   * handlers that are not necessarily instances of [TextTrackCue].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<Event> exitEvent =
+      const EventStreamProvider<Event>('exit');
+
+  num endTime;
+
+  String id;
+
+  bool pauseOnExit;
+
+  num startTime;
+
+  final TextTrack track;
+
+  /// Stream of `enter` events handled by this [TextTrackCue].
+  Stream<Event> get onEnter => enterEvent.forTarget(this);
+
+  /// Stream of `exit` events handled by this [TextTrackCue].
+  Stream<Event> get onExit => exitEvent.forTarget(this);
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("TextTrackCueList")
+class TextTrackCueList extends Interceptor
+    with ListMixin<TextTrackCue>, ImmutableListMixin<TextTrackCue>
+    implements List<TextTrackCue>, JavaScriptIndexingBehavior<TextTrackCue> {
+  // To suppress missing implicit constructor warnings.
+  factory TextTrackCueList._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  int get length => JS("int", "#.length", this);
+
+  TextTrackCue operator [](int index) {
+    if (JS("bool", "# >>> 0 !== # || # >= #", index, index, index, length))
+      throw new RangeError.index(index, this);
+    return JS("TextTrackCue", "#[#]", this, index);
+  }
+
+  void operator []=(int index, TextTrackCue value) {
+    throw new UnsupportedError("Cannot assign element of immutable List.");
+  }
+  // -- start List<TextTrackCue> mixins.
+  // TextTrackCue is the element type.
+
+  set length(int value) {
+    throw new UnsupportedError("Cannot resize immutable List.");
+  }
+
+  TextTrackCue get first {
+    if (this.length > 0) {
+      return JS('TextTrackCue', '#[0]', this);
+    }
+    throw new StateError("No elements");
+  }
+
+  TextTrackCue get last {
+    int len = this.length;
+    if (len > 0) {
+      return JS('TextTrackCue', '#[#]', this, len - 1);
+    }
+    throw new StateError("No elements");
+  }
+
+  TextTrackCue get single {
+    int len = this.length;
+    if (len == 1) {
+      return JS('TextTrackCue', '#[0]', this);
+    }
+    if (len == 0) throw new StateError("No elements");
+    throw new StateError("More than one element");
+  }
+
+  TextTrackCue elementAt(int index) => this[index];
+  // -- end List<TextTrackCue> mixins.
+
+  TextTrackCue __getter__(int index) native;
+
+  TextTrackCue getCueById(String id) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("TextTrackList")
+class TextTrackList extends EventTarget
+    with ListMixin<TextTrack>, ImmutableListMixin<TextTrack>
+    implements List<TextTrack>, JavaScriptIndexingBehavior<TextTrack> {
+  // To suppress missing implicit constructor warnings.
+  factory TextTrackList._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  /**
+   * Static factory designed to expose `addtrack` events to event
+   * handlers that are not necessarily instances of [TextTrackList].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<TrackEvent> addTrackEvent =
+      const EventStreamProvider<TrackEvent>('addtrack');
+
+  static const EventStreamProvider<Event> changeEvent =
+      const EventStreamProvider<Event>('change');
+
+  int get length => JS("int", "#.length", this);
+
+  TextTrack operator [](int index) {
+    if (JS("bool", "# >>> 0 !== # || # >= #", index, index, index, length))
+      throw new RangeError.index(index, this);
+    return JS("TextTrack", "#[#]", this, index);
+  }
+
+  void operator []=(int index, TextTrack value) {
+    throw new UnsupportedError("Cannot assign element of immutable List.");
+  }
+  // -- start List<TextTrack> mixins.
+  // TextTrack is the element type.
+
+  set length(int value) {
+    throw new UnsupportedError("Cannot resize immutable List.");
+  }
+
+  TextTrack get first {
+    if (this.length > 0) {
+      return JS('TextTrack', '#[0]', this);
+    }
+    throw new StateError("No elements");
+  }
+
+  TextTrack get last {
+    int len = this.length;
+    if (len > 0) {
+      return JS('TextTrack', '#[#]', this, len - 1);
+    }
+    throw new StateError("No elements");
+  }
+
+  TextTrack get single {
+    int len = this.length;
+    if (len == 1) {
+      return JS('TextTrack', '#[0]', this);
+    }
+    if (len == 0) throw new StateError("No elements");
+    throw new StateError("More than one element");
+  }
+
+  TextTrack elementAt(int index) => this[index];
+  // -- end List<TextTrack> mixins.
+
+  TextTrack __getter__(int index) native;
+
+  TextTrack getTrackById(String id) native;
+
+  /// Stream of `addtrack` events handled by this [TextTrackList].
+  Stream<TrackEvent> get onAddTrack => addTrackEvent.forTarget(this);
+
+  Stream<Event> get onChange => changeEvent.forTarget(this);
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("HTMLTimeElement")
+class TimeElement extends HtmlElement {
+  // To suppress missing implicit constructor warnings.
+  factory TimeElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  TimeElement.created() : super.created();
+
+  String dateTime;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("TimeRanges")
+class TimeRanges extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory TimeRanges._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final int length;
+
+  double end(int index) native;
+
+  double start(int index) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+typedef void TimeoutHandler();
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("HTMLTitleElement")
+class TitleElement extends HtmlElement {
+  // To suppress missing implicit constructor warnings.
+  factory TitleElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory TitleElement() => JS(
+      'returns:TitleElement;creates:TitleElement;new:true',
+      '#.createElement(#)',
+      document,
+      "title");
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  TitleElement.created() : super.created();
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("Touch")
+class Touch extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory Touch._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory Touch(Map initDict) {
+    var initDict_1 = convertDartToNative_Dictionary(initDict);
+    return Touch._create_1(initDict_1);
+  }
+  static Touch _create_1(initDict) => JS('Touch', 'new Touch(#)', initDict);
+
+  @JSName('clientX')
+  final num _clientX;
+
+  @JSName('clientY')
+  final num _clientY;
+
+  final num force;
+
+  final int identifier;
+
+  @JSName('pageX')
+  final num _pageX;
+
+  @JSName('pageY')
+  final num _pageY;
+
+  @JSName('radiusX')
+  final num _radiusX;
+
+  @JSName('radiusY')
+  final num _radiusY;
+
+  final String region;
+
+  final num rotationAngle;
+
+  @JSName('screenX')
+  final num _screenX;
+
+  @JSName('screenY')
+  final num _screenY;
+
+  EventTarget get target => _convertNativeToDart_EventTarget(this._get_target);
+  @JSName('target')
+  @Creates('Element|Document')
+  @Returns('Element|Document')
+  final dynamic _get_target;
+
+// As of Chrome 37, these all changed from long to double.  This code
+// preserves backwards compatibility for the time being.
+  int get __clientX => JS<num>('num', '#.clientX', this).round();
+  int get __clientY => JS<num>('num', '#.clientY', this).round();
+  int get __screenX => JS<num>('num', '#.screenX', this).round();
+  int get __screenY => JS<num>('num', '#.screenY', this).round();
+  int get __pageX => JS<num>('num', '#.pageX', this).round();
+  int get __pageY => JS<num>('num', '#.pageY', this).round();
+  int get __radiusX => JS<num>('num', '#.radiusX', this).round();
+  int get __radiusY => JS<num>('num', '#.radiusY', this).round();
+
+  Point get client => new Point(__clientX, __clientY);
+
+  Point get page => new Point(__pageX, __pageY);
+
+  Point get screen => new Point(__screenX, __screenY);
+
+  @SupportedBrowser(SupportedBrowser.CHROME)
+  @SupportedBrowser(SupportedBrowser.SAFARI)
+  int get radiusX => __radiusX;
+
+  @SupportedBrowser(SupportedBrowser.CHROME)
+  @SupportedBrowser(SupportedBrowser.SAFARI)
+  int get radiusY => __radiusY;
+}
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+@Native("TouchEvent")
+class TouchEvent extends UIEvent {
+  // To suppress missing implicit constructor warnings.
+  factory TouchEvent._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory TouchEvent(String type, [Map eventInitDict]) {
+    if (eventInitDict != null) {
+      var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+      return TouchEvent._create_1(type, eventInitDict_1);
+    }
+    return TouchEvent._create_2(type);
+  }
+  static TouchEvent _create_1(type, eventInitDict) =>
+      JS('TouchEvent', 'new TouchEvent(#,#)', type, eventInitDict);
+  static TouchEvent _create_2(type) =>
+      JS('TouchEvent', 'new TouchEvent(#)', type);
+
+  final bool altKey;
+
+  final TouchList changedTouches;
+
+  final bool ctrlKey;
+
+  final bool metaKey;
+
+  final bool shiftKey;
+
+  final TouchList targetTouches;
+
+  final TouchList touches;
+
+  /**
+   * Checks if touch events supported on the current platform.
+   */
+  static bool get supported {
+    try {
+      return TouchEvent('touches') is TouchEvent;
+    } catch (_) {}
+
+    return false;
+  }
+}
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+@Native("TouchList")
+class TouchList extends Interceptor
+    with ListMixin<Touch>, ImmutableListMixin<Touch>
+    implements JavaScriptIndexingBehavior<Touch>, List<Touch> {
+  /// NB: This constructor likely does not work as you might expect it to! This
+  /// constructor will simply fail (returning null) if you are not on a device
+  /// with touch enabled. See dartbug.com/8314.
+  // TODO(5760): createTouchList now uses varargs.
+  factory TouchList() => null; //document._createTouchList();
+  // To suppress missing implicit constructor warnings.
+  factory TouchList._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  /// Checks if this type is supported on the current platform.
+  static bool get supported => JS('bool', '!!document.createTouchList');
+
+  int get length => JS("int", "#.length", this);
+
+  Touch operator [](int index) {
+    if (JS("bool", "# >>> 0 !== # || # >= #", index, index, index, length))
+      throw new RangeError.index(index, this);
+    return JS("Touch", "#[#]", this, index);
+  }
+
+  void operator []=(int index, Touch value) {
+    throw new UnsupportedError("Cannot assign element of immutable List.");
+  }
+  // -- start List<Touch> mixins.
+  // Touch is the element type.
+
+  set length(int value) {
+    throw new UnsupportedError("Cannot resize immutable List.");
+  }
+
+  Touch get first {
+    if (this.length > 0) {
+      return JS('Touch', '#[0]', this);
+    }
+    throw new StateError("No elements");
+  }
+
+  Touch get last {
+    int len = this.length;
+    if (len > 0) {
+      return JS('Touch', '#[#]', this, len - 1);
+    }
+    throw new StateError("No elements");
+  }
+
+  Touch get single {
+    int len = this.length;
+    if (len == 1) {
+      return JS('Touch', '#[0]', this);
+    }
+    if (len == 0) throw new StateError("No elements");
+    throw new StateError("More than one element");
+  }
+
+  Touch elementAt(int index) => this[index];
+  // -- end List<Touch> mixins.
+
+  Touch item(int index) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("TrackDefault")
+class TrackDefault extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory TrackDefault._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory TrackDefault(
+      String type, String language, String label, List<String> kinds,
+      [String byteStreamTrackID]) {
+    if (byteStreamTrackID != null) {
+      List kinds_1 = convertDartToNative_StringArray(kinds);
+      return TrackDefault._create_1(
+          type, language, label, kinds_1, byteStreamTrackID);
+    }
+    List kinds_1 = convertDartToNative_StringArray(kinds);
+    return TrackDefault._create_2(type, language, label, kinds_1);
+  }
+  static TrackDefault _create_1(
+          type, language, label, kinds, byteStreamTrackID) =>
+      JS('TrackDefault', 'new TrackDefault(#,#,#,#,#)', type, language, label,
+          kinds, byteStreamTrackID);
+  static TrackDefault _create_2(type, language, label, kinds) => JS(
+      'TrackDefault',
+      'new TrackDefault(#,#,#,#)',
+      type,
+      language,
+      label,
+      kinds);
+
+  final String byteStreamTrackID;
+
+  final Object kinds;
+
+  final String label;
+
+  final String language;
+
+  final String type;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("TrackDefaultList")
+class TrackDefaultList extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory TrackDefaultList._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory TrackDefaultList([List<TrackDefault> trackDefaults]) {
+    if (trackDefaults != null) {
+      return TrackDefaultList._create_1(trackDefaults);
+    }
+    return TrackDefaultList._create_2();
+  }
+  static TrackDefaultList _create_1(trackDefaults) =>
+      JS('TrackDefaultList', 'new TrackDefaultList(#)', trackDefaults);
+  static TrackDefaultList _create_2() =>
+      JS('TrackDefaultList', 'new TrackDefaultList()');
+
+  final int length;
+
+  TrackDefault item(int index) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.IE, '10')
+@SupportedBrowser(SupportedBrowser.SAFARI)
+@Native("HTMLTrackElement")
+class TrackElement extends HtmlElement {
+  // To suppress missing implicit constructor warnings.
+  factory TrackElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory TrackElement() => document.createElement("track");
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  TrackElement.created() : super.created();
+
+  /// Checks if this type is supported on the current platform.
+  static bool get supported => Element.isTagSupported('track');
+
+  static const int ERROR = 3;
+
+  static const int LOADED = 2;
+
+  static const int LOADING = 1;
+
+  static const int NONE = 0;
+
+  @JSName('default')
+  bool defaultValue;
+
+  String kind;
+
+  String label;
+
+  final int readyState;
+
+  String src;
+
+  String srclang;
+
+  final TextTrack track;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("TrackEvent")
+class TrackEvent extends Event {
+  // To suppress missing implicit constructor warnings.
+  factory TrackEvent._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory TrackEvent(String type, [Map eventInitDict]) {
+    if (eventInitDict != null) {
+      var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+      return TrackEvent._create_1(type, eventInitDict_1);
+    }
+    return TrackEvent._create_2(type);
+  }
+  static TrackEvent _create_1(type, eventInitDict) =>
+      JS('TrackEvent', 'new TrackEvent(#,#)', type, eventInitDict);
+  static TrackEvent _create_2(type) =>
+      JS('TrackEvent', 'new TrackEvent(#)', type);
+
+  @Creates('Null')
+  final Object track;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("TransitionEvent,WebKitTransitionEvent")
+class TransitionEvent extends Event {
+  // To suppress missing implicit constructor warnings.
+  factory TransitionEvent._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory TransitionEvent(String type, [Map eventInitDict]) {
+    if (eventInitDict != null) {
+      var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+      return TransitionEvent._create_1(type, eventInitDict_1);
+    }
+    return TransitionEvent._create_2(type);
+  }
+  static TransitionEvent _create_1(type, eventInitDict) =>
+      JS('TransitionEvent', 'new TransitionEvent(#,#)', type, eventInitDict);
+  static TransitionEvent _create_2(type) =>
+      JS('TransitionEvent', 'new TransitionEvent(#)', type);
+
+  final num elapsedTime;
+
+  final String propertyName;
+
+  final String pseudoElement;
+}
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("TreeWalker")
+class TreeWalker extends Interceptor {
+  factory TreeWalker(Node root, int whatToShow) {
+    return document._createTreeWalker(root, whatToShow, null);
+  }
+  // To suppress missing implicit constructor warnings.
+  factory TreeWalker._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  Node currentNode;
+
+  final NodeFilter filter;
+
+  final Node root;
+
+  final int whatToShow;
+
+  Node firstChild() native;
+
+  Node lastChild() native;
+
+  Node nextNode() native;
+
+  Node nextSibling() native;
+
+  Node parentNode() native;
+
+  Node previousNode() native;
+
+  Node previousSibling() native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("TrustedHTML")
+class TrustedHtml extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory TrustedHtml._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  static TrustedHtml escape(String html) native;
+
+  static TrustedHtml unsafelyCreate(String html) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("TrustedScriptURL")
+class TrustedScriptUrl extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory TrustedScriptUrl._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  static TrustedScriptUrl unsafelyCreate(String url) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("TrustedURL")
+class TrustedUrl extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory TrustedUrl._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  static TrustedUrl create(String url) native;
+
+  static TrustedUrl unsafelyCreate(String url) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+@Native("UIEvent")
+class UIEvent extends Event {
+  // In JS, canBubble and cancelable are technically required parameters to
+  // init*Event. In practice, though, if they aren't provided they simply
+  // default to false (since that's Boolean(undefined)).
+  //
+  // Contrary to JS, we default canBubble and cancelable to true, since that's
+  // what people want most of the time anyway.
+  factory UIEvent(String type,
+      {Window view,
+      int detail: 0,
+      bool canBubble: true,
+      bool cancelable: true}) {
+    if (view == null) {
+      view = window;
+    }
+    UIEvent e = document._createEvent("UIEvent");
+    e._initUIEvent(type, canBubble, cancelable, view, detail);
+    return e;
+  }
+
+  factory UIEvent._(String type, [Map eventInitDict]) {
+    if (eventInitDict != null) {
+      var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+      return UIEvent._create_1(type, eventInitDict_1);
+    }
+    return UIEvent._create_2(type);
+  }
+  static UIEvent _create_1(type, eventInitDict) =>
+      JS('UIEvent', 'new UIEvent(#,#)', type, eventInitDict);
+  static UIEvent _create_2(type) => JS('UIEvent', 'new UIEvent(#)', type);
+
+  final int detail;
+
+  final InputDeviceCapabilities sourceCapabilities;
+
+  WindowBase get view => _convertNativeToDart_Window(this._get_view);
+  @JSName('view')
+  @Creates('Window|=Object')
+  @Returns('Window|=Object')
+  final dynamic _get_view;
+
+  @JSName('which')
+  @Unstable()
+  final int _which;
+
+  @JSName('initUIEvent')
+  void _initUIEvent(String type, bool bubbles, bool cancelable, Window view,
+      int detail) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("HTMLUListElement")
+class UListElement extends HtmlElement {
+  // To suppress missing implicit constructor warnings.
+  factory UListElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory UListElement() => JS(
+      'returns:UListElement;creates:UListElement;new:true',
+      '#.createElement(#)',
+      document,
+      "ul");
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  UListElement.created() : super.created();
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("UnderlyingSourceBase")
+class UnderlyingSourceBase extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory UnderlyingSourceBase._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  Future cancel(Object reason) =>
+      promiseToFuture(JS("", "#.cancel(#)", this, reason));
+
+  void notifyLockAcquired() native;
+
+  void notifyLockReleased() native;
+
+  Future pull() => promiseToFuture(JS("", "#.pull()", this));
+
+  Future start(Object stream) =>
+      promiseToFuture(JS("", "#.start(#)", this, stream));
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("HTMLUnknownElement")
+class UnknownElement extends HtmlElement {
+  // To suppress missing implicit constructor warnings.
+  factory UnknownElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  UnknownElement.created() : super.created();
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("URL")
+class Url extends Interceptor {
+  static String createObjectUrl(blob_OR_source_OR_stream) => JS(
+      'String',
+      '(self.URL || self.webkitURL).createObjectURL(#)',
+      blob_OR_source_OR_stream);
+
+  static String createObjectUrlFromSource(MediaSource source) =>
+      JS('String', '(self.URL || self.webkitURL).createObjectURL(#)', source);
+
+  static String createObjectUrlFromStream(MediaStream stream) =>
+      JS('String', '(self.URL || self.webkitURL).createObjectURL(#)', stream);
+
+  static String createObjectUrlFromBlob(Blob blob) =>
+      JS('String', '(self.URL || self.webkitURL).createObjectURL(#)', blob);
+
+  static void revokeObjectUrl(String url) =>
+      JS('void', '(self.URL || self.webkitURL).revokeObjectURL(#)', url);
+
+  String toString() => JS('String', 'String(#)', this);
+
+  // To suppress missing implicit constructor warnings.
+  factory Url._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  String hash;
+
+  String host;
+
+  String hostname;
+
+  String href;
+
+  final String origin;
+
+  String password;
+
+  String pathname;
+
+  String port;
+
+  String protocol;
+
+  String search;
+
+  final UrlSearchParams searchParams;
+
+  String username;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("URLSearchParams")
+class UrlSearchParams extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory UrlSearchParams._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory UrlSearchParams([Object init]) {
+    if (init != null) {
+      return UrlSearchParams._create_1(init);
+    }
+    return UrlSearchParams._create_2();
+  }
+  static UrlSearchParams _create_1(init) =>
+      JS('UrlSearchParams', 'new URLSearchParams(#)', init);
+  static UrlSearchParams _create_2() =>
+      JS('UrlSearchParams', 'new URLSearchParams()');
+
+  void append(String name, String value) native;
+
+  void delete(String name) native;
+
+  String get(String name) native;
+
+  List<String> getAll(String name) native;
+
+  bool has(String name) native;
+
+  void set(String name, String value) native;
+
+  void sort() native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+abstract class UrlUtilsReadOnly extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory UrlUtilsReadOnly._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final String hash;
+
+  final String host;
+
+  final String hostname;
+
+  final String href;
+
+  final String origin;
+
+  final String pathname;
+
+  final String port;
+
+  final String protocol;
+
+  final String search;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("VR")
+class VR extends EventTarget {
+  // To suppress missing implicit constructor warnings.
+  factory VR._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  Future getDevices() => promiseToFuture(JS("", "#.getDevices()", this));
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("VRCoordinateSystem")
+class VRCoordinateSystem extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory VRCoordinateSystem._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  Float32List getTransformTo(VRCoordinateSystem other) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("VRDevice")
+class VRDevice extends EventTarget {
+  // To suppress missing implicit constructor warnings.
+  factory VRDevice._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final String deviceName;
+
+  final bool isExternal;
+
+  Future requestSession([Map options]) {
+    var options_dict = null;
+    if (options != null) {
+      options_dict = convertDartToNative_Dictionary(options);
+    }
+    return promiseToFuture(JS("", "#.requestSession(#)", this, options_dict));
+  }
+
+  Future supportsSession([Map options]) {
+    var options_dict = null;
+    if (options != null) {
+      options_dict = convertDartToNative_Dictionary(options);
+    }
+    return promiseToFuture(JS("", "#.supportsSession(#)", this, options_dict));
+  }
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("VRDeviceEvent")
+class VRDeviceEvent extends Event {
+  // To suppress missing implicit constructor warnings.
+  factory VRDeviceEvent._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory VRDeviceEvent(String type, Map eventInitDict) {
+    var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+    return VRDeviceEvent._create_1(type, eventInitDict_1);
+  }
+  static VRDeviceEvent _create_1(type, eventInitDict) =>
+      JS('VRDeviceEvent', 'new VRDeviceEvent(#,#)', type, eventInitDict);
+
+  final VRDevice device;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("VRDisplay")
+class VRDisplay extends EventTarget {
+  // To suppress missing implicit constructor warnings.
+  factory VRDisplay._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final VRDisplayCapabilities capabilities;
+
+  num depthFar;
+
+  num depthNear;
+
+  final int displayId;
+
+  final String displayName;
+
+  final bool isPresenting;
+
+  final VRStageParameters stageParameters;
+
+  void cancelAnimationFrame(int handle) native;
+
+  Future exitPresent() => promiseToFuture(JS("", "#.exitPresent()", this));
+
+  VREyeParameters getEyeParameters(String whichEye) native;
+
+  bool getFrameData(VRFrameData frameData) native;
+
+  List<Map> getLayers() native;
+
+  int requestAnimationFrame(FrameRequestCallback callback) native;
+
+  Future requestPresent(List<Map> layers) =>
+      promiseToFuture(JS("", "#.requestPresent(#)", this, layers));
+
+  void submitFrame() native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("VRDisplayCapabilities")
+class VRDisplayCapabilities extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory VRDisplayCapabilities._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final bool canPresent;
+
+  final bool hasExternalDisplay;
+
+  final bool hasPosition;
+
+  final int maxLayers;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("VRDisplayEvent")
+class VRDisplayEvent extends Event {
+  // To suppress missing implicit constructor warnings.
+  factory VRDisplayEvent._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory VRDisplayEvent(String type, [Map eventInitDict]) {
+    if (eventInitDict != null) {
+      var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+      return VRDisplayEvent._create_1(type, eventInitDict_1);
+    }
+    return VRDisplayEvent._create_2(type);
+  }
+  static VRDisplayEvent _create_1(type, eventInitDict) =>
+      JS('VRDisplayEvent', 'new VRDisplayEvent(#,#)', type, eventInitDict);
+  static VRDisplayEvent _create_2(type) =>
+      JS('VRDisplayEvent', 'new VRDisplayEvent(#)', type);
+
+  final VRDisplay display;
+
+  final String reason;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("VREyeParameters")
+class VREyeParameters extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory VREyeParameters._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final Float32List offset;
+
+  final int renderHeight;
+
+  final int renderWidth;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("VRFrameData")
+class VRFrameData extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory VRFrameData._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory VRFrameData() {
+    return VRFrameData._create_1();
+  }
+  static VRFrameData _create_1() => JS('VRFrameData', 'new VRFrameData()');
+
+  final Float32List leftProjectionMatrix;
+
+  final Float32List leftViewMatrix;
+
+  final VRPose pose;
+
+  final Float32List rightProjectionMatrix;
+
+  final Float32List rightViewMatrix;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("VRFrameOfReference")
+class VRFrameOfReference extends VRCoordinateSystem {
+  // To suppress missing implicit constructor warnings.
+  factory VRFrameOfReference._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final VRStageBounds bounds;
+
+  final num emulatedHeight;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("VRPose")
+class VRPose extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory VRPose._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final Float32List angularAcceleration;
+
+  final Float32List angularVelocity;
+
+  final Float32List linearAcceleration;
+
+  final Float32List linearVelocity;
+
+  final Float32List orientation;
+
+  final Float32List position;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("VRSession")
+class VRSession extends EventTarget {
+  // To suppress missing implicit constructor warnings.
+  factory VRSession._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  static const EventStreamProvider<Event> blurEvent =
+      const EventStreamProvider<Event>('blur');
+
+  static const EventStreamProvider<Event> focusEvent =
+      const EventStreamProvider<Event>('focus');
+
+  num depthFar;
+
+  num depthNear;
+
+  final VRDevice device;
+
+  final bool exclusive;
+
+  Future end() => promiseToFuture(JS("", "#.end()", this));
+
+  Future requestFrameOfReference(String type, [Map options]) {
+    var options_dict = null;
+    if (options != null) {
+      options_dict = convertDartToNative_Dictionary(options);
+    }
+    return promiseToFuture(
+        JS("", "#.requestFrameOfReference(#, #)", this, type, options_dict));
+  }
+
+  Stream<Event> get onBlur => blurEvent.forTarget(this);
+
+  Stream<Event> get onFocus => focusEvent.forTarget(this);
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("VRSessionEvent")
+class VRSessionEvent extends Event {
+  // To suppress missing implicit constructor warnings.
+  factory VRSessionEvent._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory VRSessionEvent(String type, Map eventInitDict) {
+    var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+    return VRSessionEvent._create_1(type, eventInitDict_1);
+  }
+  static VRSessionEvent _create_1(type, eventInitDict) =>
+      JS('VRSessionEvent', 'new VRSessionEvent(#,#)', type, eventInitDict);
+
+  final VRSession session;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("VRStageBounds")
+class VRStageBounds extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory VRStageBounds._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final List<VRStageBoundsPoint> geometry;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("VRStageBoundsPoint")
+class VRStageBoundsPoint extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory VRStageBoundsPoint._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final num x;
+
+  final num z;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("VRStageParameters")
+class VRStageParameters extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory VRStageParameters._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final Float32List sittingToStandingTransform;
+
+  final num sizeX;
+
+  final num sizeZ;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("ValidityState")
+class ValidityState extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory ValidityState._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final bool badInput;
+
+  final bool customError;
+
+  final bool patternMismatch;
+
+  final bool rangeOverflow;
+
+  final bool rangeUnderflow;
+
+  final bool stepMismatch;
+
+  final bool tooLong;
+
+  final bool tooShort;
+
+  final bool typeMismatch;
+
+  final bool valid;
+
+  final bool valueMissing;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("HTMLVideoElement")
+class VideoElement extends MediaElement implements CanvasImageSource {
+  // To suppress missing implicit constructor warnings.
+  factory VideoElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory VideoElement() => JS(
+      'returns:VideoElement;creates:VideoElement;new:true',
+      '#.createElement(#)',
+      document,
+      "video");
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  VideoElement.created() : super.created();
+
+  int height;
+
+  String poster;
+
+  final int videoHeight;
+
+  final int videoWidth;
+
+  @JSName('webkitDecodedFrameCount')
+  @SupportedBrowser(SupportedBrowser.CHROME)
+  @SupportedBrowser(SupportedBrowser.SAFARI)
+  final int decodedFrameCount;
+
+  @JSName('webkitDroppedFrameCount')
+  @SupportedBrowser(SupportedBrowser.CHROME)
+  @SupportedBrowser(SupportedBrowser.SAFARI)
+  final int droppedFrameCount;
+
+  int width;
+
+  VideoPlaybackQuality getVideoPlaybackQuality() native;
+
+  @JSName('webkitEnterFullscreen')
+  @SupportedBrowser(SupportedBrowser.CHROME)
+  @SupportedBrowser(SupportedBrowser.SAFARI)
+  void enterFullscreen() native;
+
+  @JSName('webkitExitFullscreen')
+  @SupportedBrowser(SupportedBrowser.CHROME)
+  @SupportedBrowser(SupportedBrowser.SAFARI)
+  void exitFullscreen() native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("VideoPlaybackQuality")
+class VideoPlaybackQuality extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory VideoPlaybackQuality._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final int corruptedVideoFrames;
+
+  final num creationTime;
+
+  final int droppedVideoFrames;
+
+  final int totalVideoFrames;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("VideoTrack")
+class VideoTrack extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory VideoTrack._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final String id;
+
+  final String kind;
+
+  final String label;
+
+  final String language;
+
+  bool selected;
+
+  final SourceBuffer sourceBuffer;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("VideoTrackList")
+class VideoTrackList extends EventTarget {
+  // To suppress missing implicit constructor warnings.
+  factory VideoTrackList._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  static const EventStreamProvider<Event> changeEvent =
+      const EventStreamProvider<Event>('change');
+
+  final int length;
+
+  final int selectedIndex;
+
+  VideoTrack __getter__(int index) native;
+
+  VideoTrack getTrackById(String id) native;
+
+  Stream<Event> get onChange => changeEvent.forTarget(this);
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("VisualViewport")
+class VisualViewport extends EventTarget {
+  // To suppress missing implicit constructor warnings.
+  factory VisualViewport._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  static const EventStreamProvider<Event> resizeEvent =
+      const EventStreamProvider<Event>('resize');
+
+  static const EventStreamProvider<Event> scrollEvent =
+      const EventStreamProvider<Event>('scroll');
+
+  final num height;
+
+  final num offsetLeft;
+
+  final num offsetTop;
+
+  final num pageLeft;
+
+  final num pageTop;
+
+  final num scale;
+
+  final num width;
+
+  Stream<Event> get onResize => resizeEvent.forTarget(this);
+
+  Stream<Event> get onScroll => scrollEvent.forTarget(this);
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+typedef void VoidCallback();
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("VTTCue")
+class VttCue extends TextTrackCue {
+  // To suppress missing implicit constructor warnings.
+  factory VttCue._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory VttCue(num startTime, num endTime, String text) {
+    return VttCue._create_1(startTime, endTime, text);
+  }
+  static VttCue _create_1(startTime, endTime, text) =>
+      JS('VttCue', 'new VTTCue(#,#,#)', startTime, endTime, text);
+
+  String align;
+
+  @Creates('Null')
+  @Returns('num|String')
+  Object line;
+
+  @Creates('Null')
+  @Returns('num|String')
+  Object position;
+
+  VttRegion region;
+
+  num size;
+
+  bool snapToLines;
+
+  String text;
+
+  String vertical;
+
+  @JSName('getCueAsHTML')
+  DocumentFragment getCueAsHtml() native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("VTTRegion")
+class VttRegion extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory VttRegion._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory VttRegion() {
+    return VttRegion._create_1();
+  }
+  static VttRegion _create_1() => JS('VttRegion', 'new VTTRegion()');
+
+  String id;
+
+  int lines;
+
+  num regionAnchorX;
+
+  num regionAnchorY;
+
+  String scroll;
+
+  num viewportAnchorX;
+
+  num viewportAnchorY;
+
+  num width;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/**
+ * Use the WebSocket interface to connect to a WebSocket,
+ * and to send and receive data on that WebSocket.
+ *
+ * To use a WebSocket in your web app, first create a WebSocket object,
+ * passing the WebSocket URL as an argument to the constructor.
+ *
+ *     var webSocket = new WebSocket('ws://127.0.0.1:1337/ws');
+ *
+ * To send data on the WebSocket, use the [send] method.
+ *
+ *     if (webSocket != null && webSocket.readyState == WebSocket.OPEN) {
+ *       webSocket.send(data);
+ *     } else {
+ *       print('WebSocket not connected, message $data not sent');
+ *     }
+ *
+ * To receive data on the WebSocket, register a listener for message events.
+ *
+ *     webSocket.onMessage.listen((MessageEvent e) {
+ *       receivedData(e.data);
+ *     });
+ *
+ * The message event handler receives a [MessageEvent] object
+ * as its sole argument.
+ * You can also define open, close, and error handlers,
+ * as specified by [WebSocketEvents].
+ *
+ * For more information, see the
+ * [WebSockets](http://www.dartlang.org/docs/library-tour/#html-websockets)
+ * section of the library tour and
+ * [Introducing WebSockets](http://www.html5rocks.com/en/tutorials/websockets/basics/),
+ * an HTML5Rocks.com tutorial.
+ */
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.FIREFOX)
+@SupportedBrowser(SupportedBrowser.IE, '10')
+@SupportedBrowser(SupportedBrowser.SAFARI)
+@Unstable()
+@Native("WebSocket")
+class WebSocket extends EventTarget {
+  // To suppress missing implicit constructor warnings.
+  factory WebSocket._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  /**
+   * Static factory designed to expose `close` events to event
+   * handlers that are not necessarily instances of [WebSocket].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<CloseEvent> closeEvent =
+      const EventStreamProvider<CloseEvent>('close');
+
+  /**
+   * Static factory designed to expose `error` events to event
+   * handlers that are not necessarily instances of [WebSocket].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<Event> errorEvent =
+      const EventStreamProvider<Event>('error');
+
+  /**
+   * Static factory designed to expose `message` events to event
+   * handlers that are not necessarily instances of [WebSocket].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<MessageEvent> messageEvent =
+      const EventStreamProvider<MessageEvent>('message');
+
+  /**
+   * Static factory designed to expose `open` events to event
+   * handlers that are not necessarily instances of [WebSocket].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<Event> openEvent =
+      const EventStreamProvider<Event>('open');
+
+  factory WebSocket(String url, [Object protocols]) {
+    if (protocols != null) {
+      return WebSocket._create_1(url, protocols);
+    }
+    return WebSocket._create_2(url);
+  }
+  static WebSocket _create_1(url, protocols) =>
+      JS('WebSocket', 'new WebSocket(#,#)', url, protocols);
+  static WebSocket _create_2(url) => JS('WebSocket', 'new WebSocket(#)', url);
+
+  /// Checks if this type is supported on the current platform.
+  static bool get supported =>
+      JS('bool', 'typeof window.WebSocket != "undefined"');
+
+  static const int CLOSED = 3;
+
+  static const int CLOSING = 2;
+
+  static const int CONNECTING = 0;
+
+  static const int OPEN = 1;
+
+  String binaryType;
+
+  final int bufferedAmount;
+
+  final String extensions;
+
+  final String protocol;
+
+  final int readyState;
+
+  final String url;
+
+  void close([int code, String reason]) native;
+
+  /**
+   * Transmit data to the server over this connection.
+   *
+   * This method accepts data of type [Blob], [ByteBuffer], [String], or
+   * [TypedData]. Named variants [sendBlob], [sendByteBuffer], [sendString],
+   * or [sendTypedData], in contrast, only accept data of the specified type.
+   */
+  void send(data) native;
+
+  @JSName('send')
+  /**
+   * Transmit data to the server over this connection.
+   *
+   * This method accepts data of type [Blob], [ByteBuffer], [String], or
+   * [TypedData]. Named variants [sendBlob], [sendByteBuffer], [sendString],
+   * or [sendTypedData], in contrast, only accept data of the specified type.
+   */
+  void sendBlob(Blob data) native;
+
+  @JSName('send')
+  /**
+   * Transmit data to the server over this connection.
+   *
+   * This method accepts data of type [Blob], [ByteBuffer], [String], or
+   * [TypedData]. Named variants [sendBlob], [sendByteBuffer], [sendString],
+   * or [sendTypedData], in contrast, only accept data of the specified type.
+   */
+  void sendByteBuffer(ByteBuffer data) native;
+
+  @JSName('send')
+  /**
+   * Transmit data to the server over this connection.
+   *
+   * This method accepts data of type [Blob], [ByteBuffer], [String], or
+   * [TypedData]. Named variants [sendBlob], [sendByteBuffer], [sendString],
+   * or [sendTypedData], in contrast, only accept data of the specified type.
+   */
+  void sendString(String data) native;
+
+  @JSName('send')
+  /**
+   * Transmit data to the server over this connection.
+   *
+   * This method accepts data of type [Blob], [ByteBuffer], [String], or
+   * [TypedData]. Named variants [sendBlob], [sendByteBuffer], [sendString],
+   * or [sendTypedData], in contrast, only accept data of the specified type.
+   */
+  void sendTypedData(TypedData data) native;
+
+  /// Stream of `close` events handled by this [WebSocket].
+  Stream<CloseEvent> get onClose => closeEvent.forTarget(this);
+
+  /// Stream of `error` events handled by this [WebSocket].
+  Stream<Event> get onError => errorEvent.forTarget(this);
+
+  /// Stream of `message` events handled by this [WebSocket].
+  Stream<MessageEvent> get onMessage => messageEvent.forTarget(this);
+
+  /// Stream of `open` events handled by this [WebSocket].
+  Stream<Event> get onOpen => openEvent.forTarget(this);
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("WheelEvent")
+class WheelEvent extends MouseEvent {
+  factory WheelEvent(String type,
+      {Window view,
+      num deltaX: 0,
+      num deltaY: 0,
+      num deltaZ: 0,
+      int deltaMode: 0,
+      int detail: 0,
+      int screenX: 0,
+      int screenY: 0,
+      int clientX: 0,
+      int clientY: 0,
+      int button: 0,
+      bool canBubble: true,
+      bool cancelable: true,
+      bool ctrlKey: false,
+      bool altKey: false,
+      bool shiftKey: false,
+      bool metaKey: false,
+      EventTarget relatedTarget}) {
+    var options = {
+      'view': view,
+      'deltaMode': deltaMode,
+      'deltaX': deltaX,
+      'deltaY': deltaY,
+      'deltaZ': deltaZ,
+      'detail': detail,
+      'screenX': screenX,
+      'screenY': screenY,
+      'clientX': clientX,
+      'clientY': clientY,
+      'button': button,
+      'bubbles': canBubble,
+      'cancelable': cancelable,
+      'ctrlKey': ctrlKey,
+      'altKey': altKey,
+      'shiftKey': shiftKey,
+      'metaKey': metaKey,
+      'relatedTarget': relatedTarget,
+    };
+
+    if (view == null) {
+      view = window;
+    }
+
+    return JS('WheelEvent', 'new WheelEvent(#, #)', type,
+        convertDartToNative_Dictionary(options));
+  }
+
+  factory WheelEvent._(String type, [Map eventInitDict]) {
+    if (eventInitDict != null) {
+      var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+      return WheelEvent._create_1(type, eventInitDict_1);
+    }
+    return WheelEvent._create_2(type);
+  }
+  static WheelEvent _create_1(type, eventInitDict) =>
+      JS('WheelEvent', 'new WheelEvent(#,#)', type, eventInitDict);
+  static WheelEvent _create_2(type) =>
+      JS('WheelEvent', 'new WheelEvent(#)', type);
+
+  static const int DOM_DELTA_LINE = 0x01;
+
+  static const int DOM_DELTA_PAGE = 0x02;
+
+  static const int DOM_DELTA_PIXEL = 0x00;
+
+  @JSName('deltaX')
+  final num _deltaX;
+
+  @JSName('deltaY')
+  final num _deltaY;
+
+  final num deltaZ;
+
+  /**
+   * The amount that is expected to scroll vertically, in units determined by
+   * [deltaMode].
+   *
+   * See also:
+   *
+   * * [WheelEvent.deltaY](http://dev.w3.org/2006/webapi/DOM-Level-3-Events/html/DOM3-Events.html#events-WheelEvent-deltaY) from the W3C.
+   */
+  num get deltaY {
+    if (JS('bool', '#.deltaY !== undefined', this)) {
+      // W3C WheelEvent
+      return this._deltaY;
+    }
+    throw new UnsupportedError('deltaY is not supported');
+  }
+
+  /**
+   * The amount that is expected to scroll horizontally, in units determined by
+   * [deltaMode].
+   *
+   * See also:
+   *
+   * * [WheelEvent.deltaX](http://dev.w3.org/2006/webapi/DOM-Level-3-Events/html/DOM3-Events.html#events-WheelEvent-deltaX) from the W3C.
+   */
+  num get deltaX {
+    if (JS('bool', '#.deltaX !== undefined', this)) {
+      // W3C WheelEvent
+      return this._deltaX;
+    }
+    throw new UnsupportedError('deltaX is not supported');
+  }
+
+  int get deltaMode {
+    if (JS('bool', '!!(#.deltaMode)', this)) {
+      return JS('int', '#.deltaMode', this);
+    }
+    // If not available then we're poly-filling and doing pixel scroll.
+    return 0;
+  }
+
+  num get _wheelDelta => JS('num', '#.wheelDelta', this);
+  num get _wheelDeltaX => JS('num', '#.wheelDeltaX', this);
+  num get _detail => JS('num', '#.detail', this);
+
+  bool get _hasInitMouseScrollEvent =>
+      JS('bool', '!!(#.initMouseScrollEvent)', this);
+
+  @JSName('initMouseScrollEvent')
+  void _initMouseScrollEvent(
+      String type,
+      bool canBubble,
+      bool cancelable,
+      Window view,
+      int detail,
+      int screenX,
+      int screenY,
+      int clientX,
+      int clientY,
+      bool ctrlKey,
+      bool altKey,
+      bool shiftKey,
+      bool metaKey,
+      int button,
+      EventTarget relatedTarget,
+      int axis) native;
+
+  bool get _hasInitWheelEvent => JS('bool', '!!(#.initWheelEvent)', this);
+  @JSName('initWheelEvent')
+  void _initWheelEvent(
+      String eventType,
+      bool canBubble,
+      bool cancelable,
+      Window view,
+      int detail,
+      int screenX,
+      int screenY,
+      int clientX,
+      int clientY,
+      int button,
+      EventTarget relatedTarget,
+      String modifiersList,
+      int deltaX,
+      int deltaY,
+      int deltaZ,
+      int deltaMode) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/**
+ * Top-level container for the current browser tab or window.
+ *
+ * In a web browser, each window has a [Window] object, but within the context
+ * of a script, this object represents only the current window.
+ * Each other window, tab, and iframe has its own [Window] object.
+ *
+ * Each window contains a [Document] object, which contains all of the window's
+ * content.
+ *
+ * Use the top-level `window` object to access the current window.
+ * For example:
+ *
+ *     // Draw a scene when the window repaints.
+ *     drawScene(num delta) {...}
+ *     window.animationFrame.then(drawScene);.
+ *
+ *     // Write to the console.
+ *     window.console.log('Jinkies!');
+ *     window.console.error('Jeepers!');
+ *
+ * **Note:** This class represents only the current window, while [WindowBase]
+ * is a representation of any window, including other tabs, windows, and frames.
+ *
+ * ## See also
+ *
+ * * [WindowBase]
+ *
+ * ## Other resources
+ *
+ * * [DOM Window](https://developer.mozilla.org/en-US/docs/DOM/window) from MDN.
+ * * [Window](http://www.w3.org/TR/Window/) from the W3C.
+ */
+@Native("Window,DOMWindow")
+class Window extends EventTarget
+    implements
+        WindowEventHandlers,
+        WindowBase,
+        GlobalEventHandlers,
+        _WindowTimers,
+        WindowBase64 {
+  /**
+   * Returns a Future that completes just before the window is about to
+   * repaint so the user can draw an animation frame.
+   *
+   * If you need to later cancel this animation, use [requestAnimationFrame]
+   * instead.
+   *
+   * The [Future] completes to a timestamp that represents a floating
+   * point value of the number of milliseconds that have elapsed since the page
+   * started to load (which is also the timestamp at this call to
+   * animationFrame).
+   *
+   * Note: The code that runs when the future completes should call
+   * [animationFrame] again for the animation to continue.
+   */
+  Future<num> get animationFrame {
+    var completer = new Completer<num>.sync();
+    requestAnimationFrame((time) {
+      completer.complete(time);
+    });
+    return completer.future;
+  }
+
+  /**
+   * The newest document in this window.
+   *
+   * ## Other resources
+   *
+   * * [Loading web
+   *   pages](https://html.spec.whatwg.org/multipage/browsers.html)
+   *   from WHATWG.
+   */
+  Document get document => JS('Document', '#.document', this);
+
+  WindowBase _open2(url, name) =>
+      JS('Window|Null', '#.open(#,#)', this, url, name);
+
+  WindowBase _open3(url, name, options) =>
+      JS('Window|Null', '#.open(#,#,#)', this, url, name, options);
+
+  /**
+   * Opens a new window.
+   *
+   * ## Other resources
+   *
+   * * [Window.open](https://developer.mozilla.org/en-US/docs/Web/API/Window.open)
+   *   from MDN.
+   */
+  WindowBase open(String url, String name, [String options]) {
+    if (options == null) {
+      return _DOMWindowCrossFrame._createSafe(_open2(url, name));
+    } else {
+      return _DOMWindowCrossFrame._createSafe(_open3(url, name, options));
+    }
+  }
+
+  // API level getter and setter for Location.
+  // TODO: The cross domain safe wrapper can be inserted here.
+  /**
+   * The current location of this window.
+   *
+   *     Location currentLocation = window.location;
+   *     print(currentLocation.href); // 'http://www.example.com:80/'
+   */
+  Location get location => _location;
+
+  // TODO: consider forcing users to do: window.location.assign('string').
+  /**
+   * Sets the window's location, which causes the browser to navigate to the new
+   * location.
+   */
+  set location(value) {
+    _location = value;
+  }
+
+  // Native getter and setter to access raw Location object.
+  dynamic get _location => JS('Location|Null', '#.location', this);
+  set _location(value) {
+    JS('void', '#.location = #', this, value);
+  }
+
+  /**
+   * Called to draw an animation frame and then request the window to repaint
+   * after [callback] has finished (creating the animation).
+   *
+   * Use this method only if you need to later call [cancelAnimationFrame]. If
+   * not, the preferred Dart idiom is to set animation frames by calling
+   * [animationFrame], which returns a Future.
+   *
+   * Returns a non-zero valued integer to represent the request id for this
+   * request. This value only needs to be saved if you intend to call
+   * [cancelAnimationFrame] so you can specify the particular animation to
+   * cancel.
+   *
+   * Note: The supplied [callback] needs to call [requestAnimationFrame] again
+   * for the animation to continue.
+   */
+  int requestAnimationFrame(FrameRequestCallback callback) {
+    _ensureRequestAnimationFrame();
+    return _requestAnimationFrame(_wrapZone(callback));
+  }
+
+  /**
+   * Cancels an animation frame request.
+   *
+   * ## Other resources
+   *
+   * * [Window.cancelAnimationFrame](https://developer.mozilla.org/en-US/docs/Web/API/Window.cancelAnimationFrame)
+   *   from MDN.
+   */
+  void cancelAnimationFrame(int id) {
+    _ensureRequestAnimationFrame();
+    _cancelAnimationFrame(id);
+  }
+
+  @JSName('requestAnimationFrame')
+  int _requestAnimationFrame(FrameRequestCallback callback) native;
+
+  @JSName('cancelAnimationFrame')
+  void _cancelAnimationFrame(int id) native;
+
+  _ensureRequestAnimationFrame() {
+    if (JS<bool>(
+        'bool',
+        '!!(#.requestAnimationFrame && #.cancelAnimationFrame)',
+        this,
+        this)) return;
+
+    JS(
+        'void',
+        r"""
+  (function($this) {
+   var vendors = ['ms', 'moz', 'webkit', 'o'];
+   for (var i = 0; i < vendors.length && !$this.requestAnimationFrame; ++i) {
+     $this.requestAnimationFrame = $this[vendors[i] + 'RequestAnimationFrame'];
+     $this.cancelAnimationFrame =
+         $this[vendors[i]+'CancelAnimationFrame'] ||
+         $this[vendors[i]+'CancelRequestAnimationFrame'];
+   }
+   if ($this.requestAnimationFrame && $this.cancelAnimationFrame) return;
+   $this.requestAnimationFrame = function(callback) {
+      return window.setTimeout(function() {
+        callback(Date.now());
+      }, 16 /* 16ms ~= 60fps */);
+   };
+   $this.cancelAnimationFrame = function(id) { clearTimeout(id); }
+  })(#)""",
+        this);
+  }
+
+  /**
+   * Gets an instance of the Indexed DB factory to being using Indexed DB.
+   *
+   * Use [indexed_db.IdbFactory.supported] to check if Indexed DB is supported on the
+   * current platform.
+   */
+  @SupportedBrowser(SupportedBrowser.CHROME, '23.0')
+  @SupportedBrowser(SupportedBrowser.FIREFOX, '15.0')
+  @SupportedBrowser(SupportedBrowser.IE, '10.0')
+  IdbFactory get indexedDB => JS(
+      'IdbFactory|Null', // If not supported, returns null.
+      '#.indexedDB || #.webkitIndexedDB || #.mozIndexedDB',
+      this,
+      this,
+      this);
+
+  /// The debugging console for this window.
+  Console get console => Console._safeConsole;
+
+  /**
+   * Access a sandboxed file system of `size` bytes.
+   *
+   * If `persistent` is true, the application will request permission from the
+   * user to create lasting storage. This storage cannot be freed without the
+   * user's permission. Returns a [Future] whose value stores a reference to
+   * the sandboxed file system for use. Because the file system is sandboxed,
+   * applications cannot access file systems created in other web pages.
+   */
+  Future<FileSystem> requestFileSystem(int size, {bool persistent: false}) {
+    return _requestFileSystem(persistent ? 1 : 0, size);
+  }
+
+  /**
+   * convertPointFromNodeToPage and convertPointFromPageToNode are removed.
+   * see http://dev.w3.org/csswg/cssom-view/#geometry
+   */
+  static bool get supportsPointConversions => DomPoint.supported;
+  // To suppress missing implicit constructor warnings.
+  factory Window._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  /**
+   * Static factory designed to expose `contentloaded` events to event
+   * handlers that are not necessarily instances of [Window].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<Event> contentLoadedEvent =
+      const EventStreamProvider<Event>('DOMContentLoaded');
+
+  /**
+   * Static factory designed to expose `devicemotion` events to event
+   * handlers that are not necessarily instances of [Window].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<DeviceMotionEvent> deviceMotionEvent =
+      const EventStreamProvider<DeviceMotionEvent>('devicemotion');
+
+  /**
+   * Static factory designed to expose `deviceorientation` events to event
+   * handlers that are not necessarily instances of [Window].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<DeviceOrientationEvent>
+      deviceOrientationEvent =
+      const EventStreamProvider<DeviceOrientationEvent>('deviceorientation');
+
+  /**
+   * Static factory designed to expose `hashchange` events to event
+   * handlers that are not necessarily instances of [Window].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<Event> hashChangeEvent =
+      const EventStreamProvider<Event>('hashchange');
+
+  static const EventStreamProvider<Event> loadStartEvent =
+      const EventStreamProvider<Event>('loadstart');
+
+  /**
+   * Static factory designed to expose `message` events to event
+   * handlers that are not necessarily instances of [Window].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<MessageEvent> messageEvent =
+      const EventStreamProvider<MessageEvent>('message');
+
+  /**
+   * Static factory designed to expose `offline` events to event
+   * handlers that are not necessarily instances of [Window].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<Event> offlineEvent =
+      const EventStreamProvider<Event>('offline');
+
+  /**
+   * Static factory designed to expose `online` events to event
+   * handlers that are not necessarily instances of [Window].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<Event> onlineEvent =
+      const EventStreamProvider<Event>('online');
+
+  /**
+   * Static factory designed to expose `pagehide` events to event
+   * handlers that are not necessarily instances of [Window].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<Event> pageHideEvent =
+      const EventStreamProvider<Event>('pagehide');
+
+  /**
+   * Static factory designed to expose `pageshow` events to event
+   * handlers that are not necessarily instances of [Window].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<Event> pageShowEvent =
+      const EventStreamProvider<Event>('pageshow');
+
+  /**
+   * Static factory designed to expose `popstate` events to event
+   * handlers that are not necessarily instances of [Window].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<PopStateEvent> popStateEvent =
+      const EventStreamProvider<PopStateEvent>('popstate');
+
+  static const EventStreamProvider<Event> progressEvent =
+      const EventStreamProvider<Event>('progress');
+
+  /**
+   * Static factory designed to expose `storage` events to event
+   * handlers that are not necessarily instances of [Window].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<StorageEvent> storageEvent =
+      const EventStreamProvider<StorageEvent>('storage');
+
+  /**
+   * Static factory designed to expose `unload` events to event
+   * handlers that are not necessarily instances of [Window].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<Event> unloadEvent =
+      const EventStreamProvider<Event>('unload');
+
+  /**
+   * Static factory designed to expose `animationend` events to event
+   * handlers that are not necessarily instances of [Window].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  @SupportedBrowser(SupportedBrowser.CHROME)
+  @SupportedBrowser(SupportedBrowser.SAFARI)
+  static const EventStreamProvider<AnimationEvent> animationEndEvent =
+      const EventStreamProvider<AnimationEvent>('webkitAnimationEnd');
+
+  /**
+   * Static factory designed to expose `animationiteration` events to event
+   * handlers that are not necessarily instances of [Window].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  @SupportedBrowser(SupportedBrowser.CHROME)
+  @SupportedBrowser(SupportedBrowser.SAFARI)
+  static const EventStreamProvider<AnimationEvent> animationIterationEvent =
+      const EventStreamProvider<AnimationEvent>('webkitAnimationIteration');
+
+  /**
+   * Static factory designed to expose `animationstart` events to event
+   * handlers that are not necessarily instances of [Window].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  @SupportedBrowser(SupportedBrowser.CHROME)
+  @SupportedBrowser(SupportedBrowser.SAFARI)
+  static const EventStreamProvider<AnimationEvent> animationStartEvent =
+      const EventStreamProvider<AnimationEvent>('webkitAnimationStart');
+
+  /**
+   * Indicates that file system data cannot be cleared unless given user
+   * permission.
+   *
+   * ## Other resources
+   *
+   * * [Exploring the FileSystem
+   *   APIs](http://www.html5rocks.com/en/tutorials/file/filesystem/)
+   *   from HTML5Rocks.
+   * * [File API](http://www.w3.org/TR/file-system-api/#idl-def-LocalFileSystem)
+   *   from W3C.
+   */
+  static const int PERSISTENT = 1;
+
+  /**
+   * Indicates that file system data can be cleared at any time.
+   *
+   * ## Other resources
+   *
+   * * [Exploring the FileSystem
+   *   APIs](http://www.html5rocks.com/en/tutorials/file/filesystem/) from HTML5Rocks.
+   * * [File API](http://www.w3.org/TR/file-system-api/#idl-def-LocalFileSystem)
+   *   from W3C.
+   */
+  static const int TEMPORARY = 0;
+
+  final _Worklet animationWorklet;
+
+  /**
+   * The application cache for this window.
+   *
+   * ## Other resources
+   *
+   * * [A beginner's guide to using the application
+   *   cache](http://www.html5rocks.com/en/tutorials/appcache/beginner)
+   *   from HTML5Rocks.
+   * * [Application cache
+   *   API](https://html.spec.whatwg.org/multipage/browsers.html#application-cache-api)
+   *   from WHATWG.
+   */
+  final ApplicationCache applicationCache;
+
+  final _Worklet audioWorklet;
+
+  final CacheStorage caches;
+
+  final bool closed;
+
+  final CookieStore cookieStore;
+
+  /**
+   * Entrypoint for the browser's cryptographic functions.
+   *
+   * ## Other resources
+   *
+   * * [Web cryptography API](http://www.w3.org/TR/WebCryptoAPI/) from W3C.
+   */
+  final Crypto crypto;
+
+  final CustomElementRegistry customElements;
+
+  /// *Deprecated*.
+  String defaultStatus;
+
+  /// *Deprecated*.
+  String defaultstatus;
+
+  /**
+   * The ratio between physical pixels and logical CSS pixels.
+   *
+   * ## Other resources
+   *
+   * * [devicePixelRatio](http://www.quirksmode.org/blog/archives/2012/06/devicepixelrati.html)
+   *   from quirksmode.
+   * * [More about devicePixelRatio](http://www.quirksmode.org/blog/archives/2012/07/more_about_devi.html)
+   *   from quirksmode.
+   */
+  final num devicePixelRatio;
+
+  final External external;
+
+  /**
+   * The current session history for this window's newest document.
+   *
+   * ## Other resources
+   *
+   * * [Loading web pages](https://html.spec.whatwg.org/multipage/browsers.html)
+   *   from WHATWG.
+   */
+  final History history;
+
+  /**
+   * The height of the viewport including scrollbars.
+   *
+   * ## Other resources
+   *
+   * * [Window.innerHeight](https://developer.mozilla.org/en-US/docs/Web/API/Window/innerHeight)
+   *   from MDN.
+   */
+  final int innerHeight;
+
+  /**
+   * The width of the viewport including scrollbars.
+   *
+   * ## Other resources
+   *
+   * * [Window.innerWidth](https://developer.mozilla.org/en-US/docs/Web/API/Window/innerWidth)
+   *   from MDN.
+   */
+  final int innerWidth;
+
+  final bool isSecureContext;
+
+  /**
+   * Storage for this window that persists across sessions.
+   *
+   * ## Other resources
+   *
+   * * [DOM storage guide](https://developer.mozilla.org/en-US/docs/Web/Guide/API/DOM/Storage)
+   *   from MDN.
+   * * [The past, present & future of local storage for web
+   *   applications](http://diveintohtml5.info/storage.html) from Dive Into HTML5.
+   * * [Local storage specification](http://www.w3.org/TR/webstorage/#the-localstorage-attribute)
+   *   from W3C.
+   */
+  final Storage localStorage;
+
+  /**
+   * This window's location bar, which displays the URL.
+   *
+   * ## Other resources
+   *
+   * * [Browser interface
+   *   elements](https://html.spec.whatwg.org/multipage/browsers.html#browser-interface-elements)
+   *   from WHATWG.
+   */
+  final BarProp locationbar;
+
+  /**
+   * This window's menu bar, which displays menu commands.
+   *
+   * ## Other resources
+   *
+   * * [Browser interface
+   *   elements](https://html.spec.whatwg.org/multipage/browsers.html#browser-interface-elements)
+   *   from WHATWG.
+   */
+  final BarProp menubar;
+
+  /**
+   * The name of this window.
+   *
+   * ## Other resources
+   *
+   * * [Window.name](https://developer.mozilla.org/en-US/docs/Web/API/Window/name)
+   *   from MDN.
+   */
+  String name;
+
+  /**
+   * The user agent accessing this window.
+   *
+   * ## Other resources
+   *
+   * * [The navigator
+   *   object](https://html.spec.whatwg.org/multipage/webappapis.html#the-navigator-object)
+   *   from WHATWG.
+   */
+  final Navigator navigator;
+
+  /**
+   * Whether objects are drawn offscreen before being displayed.
+   *
+   * ## Other resources
+   *
+   * * [offscreenBuffering](https://webplatform.github.io/docs/dom/HTMLElement/offscreenBuffering/)
+   *   from WebPlatform.org.
+   */
+  final bool offscreenBuffering;
+
+  WindowBase get opener => _convertNativeToDart_Window(this._get_opener);
+  @JSName('opener')
+  @Creates('Window|=Object')
+  @Returns('Window|=Object')
+  final dynamic _get_opener;
+
+  set opener(Window value) {
+    JS("void", "#.opener = #", this, value);
+  }
+
+  final int orientation;
+
+  final String origin;
+
+  /**
+   * The height of this window including all user interface elements.
+   *
+   * ## Other resources
+   *
+   * * [Window.outerHeight](https://developer.mozilla.org/en-US/docs/Web/API/Window/outerHeight)
+   *   from MDN.
+   */
+  final int outerHeight;
+
+  /**
+   * The width of the window including all user interface elements.
+   *
+   * ## Other resources
+   *
+   * * [Window.outerWidth](https://developer.mozilla.org/en-US/docs/Web/API/Window/outerWidth)
+   *   from MDN.
+   */
+  final int outerWidth;
+
+  @JSName('pageXOffset')
+  /**
+   * The distance this window has been scrolled horizontally.
+   *
+   * This attribute is an alias for [scrollX].
+   *
+   * ## Other resources
+   *
+   * * [The Screen interface
+   *   specification](http://www.w3.org/TR/cssom-view/#screen) from W3C.
+   * * [scrollX and
+   *   pageXOffset](https://developer.mozilla.org/en-US/docs/Web/API/Window.scrollX)
+   *   from MDN.
+   */
+  final num _pageXOffset;
+
+  @JSName('pageYOffset')
+  /**
+   * The distance this window has been scrolled vertically.
+   *
+   * This attribute is an alias for [scrollY].
+   *
+   * ## Other resources
+   *
+   * * [The Screen interface
+   *   specification](http://www.w3.org/TR/cssom-view/#screen) from W3C.
+   * * [scrollY and
+   *   pageYOffset](https://developer.mozilla.org/en-US/docs/Web/API/Window.scrollY)
+   *   from MDN.
+   */
+  final num _pageYOffset;
+
+  WindowBase get parent => _convertNativeToDart_Window(this._get_parent);
+  @JSName('parent')
+  @Creates('Window|=Object')
+  @Returns('Window|=Object')
+  final dynamic _get_parent;
+
+  /**
+   * Timing and navigation data for this window.
+   *
+   * ## Other resources
+   *
+   * * [Measuring page load speed with navigation
+   *   timeing](http://www.html5rocks.com/en/tutorials/webperformance/basics/)
+   *   from HTML5Rocks.
+   * * [Navigation timing
+   *   specification](http://www.w3.org/TR/navigation-timing/) from W3C.
+   */
+  @SupportedBrowser(SupportedBrowser.CHROME)
+  @SupportedBrowser(SupportedBrowser.FIREFOX)
+  @SupportedBrowser(SupportedBrowser.IE)
+  final Performance performance;
+
+  /**
+   * Information about the screen displaying this window.
+   *
+   * ## Other resources
+   *
+   * * [The Screen interface specification](http://www.w3.org/TR/cssom-view/#screen)
+   *   from W3C.
+   */
+  final Screen screen;
+
+  /**
+   * The distance from the left side of the screen to the left side of this
+   * window.
+   *
+   * ## Other resources
+   *
+   * * [The Screen interface specification](http://www.w3.org/TR/cssom-view/#screen)
+   *   from W3C.
+   */
+  final int screenLeft;
+
+  /**
+   * The distance from the top of the screen to the top of this window.
+   *
+   * ## Other resources
+   *
+   * * [The Screen interface specification](http://www.w3.org/TR/cssom-view/#screen)
+   *   from W3C.
+   */
+  final int screenTop;
+
+  /**
+   * The distance from the left side of the screen to the mouse pointer.
+   *
+   * ## Other resources
+   *
+   * * [The Screen interface specification](http://www.w3.org/TR/cssom-view/#screen)
+   *   from W3C.
+   */
+  final int screenX;
+
+  /**
+   * The distance from the top of the screen to the mouse pointer.
+   *
+   * ## Other resources
+   *
+   * * [The Screen interface specification](http://www.w3.org/TR/cssom-view/#screen)
+   *   from W3C.
+   */
+  final int screenY;
+
+  /**
+   * This window's scroll bars.
+   *
+   * ## Other resources
+   *
+   * * [Browser interface
+   *   elements](https://html.spec.whatwg.org/multipage/browsers.html#browser-interface-elements)
+   *   from WHATWG.
+   */
+  final BarProp scrollbars;
+
+  /**
+   * The current window.
+   *
+   * ## Other resources
+   *
+   * * [Window.self](https://developer.mozilla.org/en-US/docs/Web/API/Window.self)
+   *   from MDN.
+   */
+  WindowBase get self => _convertNativeToDart_Window(this._get_self);
+  @JSName('self')
+  /**
+   * The current window.
+   *
+   * ## Other resources
+   *
+   * * [Window.self](https://developer.mozilla.org/en-US/docs/Web/API/Window.self)
+   *   from MDN.
+   */
+  @Creates('Window|=Object')
+  @Returns('Window|=Object')
+  final dynamic _get_self;
+
+  /**
+   * Storage for this window that is cleared when this session ends.
+   *
+   * ## Other resources
+   *
+   * * [DOM storage
+   *   guide](https://developer.mozilla.org/en-US/docs/Web/Guide/API/DOM/Storage)
+   *   from MDN.
+   * * [The past, present & future of local storage for web
+   *   applications](http://diveintohtml5.info/storage.html) from Dive Into HTML5.
+   * * [Local storage
+   *   specification](http://www.w3.org/TR/webstorage/#dom-sessionstorage) from W3C.
+   */
+  final Storage sessionStorage;
+
+  /**
+   * Access to speech synthesis in the browser.
+   *
+   * ## Other resources
+   *
+   * * [Web speech
+   *   specification](https://dvcs.w3.org/hg/speech-api/raw-file/tip/speechapi.html#tts-section)
+   *   from W3C.
+   */
+  final SpeechSynthesis speechSynthesis;
+
+  /// *Deprecated*.
+  String status;
+
+  /**
+   * This window's status bar.
+   *
+   * ## Other resources
+   *
+   * * [Browser interface
+   *   elements](https://html.spec.whatwg.org/multipage/browsers.html#browser-interface-elements)
+   *   from WHATWG.
+   */
+  final BarProp statusbar;
+
+  /**
+   * Access to CSS media queries.
+   *
+   * ## Other resources
+   *
+   * * [StyleMedia class
+   *   reference](https://developer.apple.com/library/safari/documentation/SafariDOMAdditions/Reference/StyleMedia/)
+   *   from Safari Developer Library.
+   */
+  final StyleMedia styleMedia;
+
+  /**
+   * This window's tool bar.
+   *
+   * ## Other resources
+   *
+   * * [Browser interface
+   *   elements](https://html.spec.whatwg.org/multipage/browsers.html#browser-interface-elements)
+   *   from WHATWG.
+   */
+  final BarProp toolbar;
+
+  WindowBase get top => _convertNativeToDart_Window(this._get_top);
+  @JSName('top')
+  @Creates('Window|=Object')
+  @Returns('Window|=Object')
+  final dynamic _get_top;
+
+  final VisualViewport visualViewport;
+
+  /**
+   * The current window.
+   *
+   * ## Other resources
+   *
+   * * [Window.window](https://developer.mozilla.org/en-US/docs/Web/API/Window.window)
+   *   from MDN.
+   */
+  WindowBase get window => _convertNativeToDart_Window(this._get_window);
+  @JSName('window')
+  /**
+   * The current window.
+   *
+   * ## Other resources
+   *
+   * * [Window.window](https://developer.mozilla.org/en-US/docs/Web/API/Window.window)
+   *   from MDN.
+   */
+  @Creates('Window|=Object')
+  @Returns('Window|=Object')
+  final dynamic _get_window;
+
+  @Creates('Window|=Object')
+  @Returns('Window|=Object')
+  WindowBase __getter__(index_OR_name) {
+    if ((index_OR_name is int)) {
+      return _convertNativeToDart_Window(__getter___1(index_OR_name));
+    }
+    if ((index_OR_name is String)) {
+      return _convertNativeToDart_Window(__getter___2(index_OR_name));
+    }
+    throw new ArgumentError("Incorrect number or type of arguments");
+  }
+
+  @JSName('__getter__')
+  @Creates('Window|=Object')
+  @Returns('Window|=Object')
+  __getter___1(int index) native;
+  @JSName('__getter__')
+  @Creates('Window|=Object')
+  @Returns('Window|=Object')
+  __getter___2(String name) native;
+
+  /**
+   * Displays a modal alert to the user.
+   *
+   * ## Other resources
+   *
+   * * [User prompts](https://html.spec.whatwg.org/multipage/webappapis.html#user-prompts)
+   *   from WHATWG.
+   */
+  void alert([String message]) native;
+
+  void cancelIdleCallback(int handle) native;
+
+  void close() native;
+
+  /**
+   * Displays a modal OK/Cancel prompt to the user.
+   *
+   * ## Other resources
+   *
+   * * [User prompts](https://html.spec.whatwg.org/multipage/webappapis.html#user-prompts)
+   *   from WHATWG.
+   */
+  bool confirm([String message]) native;
+
+  Future fetch(/*RequestInfo*/ input, [Map init]) {
+    var init_dict = null;
+    if (init != null) {
+      init_dict = convertDartToNative_Dictionary(init);
+    }
+    return promiseToFuture(JS("", "#.fetch(#, #)", this, input, init_dict));
+  }
+
+  /**
+   * Finds text in this window.
+   *
+   * ## Other resources
+   *
+   * * [Window.find](https://developer.mozilla.org/en-US/docs/Web/API/Window.find)
+   *   from MDN.
+   */
+  bool find(String string, bool caseSensitive, bool backwards, bool wrap,
+      bool wholeWord, bool searchInFrames, bool showDialog) native;
+
+  @JSName('getComputedStyle')
+  CssStyleDeclaration _getComputedStyle(Element elt, [String pseudoElt]) native;
+
+  StylePropertyMapReadonly getComputedStyleMap(
+      Element element, String pseudoElement) native;
+
+  @JSName('getMatchedCSSRules')
+  /**
+   * Returns all CSS rules that apply to the element's pseudo-element.
+   */
+  @Returns('_CssRuleList|Null')
+  @Creates('_CssRuleList')
+  List<CssRule> getMatchedCssRules(Element element, String pseudoElement)
+      native;
+
+  /**
+   * Returns the currently selected text.
+   *
+   * ## Other resources
+   *
+   * * [Window.getSelection](https://developer.mozilla.org/en-US/docs/Web/API/Window.getSelection)
+   *   from MDN.
+   */
+  Selection getSelection() native;
+
+  /**
+   * Returns a list of media queries for the given query string.
+   *
+   * ## Other resources
+   *
+   * * [Testing media
+   *   queries](https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Testing_media_queries)
+   *   from MDN.
+   * * [The MediaQueryList
+   *   specification](http://www.w3.org/TR/cssom-view/#the-mediaquerylist-interface) from W3C.
+   */
+  MediaQueryList matchMedia(String query) native;
+
+  /**
+   * Moves this window.
+   *
+   * x and y can be negative.
+   *
+   * ## Other resources
+   *
+   * * [Window.moveBy](https://developer.mozilla.org/en-US/docs/Web/API/Window.moveBy)
+   *   from MDN.
+   * * [Window.moveBy](http://dev.w3.org/csswg/cssom-view/#dom-window-moveby) from W3C.
+   */
+  void moveBy(int x, int y) native;
+
+  @JSName('moveTo')
+  void _moveTo(int x, int y) native;
+
+  @JSName('openDatabase')
+
+  /// *Deprecated.*
+  @SupportedBrowser(SupportedBrowser.CHROME)
+  @SupportedBrowser(SupportedBrowser.SAFARI)
+  @Creates('SqlDatabase')
+  SqlDatabase _openDatabase(
+      String name, String version, String displayName, int estimatedSize,
+      [DatabaseCallback creationCallback]) native;
+
+  void postMessage(/*any*/ message, String targetOrigin,
+      [List<Object> transfer]) {
+    if (transfer != null) {
+      var message_1 = convertDartToNative_SerializedScriptValue(message);
+      _postMessage_1(message_1, targetOrigin, transfer);
+      return;
+    }
+    var message_1 = convertDartToNative_SerializedScriptValue(message);
+    _postMessage_2(message_1, targetOrigin);
+    return;
+  }
+
+  @JSName('postMessage')
+  void _postMessage_1(message, targetOrigin, List<Object> transfer) native;
+  @JSName('postMessage')
+  void _postMessage_2(message, targetOrigin) native;
+
+  /**
+   * Opens the print dialog for this window.
+   *
+   * ## Other resources
+   *
+   * * [Window.print](https://developer.mozilla.org/en-US/docs/Web/API/Window.print)
+   *   from MDN.
+   */
+  void print() native;
+
+  int requestIdleCallback(IdleRequestCallback callback, [Map options]) {
+    if (options != null) {
+      var callback_1 = convertDartClosureToJS(callback, 1);
+      var options_2 = convertDartToNative_Dictionary(options);
+      return _requestIdleCallback_1(callback_1, options_2);
+    }
+    var callback_1 = convertDartClosureToJS(callback, 1);
+    return _requestIdleCallback_2(callback_1);
+  }
+
+  @JSName('requestIdleCallback')
+  int _requestIdleCallback_1(callback, options) native;
+  @JSName('requestIdleCallback')
+  int _requestIdleCallback_2(callback) native;
+
+  /**
+   * Resizes this window by an offset.
+   *
+   * ## Other resources
+   *
+   * * [Window.resizeBy](https://developer.mozilla.org/en-US/docs/Web/API/Window/resizeBy)
+   *   from MDN.
+   */
+  void resizeBy(int x, int y) native;
+
+  /**
+   * Resizes this window to a specific width and height.
+   *
+   * ## Other resources
+   *
+   * * [Window.resizeTo](https://developer.mozilla.org/en-US/docs/Web/API/Window/resizeTo)
+   *   from MDN.
+   */
+  void resizeTo(int x, int y) native;
+
+  /**
+   * Scrolls the page horizontally and vertically to a specific point.
+   *
+   * This method is identical to [scrollTo].
+   *
+   * ## Other resources
+   *
+   * * [Window.scroll](https://developer.mozilla.org/en-US/docs/Web/API/Window/scroll)
+   *   from MDN.
+   */
+  void scroll([options_OR_x, y, Map scrollOptions]) {
+    if (options_OR_x == null && y == null && scrollOptions == null) {
+      _scroll_1();
+      return;
+    }
+    if ((options_OR_x is Map) && y == null && scrollOptions == null) {
+      var options_1 = convertDartToNative_Dictionary(options_OR_x);
+      _scroll_2(options_1);
+      return;
+    }
+    if ((y is num) && (options_OR_x is num) && scrollOptions == null) {
+      _scroll_3(options_OR_x, y);
+      return;
+    }
+    if ((y is int) && (options_OR_x is int) && scrollOptions == null) {
+      _scroll_4(options_OR_x, y);
+      return;
+    }
+    if (scrollOptions != null && (y is int) && (options_OR_x is int)) {
+      var scrollOptions_1 = convertDartToNative_Dictionary(scrollOptions);
+      _scroll_5(options_OR_x, y, scrollOptions_1);
+      return;
+    }
+    throw new ArgumentError("Incorrect number or type of arguments");
+  }
+
+  @JSName('scroll')
+  /**
+   * Scrolls the page horizontally and vertically to a specific point.
+   *
+   * This method is identical to [scrollTo].
+   *
+   * ## Other resources
+   *
+   * * [Window.scroll](https://developer.mozilla.org/en-US/docs/Web/API/Window/scroll)
+   *   from MDN.
+   */
+  void _scroll_1() native;
+  @JSName('scroll')
+  /**
+   * Scrolls the page horizontally and vertically to a specific point.
+   *
+   * This method is identical to [scrollTo].
+   *
+   * ## Other resources
+   *
+   * * [Window.scroll](https://developer.mozilla.org/en-US/docs/Web/API/Window/scroll)
+   *   from MDN.
+   */
+  void _scroll_2(options) native;
+  @JSName('scroll')
+  /**
+   * Scrolls the page horizontally and vertically to a specific point.
+   *
+   * This method is identical to [scrollTo].
+   *
+   * ## Other resources
+   *
+   * * [Window.scroll](https://developer.mozilla.org/en-US/docs/Web/API/Window/scroll)
+   *   from MDN.
+   */
+  void _scroll_3(num x, num y) native;
+  @JSName('scroll')
+  /**
+   * Scrolls the page horizontally and vertically to a specific point.
+   *
+   * This method is identical to [scrollTo].
+   *
+   * ## Other resources
+   *
+   * * [Window.scroll](https://developer.mozilla.org/en-US/docs/Web/API/Window/scroll)
+   *   from MDN.
+   */
+  void _scroll_4(int x, int y) native;
+  @JSName('scroll')
+  /**
+   * Scrolls the page horizontally and vertically to a specific point.
+   *
+   * This method is identical to [scrollTo].
+   *
+   * ## Other resources
+   *
+   * * [Window.scroll](https://developer.mozilla.org/en-US/docs/Web/API/Window/scroll)
+   *   from MDN.
+   */
+  void _scroll_5(int x, int y, scrollOptions) native;
+
+  /**
+   * Scrolls the page horizontally and vertically by an offset.
+   *
+   * ## Other resources
+   *
+   * * [Window.scrollBy](https://developer.mozilla.org/en-US/docs/Web/API/Window/scrollBy)
+   *   from MDN.
+   */
+  void scrollBy([options_OR_x, y, Map scrollOptions]) {
+    if (options_OR_x == null && y == null && scrollOptions == null) {
+      _scrollBy_1();
+      return;
+    }
+    if ((options_OR_x is Map) && y == null && scrollOptions == null) {
+      var options_1 = convertDartToNative_Dictionary(options_OR_x);
+      _scrollBy_2(options_1);
+      return;
+    }
+    if ((y is num) && (options_OR_x is num) && scrollOptions == null) {
+      _scrollBy_3(options_OR_x, y);
+      return;
+    }
+    if ((y is int) && (options_OR_x is int) && scrollOptions == null) {
+      _scrollBy_4(options_OR_x, y);
+      return;
+    }
+    if (scrollOptions != null && (y is int) && (options_OR_x is int)) {
+      var scrollOptions_1 = convertDartToNative_Dictionary(scrollOptions);
+      _scrollBy_5(options_OR_x, y, scrollOptions_1);
+      return;
+    }
+    throw new ArgumentError("Incorrect number or type of arguments");
+  }
+
+  @JSName('scrollBy')
+  /**
+   * Scrolls the page horizontally and vertically by an offset.
+   *
+   * ## Other resources
+   *
+   * * [Window.scrollBy](https://developer.mozilla.org/en-US/docs/Web/API/Window/scrollBy)
+   *   from MDN.
+   */
+  void _scrollBy_1() native;
+  @JSName('scrollBy')
+  /**
+   * Scrolls the page horizontally and vertically by an offset.
+   *
+   * ## Other resources
+   *
+   * * [Window.scrollBy](https://developer.mozilla.org/en-US/docs/Web/API/Window/scrollBy)
+   *   from MDN.
+   */
+  void _scrollBy_2(options) native;
+  @JSName('scrollBy')
+  /**
+   * Scrolls the page horizontally and vertically by an offset.
+   *
+   * ## Other resources
+   *
+   * * [Window.scrollBy](https://developer.mozilla.org/en-US/docs/Web/API/Window/scrollBy)
+   *   from MDN.
+   */
+  void _scrollBy_3(num x, num y) native;
+  @JSName('scrollBy')
+  /**
+   * Scrolls the page horizontally and vertically by an offset.
+   *
+   * ## Other resources
+   *
+   * * [Window.scrollBy](https://developer.mozilla.org/en-US/docs/Web/API/Window/scrollBy)
+   *   from MDN.
+   */
+  void _scrollBy_4(int x, int y) native;
+  @JSName('scrollBy')
+  /**
+   * Scrolls the page horizontally and vertically by an offset.
+   *
+   * ## Other resources
+   *
+   * * [Window.scrollBy](https://developer.mozilla.org/en-US/docs/Web/API/Window/scrollBy)
+   *   from MDN.
+   */
+  void _scrollBy_5(int x, int y, scrollOptions) native;
+
+  /**
+   * Scrolls the page horizontally and vertically to a specific point.
+   *
+   * This method is identical to [scroll].
+   *
+   * ## Other resources
+   *
+   * * [Window.scrollTo](https://developer.mozilla.org/en-US/docs/Web/API/Window/scrollTo)
+   *   from MDN.
+   */
+  void scrollTo([options_OR_x, y, Map scrollOptions]) {
+    if (options_OR_x == null && y == null && scrollOptions == null) {
+      _scrollTo_1();
+      return;
+    }
+    if ((options_OR_x is Map) && y == null && scrollOptions == null) {
+      var options_1 = convertDartToNative_Dictionary(options_OR_x);
+      _scrollTo_2(options_1);
+      return;
+    }
+    if ((y is num) && (options_OR_x is num) && scrollOptions == null) {
+      _scrollTo_3(options_OR_x, y);
+      return;
+    }
+    if ((y is int) && (options_OR_x is int) && scrollOptions == null) {
+      _scrollTo_4(options_OR_x, y);
+      return;
+    }
+    if (scrollOptions != null && (y is int) && (options_OR_x is int)) {
+      var scrollOptions_1 = convertDartToNative_Dictionary(scrollOptions);
+      _scrollTo_5(options_OR_x, y, scrollOptions_1);
+      return;
+    }
+    throw new ArgumentError("Incorrect number or type of arguments");
+  }
+
+  @JSName('scrollTo')
+  /**
+   * Scrolls the page horizontally and vertically to a specific point.
+   *
+   * This method is identical to [scroll].
+   *
+   * ## Other resources
+   *
+   * * [Window.scrollTo](https://developer.mozilla.org/en-US/docs/Web/API/Window/scrollTo)
+   *   from MDN.
+   */
+  void _scrollTo_1() native;
+  @JSName('scrollTo')
+  /**
+   * Scrolls the page horizontally and vertically to a specific point.
+   *
+   * This method is identical to [scroll].
+   *
+   * ## Other resources
+   *
+   * * [Window.scrollTo](https://developer.mozilla.org/en-US/docs/Web/API/Window/scrollTo)
+   *   from MDN.
+   */
+  void _scrollTo_2(options) native;
+  @JSName('scrollTo')
+  /**
+   * Scrolls the page horizontally and vertically to a specific point.
+   *
+   * This method is identical to [scroll].
+   *
+   * ## Other resources
+   *
+   * * [Window.scrollTo](https://developer.mozilla.org/en-US/docs/Web/API/Window/scrollTo)
+   *   from MDN.
+   */
+  void _scrollTo_3(num x, num y) native;
+  @JSName('scrollTo')
+  /**
+   * Scrolls the page horizontally and vertically to a specific point.
+   *
+   * This method is identical to [scroll].
+   *
+   * ## Other resources
+   *
+   * * [Window.scrollTo](https://developer.mozilla.org/en-US/docs/Web/API/Window/scrollTo)
+   *   from MDN.
+   */
+  void _scrollTo_4(int x, int y) native;
+  @JSName('scrollTo')
+  /**
+   * Scrolls the page horizontally and vertically to a specific point.
+   *
+   * This method is identical to [scroll].
+   *
+   * ## Other resources
+   *
+   * * [Window.scrollTo](https://developer.mozilla.org/en-US/docs/Web/API/Window/scrollTo)
+   *   from MDN.
+   */
+  void _scrollTo_5(int x, int y, scrollOptions) native;
+
+  /**
+   * Stops the window from loading.
+   *
+   * ## Other resources
+   *
+   * * [The Window
+   *   object](http://www.w3.org/html/wg/drafts/html/master/browsers.html#the-window-object)
+   *   from W3C.
+   */
+  void stop() native;
+
+  @JSName('webkitRequestFileSystem')
+  @SupportedBrowser(SupportedBrowser.CHROME)
+  void __requestFileSystem(
+      int type, int size, _FileSystemCallback successCallback,
+      [_ErrorCallback errorCallback]) native;
+
+  @JSName('webkitRequestFileSystem')
+  @SupportedBrowser(SupportedBrowser.CHROME)
+  Future<FileSystem> _requestFileSystem(int type, int size) {
+    var completer = new Completer<FileSystem>();
+    __requestFileSystem(type, size, (value) {
+      applyExtension('DOMFileSystem', value);
+      applyExtension('DirectoryEntry', value.root);
+      completer.complete(value);
+    }, (error) {
+      completer.completeError(error);
+    });
+    return completer.future;
+  }
+
+  @JSName('webkitResolveLocalFileSystemURL')
+  /**
+   * Asynchronously retrieves a local filesystem entry.
+   *
+   * ## Other resources
+   *
+   * * [Obtaining access to file system entry
+   *   points](http://www.w3.org/TR/file-system-api/#obtaining-access-to-file-system-entry-points)
+   * from W3C.
+   */
+  @SupportedBrowser(SupportedBrowser.CHROME)
+  void _resolveLocalFileSystemUrl(String url, _EntryCallback successCallback,
+      [_ErrorCallback errorCallback]) native;
+
+  @JSName('webkitResolveLocalFileSystemURL')
+  /**
+   * Asynchronously retrieves a local filesystem entry.
+   *
+   * ## Other resources
+   *
+   * * [Obtaining access to file system entry
+   *   points](http://www.w3.org/TR/file-system-api/#obtaining-access-to-file-system-entry-points)
+   * from W3C.
+   */
+  @SupportedBrowser(SupportedBrowser.CHROME)
+  Future<Entry> resolveLocalFileSystemUrl(String url) {
+    var completer = new Completer<Entry>();
+    _resolveLocalFileSystemUrl(url, (value) {
+      completer.complete(value);
+    }, (error) {
+      completer.completeError(error);
+    });
+    return completer.future;
+  }
+
+  // From WindowBase64
+
+  String atob(String atob) native;
+
+  String btoa(String btoa) native;
+
+  // From WindowTimers
+
+  @JSName('setInterval')
+  int _setInterval_String(String handler, [int timeout, Object arguments])
+      native;
+
+  @JSName('setTimeout')
+  int _setTimeout_String(String handler, [int timeout, Object arguments])
+      native;
+
+  @JSName('clearInterval')
+  void _clearInterval([int handle]) native;
+
+  @JSName('clearTimeout')
+  void _clearTimeout([int handle]) native;
+
+  @JSName('setInterval')
+  int _setInterval(Object handler, [int timeout]) native;
+
+  @JSName('setTimeout')
+  int _setTimeout(Object handler, [int timeout]) native;
+
+  /// Stream of `contentloaded` events handled by this [Window].
+  Stream<Event> get onContentLoaded => contentLoadedEvent.forTarget(this);
+
+  /// Stream of `abort` events handled by this [Window].
+  Stream<Event> get onAbort => Element.abortEvent.forTarget(this);
+
+  /// Stream of `blur` events handled by this [Window].
+  Stream<Event> get onBlur => Element.blurEvent.forTarget(this);
+
+  Stream<Event> get onCanPlay => Element.canPlayEvent.forTarget(this);
+
+  Stream<Event> get onCanPlayThrough =>
+      Element.canPlayThroughEvent.forTarget(this);
+
+  /// Stream of `change` events handled by this [Window].
+  Stream<Event> get onChange => Element.changeEvent.forTarget(this);
+
+  /// Stream of `click` events handled by this [Window].
+  Stream<MouseEvent> get onClick => Element.clickEvent.forTarget(this);
+
+  /// Stream of `contextmenu` events handled by this [Window].
+  Stream<MouseEvent> get onContextMenu =>
+      Element.contextMenuEvent.forTarget(this);
+
+  /// Stream of `doubleclick` events handled by this [Window].
+  @DomName('Window.ondblclick')
+  Stream<Event> get onDoubleClick => Element.doubleClickEvent.forTarget(this);
+
+  /// Stream of `devicemotion` events handled by this [Window].
+  Stream<DeviceMotionEvent> get onDeviceMotion =>
+      deviceMotionEvent.forTarget(this);
+
+  /// Stream of `deviceorientation` events handled by this [Window].
+  Stream<DeviceOrientationEvent> get onDeviceOrientation =>
+      deviceOrientationEvent.forTarget(this);
+
+  /// Stream of `drag` events handled by this [Window].
+  Stream<MouseEvent> get onDrag => Element.dragEvent.forTarget(this);
+
+  /// Stream of `dragend` events handled by this [Window].
+  Stream<MouseEvent> get onDragEnd => Element.dragEndEvent.forTarget(this);
+
+  /// Stream of `dragenter` events handled by this [Window].
+  Stream<MouseEvent> get onDragEnter => Element.dragEnterEvent.forTarget(this);
+
+  /// Stream of `dragleave` events handled by this [Window].
+  Stream<MouseEvent> get onDragLeave => Element.dragLeaveEvent.forTarget(this);
+
+  /// Stream of `dragover` events handled by this [Window].
+  Stream<MouseEvent> get onDragOver => Element.dragOverEvent.forTarget(this);
+
+  /// Stream of `dragstart` events handled by this [Window].
+  Stream<MouseEvent> get onDragStart => Element.dragStartEvent.forTarget(this);
+
+  /// Stream of `drop` events handled by this [Window].
+  Stream<MouseEvent> get onDrop => Element.dropEvent.forTarget(this);
+
+  Stream<Event> get onDurationChange =>
+      Element.durationChangeEvent.forTarget(this);
+
+  Stream<Event> get onEmptied => Element.emptiedEvent.forTarget(this);
+
+  Stream<Event> get onEnded => Element.endedEvent.forTarget(this);
+
+  /// Stream of `error` events handled by this [Window].
+  Stream<Event> get onError => Element.errorEvent.forTarget(this);
+
+  /// Stream of `focus` events handled by this [Window].
+  Stream<Event> get onFocus => Element.focusEvent.forTarget(this);
+
+  /// Stream of `hashchange` events handled by this [Window].
+  Stream<Event> get onHashChange => hashChangeEvent.forTarget(this);
+
+  /// Stream of `input` events handled by this [Window].
+  Stream<Event> get onInput => Element.inputEvent.forTarget(this);
+
+  /// Stream of `invalid` events handled by this [Window].
+  Stream<Event> get onInvalid => Element.invalidEvent.forTarget(this);
+
+  /// Stream of `keydown` events handled by this [Window].
+  Stream<KeyboardEvent> get onKeyDown => Element.keyDownEvent.forTarget(this);
+
+  /// Stream of `keypress` events handled by this [Window].
+  Stream<KeyboardEvent> get onKeyPress => Element.keyPressEvent.forTarget(this);
+
+  /// Stream of `keyup` events handled by this [Window].
+  Stream<KeyboardEvent> get onKeyUp => Element.keyUpEvent.forTarget(this);
+
+  /// Stream of `load` events handled by this [Window].
+  Stream<Event> get onLoad => Element.loadEvent.forTarget(this);
+
+  Stream<Event> get onLoadedData => Element.loadedDataEvent.forTarget(this);
+
+  Stream<Event> get onLoadedMetadata =>
+      Element.loadedMetadataEvent.forTarget(this);
+
+  Stream<Event> get onLoadStart => loadStartEvent.forTarget(this);
+
+  /// Stream of `message` events handled by this [Window].
+  Stream<MessageEvent> get onMessage => messageEvent.forTarget(this);
+
+  /// Stream of `mousedown` events handled by this [Window].
+  Stream<MouseEvent> get onMouseDown => Element.mouseDownEvent.forTarget(this);
+
+  /// Stream of `mouseenter` events handled by this [Window].
+  Stream<MouseEvent> get onMouseEnter =>
+      Element.mouseEnterEvent.forTarget(this);
+
+  /// Stream of `mouseleave` events handled by this [Window].
+  Stream<MouseEvent> get onMouseLeave =>
+      Element.mouseLeaveEvent.forTarget(this);
+
+  /// Stream of `mousemove` events handled by this [Window].
+  Stream<MouseEvent> get onMouseMove => Element.mouseMoveEvent.forTarget(this);
+
+  /// Stream of `mouseout` events handled by this [Window].
+  Stream<MouseEvent> get onMouseOut => Element.mouseOutEvent.forTarget(this);
+
+  /// Stream of `mouseover` events handled by this [Window].
+  Stream<MouseEvent> get onMouseOver => Element.mouseOverEvent.forTarget(this);
+
+  /// Stream of `mouseup` events handled by this [Window].
+  Stream<MouseEvent> get onMouseUp => Element.mouseUpEvent.forTarget(this);
+
+  /// Stream of `mousewheel` events handled by this [Window].
+  Stream<WheelEvent> get onMouseWheel =>
+      Element.mouseWheelEvent.forTarget(this);
+
+  /// Stream of `offline` events handled by this [Window].
+  Stream<Event> get onOffline => offlineEvent.forTarget(this);
+
+  /// Stream of `online` events handled by this [Window].
+  Stream<Event> get onOnline => onlineEvent.forTarget(this);
+
+  /// Stream of `pagehide` events handled by this [Window].
+  Stream<Event> get onPageHide => pageHideEvent.forTarget(this);
+
+  /// Stream of `pageshow` events handled by this [Window].
+  Stream<Event> get onPageShow => pageShowEvent.forTarget(this);
+
+  Stream<Event> get onPause => Element.pauseEvent.forTarget(this);
+
+  Stream<Event> get onPlay => Element.playEvent.forTarget(this);
+
+  Stream<Event> get onPlaying => Element.playingEvent.forTarget(this);
+
+  /// Stream of `popstate` events handled by this [Window].
+  Stream<PopStateEvent> get onPopState => popStateEvent.forTarget(this);
+
+  Stream<Event> get onProgress => progressEvent.forTarget(this);
+
+  Stream<Event> get onRateChange => Element.rateChangeEvent.forTarget(this);
+
+  /// Stream of `reset` events handled by this [Window].
+  Stream<Event> get onReset => Element.resetEvent.forTarget(this);
+
+  /// Stream of `resize` events handled by this [Window].
+  Stream<Event> get onResize => Element.resizeEvent.forTarget(this);
+
+  /// Stream of `scroll` events handled by this [Window].
+  Stream<Event> get onScroll => Element.scrollEvent.forTarget(this);
+
+  /// Stream of `search` events handled by this [Window].
+  Stream<Event> get onSearch => Element.searchEvent.forTarget(this);
+
+  Stream<Event> get onSeeked => Element.seekedEvent.forTarget(this);
+
+  Stream<Event> get onSeeking => Element.seekingEvent.forTarget(this);
+
+  /// Stream of `select` events handled by this [Window].
+  Stream<Event> get onSelect => Element.selectEvent.forTarget(this);
+
+  Stream<Event> get onStalled => Element.stalledEvent.forTarget(this);
+
+  /// Stream of `storage` events handled by this [Window].
+  Stream<StorageEvent> get onStorage => storageEvent.forTarget(this);
+
+  /// Stream of `submit` events handled by this [Window].
+  Stream<Event> get onSubmit => Element.submitEvent.forTarget(this);
+
+  Stream<Event> get onSuspend => Element.suspendEvent.forTarget(this);
+
+  Stream<Event> get onTimeUpdate => Element.timeUpdateEvent.forTarget(this);
+
+  /// Stream of `touchcancel` events handled by this [Window].
+  Stream<TouchEvent> get onTouchCancel =>
+      Element.touchCancelEvent.forTarget(this);
+
+  /// Stream of `touchend` events handled by this [Window].
+  Stream<TouchEvent> get onTouchEnd => Element.touchEndEvent.forTarget(this);
+
+  /// Stream of `touchmove` events handled by this [Window].
+  Stream<TouchEvent> get onTouchMove => Element.touchMoveEvent.forTarget(this);
+
+  /// Stream of `touchstart` events handled by this [Window].
+  Stream<TouchEvent> get onTouchStart =>
+      Element.touchStartEvent.forTarget(this);
+
+  /// Stream of `transitionend` events handled by this [Window].
+  Stream<TransitionEvent> get onTransitionEnd =>
+      Element.transitionEndEvent.forTarget(this);
+
+  /// Stream of `unload` events handled by this [Window].
+  Stream<Event> get onUnload => unloadEvent.forTarget(this);
+
+  Stream<Event> get onVolumeChange => Element.volumeChangeEvent.forTarget(this);
+
+  Stream<Event> get onWaiting => Element.waitingEvent.forTarget(this);
+
+  /// Stream of `animationend` events handled by this [Window].
+  Stream<AnimationEvent> get onAnimationEnd =>
+      animationEndEvent.forTarget(this);
+
+  /// Stream of `animationiteration` events handled by this [Window].
+  Stream<AnimationEvent> get onAnimationIteration =>
+      animationIterationEvent.forTarget(this);
+
+  /// Stream of `animationstart` events handled by this [Window].
+  Stream<AnimationEvent> get onAnimationStart =>
+      animationStartEvent.forTarget(this);
+
+  /**
+   * Static factory designed to expose `beforeunload` events to event
+   * handlers that are not necessarily instances of [Window].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<BeforeUnloadEvent> beforeUnloadEvent =
+      const _BeforeUnloadEventStreamProvider('beforeunload');
+
+  /// Stream of `beforeunload` events handled by this [Window].
+  Stream<Event> get onBeforeUnload => beforeUnloadEvent.forTarget(this);
+
+  /// Stream of `wheel` events handled by this [Window].
+  Stream<WheelEvent> get onWheel => Element.wheelEvent.forTarget(this);
+
+  /**
+   * Moves this window to a specific position.
+   *
+   * x and y can be negative.
+   *
+   * ## Other resources
+   *
+   * * [Window.moveTo](https://developer.mozilla.org/en-US/docs/Web/API/Window.moveTo)
+   *   from MDN.
+   * * [Window.moveTo](http://dev.w3.org/csswg/cssom-view/#dom-window-moveto)
+   *   from W3C.
+   */
+  void moveTo(Point p) {
+    _moveTo(p.x, p.y);
+  }
+
+  @JSName('openDatabase')
+  @SupportedBrowser(SupportedBrowser.CHROME)
+  @SupportedBrowser(SupportedBrowser.SAFARI)
+  @Creates('SqlDatabase')
+  SqlDatabase openDatabase(
+      String name, String version, String displayName, int estimatedSize,
+      [DatabaseCallback creationCallback]) {
+    var db;
+    if (creationCallback == null)
+      db = _openDatabase(name, version, displayName, estimatedSize);
+    else
+      db = _openDatabase(
+          name, version, displayName, estimatedSize, creationCallback);
+
+    applyExtension('Database', db);
+
+    return db;
+  }
+
+  int get pageXOffset => JS<num>('num', '#.pageXOffset', this).round();
+
+  int get pageYOffset => JS<num>('num', '#.pageYOffset', this).round();
+
+  /**
+   * The distance this window has been scrolled horizontally.
+   *
+   * ## Other resources
+   *
+   * * [The Screen interface
+   *   specification](http://www.w3.org/TR/cssom-view/#screen) from W3C.
+   * * [scrollX](https://developer.mozilla.org/en-US/docs/Web/API/Window.scrollX)
+   *   from MDN.
+   */
+  int get scrollX => JS<bool>('bool', '("scrollX" in #)', this)
+      ? JS<num>('num', '#.scrollX', this).round()
+      : document.documentElement.scrollLeft;
+
+  /**
+   * The distance this window has been scrolled vertically.
+   *
+   * ## Other resources
+   *
+   * * [The Screen interface
+   *   specification](http://www.w3.org/TR/cssom-view/#screen) from W3C.
+   * * [scrollY](https://developer.mozilla.org/en-US/docs/Web/API/Window.scrollY)
+   *   from MDN.
+   */
+  int get scrollY => JS<bool>('bool', '("scrollY" in #)', this)
+      ? JS<num>('num', '#.scrollY', this).round()
+      : document.documentElement.scrollTop;
+}
+
+class _BeforeUnloadEvent extends _WrappedEvent implements BeforeUnloadEvent {
+  String _returnValue;
+
+  _BeforeUnloadEvent(Event base) : super(base);
+
+  String get returnValue => _returnValue;
+
+  set returnValue(String value) {
+    _returnValue = value;
+    // FF and IE use the value as the return value, Chrome will return this from
+    // the event callback function.
+    if (JS<bool>('bool', '("returnValue" in #)', wrapped)) {
+      JS('void', '#.returnValue = #', wrapped, value);
+    }
+  }
+}
+
+class _BeforeUnloadEventStreamProvider
+    implements EventStreamProvider<BeforeUnloadEvent> {
+  final String _eventType;
+
+  const _BeforeUnloadEventStreamProvider(this._eventType);
+
+  Stream<BeforeUnloadEvent> forTarget(EventTarget e, {bool useCapture: false}) {
+    // Specify the generic type for EventStream only in dart2js.
+    var stream = new _EventStream<BeforeUnloadEvent>(e, _eventType, useCapture);
+    var controller = new StreamController<BeforeUnloadEvent>(sync: true);
+
+    stream.listen((event) {
+      var wrapped = new _BeforeUnloadEvent(event);
+      controller.add(wrapped);
+    });
+
+    return controller.stream;
+  }
+
+  String getEventType(EventTarget target) {
+    return _eventType;
+  }
+
+  ElementStream<BeforeUnloadEvent> forElement(Element e,
+      {bool useCapture: false}) {
+    // Specify the generic type for _ElementEventStreamImpl only in dart2js.
+    return new _ElementEventStreamImpl<BeforeUnloadEvent>(
+        e, _eventType, useCapture);
+  }
+
+  ElementStream<BeforeUnloadEvent> _forElementList(ElementList<Element> e,
+      {bool useCapture: false}) {
+    // Specify the generic type for _ElementEventStreamImpl only in dart2js.
+    return new _ElementListEventStreamImpl<BeforeUnloadEvent>(
+        e, _eventType, useCapture);
+  }
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+abstract class WindowBase64 extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory WindowBase64._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  String atob(String atob);
+
+  String btoa(String btoa);
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("WindowClient")
+class WindowClient extends Client {
+  // To suppress missing implicit constructor warnings.
+  factory WindowClient._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final bool focused;
+
+  final String visibilityState;
+
+  Future<WindowClient> focus() =>
+      promiseToFuture<WindowClient>(JS("", "#.focus()", this));
+
+  Future<WindowClient> navigate(String url) =>
+      promiseToFuture<WindowClient>(JS("", "#.navigate(#)", this, url));
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+abstract class WindowEventHandlers extends EventTarget {
+  // To suppress missing implicit constructor warnings.
+  factory WindowEventHandlers._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  static const EventStreamProvider<Event> hashChangeEvent =
+      const EventStreamProvider<Event>('hashchange');
+
+  static const EventStreamProvider<MessageEvent> messageEvent =
+      const EventStreamProvider<MessageEvent>('message');
+
+  static const EventStreamProvider<Event> offlineEvent =
+      const EventStreamProvider<Event>('offline');
+
+  static const EventStreamProvider<Event> onlineEvent =
+      const EventStreamProvider<Event>('online');
+
+  static const EventStreamProvider<PopStateEvent> popStateEvent =
+      const EventStreamProvider<PopStateEvent>('popstate');
+
+  static const EventStreamProvider<StorageEvent> storageEvent =
+      const EventStreamProvider<StorageEvent>('storage');
+
+  static const EventStreamProvider<Event> unloadEvent =
+      const EventStreamProvider<Event>('unload');
+
+  Stream<Event> get onHashChange => hashChangeEvent.forTarget(this);
+
+  Stream<MessageEvent> get onMessage => messageEvent.forTarget(this);
+
+  Stream<Event> get onOffline => offlineEvent.forTarget(this);
+
+  Stream<Event> get onOnline => onlineEvent.forTarget(this);
+
+  Stream<PopStateEvent> get onPopState => popStateEvent.forTarget(this);
+
+  Stream<StorageEvent> get onStorage => storageEvent.forTarget(this);
+
+  Stream<Event> get onUnload => unloadEvent.forTarget(this);
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.FIREFOX)
+@SupportedBrowser(SupportedBrowser.IE, '10')
+@SupportedBrowser(SupportedBrowser.SAFARI)
+@Native("Worker")
+class Worker extends EventTarget implements AbstractWorker {
+  // To suppress missing implicit constructor warnings.
+  factory Worker._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  /**
+   * Static factory designed to expose `error` events to event
+   * handlers that are not necessarily instances of [Worker].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<Event> errorEvent =
+      const EventStreamProvider<Event>('error');
+
+  /**
+   * Static factory designed to expose `message` events to event
+   * handlers that are not necessarily instances of [Worker].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<MessageEvent> messageEvent =
+      const EventStreamProvider<MessageEvent>('message');
+
+  factory Worker(String scriptUrl) {
+    return Worker._create_1(scriptUrl);
+  }
+  static Worker _create_1(scriptUrl) =>
+      JS('Worker', 'new Worker(#)', scriptUrl);
+
+  /// Checks if this type is supported on the current platform.
+  static bool get supported =>
+      JS('bool', '(typeof window.Worker != "undefined")');
+
+  void postMessage(/*any*/ message, [List<Object> transfer]) {
+    if (transfer != null) {
+      var message_1 = convertDartToNative_SerializedScriptValue(message);
+      _postMessage_1(message_1, transfer);
+      return;
+    }
+    var message_1 = convertDartToNative_SerializedScriptValue(message);
+    _postMessage_2(message_1);
+    return;
+  }
+
+  @JSName('postMessage')
+  void _postMessage_1(message, List<Object> transfer) native;
+  @JSName('postMessage')
+  void _postMessage_2(message) native;
+
+  void terminate() native;
+
+  /// Stream of `error` events handled by this [Worker].
+  Stream<Event> get onError => errorEvent.forTarget(this);
+
+  /// Stream of `message` events handled by this [Worker].
+  Stream<MessageEvent> get onMessage => messageEvent.forTarget(this);
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("WorkerGlobalScope")
+class WorkerGlobalScope extends EventTarget
+    implements _WindowTimers, WindowBase64 {
+  // To suppress missing implicit constructor warnings.
+  factory WorkerGlobalScope._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  /**
+   * Static factory designed to expose `error` events to event
+   * handlers that are not necessarily instances of [WorkerGlobalScope].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<Event> errorEvent =
+      const EventStreamProvider<Event>('error');
+
+  final String addressSpace;
+
+  final CacheStorage caches;
+
+  final Crypto crypto;
+
+  final IdbFactory indexedDB;
+
+  final bool isSecureContext;
+
+  final _WorkerLocation location;
+
+  final _WorkerNavigator navigator;
+
+  final String origin;
+
+  final WorkerPerformance performance;
+
+  final WorkerGlobalScope self;
+
+  Future fetch(/*RequestInfo*/ input, [Map init]) {
+    var init_dict = null;
+    if (init != null) {
+      init_dict = convertDartToNative_Dictionary(init);
+    }
+    return promiseToFuture(JS("", "#.fetch(#, #)", this, input, init_dict));
+  }
+
+  void importScripts(String urls) native;
+
+  // From WindowBase64
+
+  String atob(String atob) native;
+
+  String btoa(String btoa) native;
+
+  // From WindowTimers
+
+  @JSName('setInterval')
+  int _setInterval_String(String handler, [int timeout, Object arguments])
+      native;
+
+  @JSName('setTimeout')
+  int _setTimeout_String(String handler, [int timeout, Object arguments])
+      native;
+
+  @JSName('clearInterval')
+  void _clearInterval([int handle]) native;
+
+  @JSName('clearTimeout')
+  void _clearTimeout([int handle]) native;
+
+  @JSName('setInterval')
+  int _setInterval(Object handler, [int timeout]) native;
+
+  @JSName('setTimeout')
+  int _setTimeout(Object handler, [int timeout]) native;
+
+  /// Stream of `error` events handled by this [WorkerGlobalScope].
+  Stream<Event> get onError => errorEvent.forTarget(this);
+
+  static WorkerGlobalScope get instance => _workerSelf;
+}
+
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("WorkerPerformance")
+class WorkerPerformance extends EventTarget {
+  // To suppress missing implicit constructor warnings.
+  factory WorkerPerformance._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final MemoryInfo memory;
+
+  final num timeOrigin;
+
+  void clearMarks(String markName) native;
+
+  void clearMeasures(String measureName) native;
+
+  void clearResourceTimings() native;
+
+  List<PerformanceEntry> getEntries() native;
+
+  List<PerformanceEntry> getEntriesByName(String name, String entryType) native;
+
+  List<PerformanceEntry> getEntriesByType(String entryType) native;
+
+  void mark(String markName) native;
+
+  void measure(String measureName, String startMark, String endMark) native;
+
+  double now() native;
+
+  void setResourceTimingBufferSize(int maxSize) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("WorkletAnimation")
+class WorkletAnimation extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory WorkletAnimation._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory WorkletAnimation(
+      String animatorName,
+      List<KeyframeEffectReadOnly> effects,
+      List<Object> timelines,
+      /*SerializedScriptValue*/ options) {
+    var options_1 = convertDartToNative_SerializedScriptValue(options);
+    return WorkletAnimation._create_1(
+        animatorName, effects, timelines, options_1);
+  }
+  static WorkletAnimation _create_1(
+          animatorName, effects, timelines, options) =>
+      JS('WorkletAnimation', 'new WorkletAnimation(#,#,#,#)', animatorName,
+          effects, timelines, options);
+
+  final String playState;
+
+  void cancel() native;
+
+  void play() native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("WorkletGlobalScope")
+class WorkletGlobalScope extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory WorkletGlobalScope._() {
+    throw new UnsupportedError("Not supported");
+  }
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// http://www.w3.org/TR/DOM-Level-3-XPath/xpath.html#XPathEvaluator
+@deprecated // experimental
+@Native("XPathEvaluator")
+class XPathEvaluator extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory XPathEvaluator._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory XPathEvaluator() {
+    return XPathEvaluator._create_1();
+  }
+  static XPathEvaluator _create_1() =>
+      JS('XPathEvaluator', 'new XPathEvaluator()');
+
+  XPathExpression createExpression(String expression, XPathNSResolver resolver)
+      native;
+
+  XPathNSResolver createNSResolver(Node nodeResolver) native;
+
+  XPathResult evaluate(
+      String expression, Node contextNode, XPathNSResolver resolver,
+      [int type, Object inResult]) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// http://www.w3.org/TR/DOM-Level-3-XPath/xpath.html#XPathExpression
+@deprecated // experimental
+@Native("XPathExpression")
+class XPathExpression extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory XPathExpression._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  XPathResult evaluate(Node contextNode, [int type, Object inResult]) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// http://www.w3.org/TR/DOM-Level-3-XPath/xpath.html#XPathNSResolver
+@deprecated // experimental
+@Native("XPathNSResolver")
+class XPathNSResolver extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory XPathNSResolver._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  @JSName('lookupNamespaceURI')
+  String lookupNamespaceUri(String prefix) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// http://www.w3.org/TR/DOM-Level-3-XPath/xpath.html#XPathResult
+@deprecated // experimental
+@Native("XPathResult")
+class XPathResult extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory XPathResult._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  static const int ANY_TYPE = 0;
+
+  static const int ANY_UNORDERED_NODE_TYPE = 8;
+
+  static const int BOOLEAN_TYPE = 3;
+
+  static const int FIRST_ORDERED_NODE_TYPE = 9;
+
+  static const int NUMBER_TYPE = 1;
+
+  static const int ORDERED_NODE_ITERATOR_TYPE = 5;
+
+  static const int ORDERED_NODE_SNAPSHOT_TYPE = 7;
+
+  static const int STRING_TYPE = 2;
+
+  static const int UNORDERED_NODE_ITERATOR_TYPE = 4;
+
+  static const int UNORDERED_NODE_SNAPSHOT_TYPE = 6;
+
+  final bool booleanValue;
+
+  final bool invalidIteratorState;
+
+  final num numberValue;
+
+  final int resultType;
+
+  final Node singleNodeValue;
+
+  final int snapshotLength;
+
+  final String stringValue;
+
+  Node iterateNext() native;
+
+  Node snapshotItem(int index) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("XMLDocument")
+class XmlDocument extends Document {
+  // To suppress missing implicit constructor warnings.
+  factory XmlDocument._() {
+    throw new UnsupportedError("Not supported");
+  }
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// http://domparsing.spec.whatwg.org/#the-xmlserializer-interface
+@deprecated // stable
+@Native("XMLSerializer")
+class XmlSerializer extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory XmlSerializer._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory XmlSerializer() {
+    return XmlSerializer._create_1();
+  }
+  static XmlSerializer _create_1() =>
+      JS('XmlSerializer', 'new XMLSerializer()');
+
+  String serializeToString(Node root) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.FIREFOX)
+@SupportedBrowser(SupportedBrowser.SAFARI)
+@deprecated // nonstandard
+@Native("XSLTProcessor")
+class XsltProcessor extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory XsltProcessor._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory XsltProcessor() {
+    return XsltProcessor._create_1();
+  }
+  static XsltProcessor _create_1() =>
+      JS('XsltProcessor', 'new XSLTProcessor()');
+
+  /// Checks if this type is supported on the current platform.
+  static bool get supported => JS('bool', '!!(window.XSLTProcessor)');
+
+  void clearParameters() native;
+
+  String getParameter(String namespaceURI, String localName) native;
+
+  void importStylesheet(Node style) native;
+
+  void removeParameter(String namespaceURI, String localName) native;
+
+  void reset() native;
+
+  void setParameter(String namespaceURI, String localName, String value) native;
+
+  Document transformToDocument(Node source) native;
+
+  DocumentFragment transformToFragment(Node source, Document output) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("Attr")
+class _Attr extends Node {
+  // To suppress missing implicit constructor warnings.
+  factory _Attr._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  @JSName('localName')
+  final String _localName;
+
+  final String name;
+
+  @JSName('namespaceURI')
+  final String _namespaceUri;
+
+  String value;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("Bluetooth")
+abstract class _Bluetooth extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory _Bluetooth._() {
+    throw new UnsupportedError("Not supported");
+  }
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("BluetoothCharacteristicProperties")
+abstract class _BluetoothCharacteristicProperties extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory _BluetoothCharacteristicProperties._() {
+    throw new UnsupportedError("Not supported");
+  }
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("BluetoothDevice")
+abstract class _BluetoothDevice extends EventTarget {
+  // To suppress missing implicit constructor warnings.
+  factory _BluetoothDevice._() {
+    throw new UnsupportedError("Not supported");
+  }
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("BluetoothRemoteGATTCharacteristic")
+abstract class _BluetoothRemoteGATTCharacteristic extends EventTarget {
+  // To suppress missing implicit constructor warnings.
+  factory _BluetoothRemoteGATTCharacteristic._() {
+    throw new UnsupportedError("Not supported");
+  }
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("BluetoothRemoteGATTServer")
+abstract class _BluetoothRemoteGATTServer extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory _BluetoothRemoteGATTServer._() {
+    throw new UnsupportedError("Not supported");
+  }
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("BluetoothRemoteGATTService")
+abstract class _BluetoothRemoteGATTService extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory _BluetoothRemoteGATTService._() {
+    throw new UnsupportedError("Not supported");
+  }
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("BluetoothUUID")
+abstract class _BluetoothUUID extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory _BluetoothUUID._() {
+    throw new UnsupportedError("Not supported");
+  }
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("BudgetService")
+class _BudgetService extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory _BudgetService._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  Future<BudgetState> getBudget() =>
+      promiseToFuture<BudgetState>(JS("", "#.getBudget()", this));
+
+  Future<double> getCost(String operation) =>
+      promiseToFuture<double>(JS("", "#.getCost(#)", this, operation));
+
+  Future<bool> reserve(String operation) =>
+      promiseToFuture<bool>(JS("", "#.reserve(#)", this, operation));
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("Cache")
+abstract class _Cache extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory _Cache._() {
+    throw new UnsupportedError("Not supported");
+  }
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+abstract class _CanvasPath extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory _CanvasPath._() {
+    throw new UnsupportedError("Not supported");
+  }
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("Clipboard")
+class _Clipboard extends EventTarget {
+  // To suppress missing implicit constructor warnings.
+  factory _Clipboard._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  Future<DataTransfer> read() =>
+      promiseToFuture<DataTransfer>(JS("", "#.read()", this));
+
+  Future<String> readText() =>
+      promiseToFuture<String>(JS("", "#.readText()", this));
+
+  Future write(DataTransfer data) =>
+      promiseToFuture(JS("", "#.write(#)", this, data));
+
+  Future writeText(String data) =>
+      promiseToFuture(JS("", "#.writeText(#)", this, data));
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("CSSRuleList")
+class _CssRuleList extends Interceptor
+    with ListMixin<CssRule>, ImmutableListMixin<CssRule>
+    implements JavaScriptIndexingBehavior<CssRule>, List<CssRule> {
+  // To suppress missing implicit constructor warnings.
+  factory _CssRuleList._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  int get length => JS("int", "#.length", this);
+
+  CssRule operator [](int index) {
+    if (JS("bool", "# >>> 0 !== # || # >= #", index, index, index, length))
+      throw new RangeError.index(index, this);
+    return JS("CssRule", "#[#]", this, index);
+  }
+
+  void operator []=(int index, CssRule value) {
+    throw new UnsupportedError("Cannot assign element of immutable List.");
+  }
+  // -- start List<CssRule> mixins.
+  // CssRule is the element type.
+
+  set length(int value) {
+    throw new UnsupportedError("Cannot resize immutable List.");
+  }
+
+  CssRule get first {
+    if (this.length > 0) {
+      return JS('CssRule', '#[0]', this);
+    }
+    throw new StateError("No elements");
+  }
+
+  CssRule get last {
+    int len = this.length;
+    if (len > 0) {
+      return JS('CssRule', '#[#]', this, len - 1);
+    }
+    throw new StateError("No elements");
+  }
+
+  CssRule get single {
+    int len = this.length;
+    if (len == 1) {
+      return JS('CssRule', '#[0]', this);
+    }
+    if (len == 0) throw new StateError("No elements");
+    throw new StateError("More than one element");
+  }
+
+  CssRule elementAt(int index) => this[index];
+  // -- end List<CssRule> mixins.
+
+  CssRule item(int index) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@Native("DOMFileSystemSync")
+abstract class _DOMFileSystemSync extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory _DOMFileSystemSync._() {
+    throw new UnsupportedError("Not supported");
+  }
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("DirectoryEntrySync")
+abstract class _DirectoryEntrySync extends _EntrySync {
+  // To suppress missing implicit constructor warnings.
+  factory _DirectoryEntrySync._() {
+    throw new UnsupportedError("Not supported");
+  }
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("DirectoryReaderSync")
+abstract class _DirectoryReaderSync extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory _DirectoryReaderSync._() {
+    throw new UnsupportedError("Not supported");
+  }
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// http://www.w3.org/TR/DOM-Level-3-Core/core.html#ID-412266927
+@deprecated // stable
+@Native("DocumentType")
+abstract class _DocumentType extends Node implements ChildNode {
+  // To suppress missing implicit constructor warnings.
+  factory _DocumentType._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  // From ChildNode
+
+}
+
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("ClientRect,DOMRect")
+class _DomRect extends DomRectReadOnly implements Rectangle {
+  // NOTE! All code below should be common with RectangleBase.
+  String toString() {
+    return 'Rectangle ($left, $top) $width x $height';
+  }
+
+  bool operator ==(other) {
+    if (other is! Rectangle) return false;
+    return left == other.left &&
+        top == other.top &&
+        width == other.width &&
+        height == other.height;
+  }
+
+  int get hashCode => _JenkinsSmiHash.hash4(
+      left.hashCode, top.hashCode, width.hashCode, height.hashCode);
+
+  /**
+   * Computes the intersection of `this` and [other].
+   *
+   * The intersection of two axis-aligned rectangles, if any, is always another
+   * axis-aligned rectangle.
+   *
+   * Returns the intersection of this and `other`, or null if they don't
+   * intersect.
+   */
+  Rectangle intersection(Rectangle other) {
+    var x0 = max(left, other.left);
+    var x1 = min(left + width, other.left + other.width);
+
+    if (x0 <= x1) {
+      var y0 = max(top, other.top);
+      var y1 = min(top + height, other.top + other.height);
+
+      if (y0 <= y1) {
+        return new Rectangle(x0, y0, x1 - x0, y1 - y0);
+      }
+    }
+    return null;
+  }
+
+  /**
+   * Returns true if `this` intersects [other].
+   */
+  bool intersects(Rectangle<num> other) {
+    return (left <= other.left + other.width &&
+        other.left <= left + width &&
+        top <= other.top + other.height &&
+        other.top <= top + height);
+  }
+
+  /**
+   * Returns a new rectangle which completely contains `this` and [other].
+   */
+  Rectangle boundingBox(Rectangle other) {
+    var right = max(this.left + this.width, other.left + other.width);
+    var bottom = max(this.top + this.height, other.top + other.height);
+
+    var left = min(this.left, other.left);
+    var top = min(this.top, other.top);
+
+    return new Rectangle(left, top, right - left, bottom - top);
+  }
+
+  /**
+   * Tests whether `this` entirely contains [another].
+   */
+  bool containsRectangle(Rectangle<num> another) {
+    return left <= another.left &&
+        left + width >= another.left + another.width &&
+        top <= another.top &&
+        top + height >= another.top + another.height;
+  }
+
+  /**
+   * Tests whether [another] is inside or along the edges of `this`.
+   */
+  bool containsPoint(Point<num> another) {
+    return another.x >= left &&
+        another.x <= left + width &&
+        another.y >= top &&
+        another.y <= top + height;
+  }
+
+  Point get topLeft => new Point(this.left, this.top);
+  Point get topRight => new Point(this.left + this.width, this.top);
+  Point get bottomRight =>
+      new Point(this.left + this.width, this.top + this.height);
+  Point get bottomLeft => new Point(this.left, this.top + this.height);
+
+  // To suppress missing implicit constructor warnings.
+  factory _DomRect._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory _DomRect([num x, num y, num width, num height]) {
+    if (height != null) {
+      return _DomRect._create_1(x, y, width, height);
+    }
+    if (width != null) {
+      return _DomRect._create_2(x, y, width);
+    }
+    if (y != null) {
+      return _DomRect._create_3(x, y);
+    }
+    if (x != null) {
+      return _DomRect._create_4(x);
+    }
+    return _DomRect._create_5();
+  }
+  static _DomRect _create_1(x, y, width, height) =>
+      JS('_DomRect', 'new DOMRect(#,#,#,#)', x, y, width, height);
+  static _DomRect _create_2(x, y, width) =>
+      JS('_DomRect', 'new DOMRect(#,#,#)', x, y, width);
+  static _DomRect _create_3(x, y) => JS('_DomRect', 'new DOMRect(#,#)', x, y);
+  static _DomRect _create_4(x) => JS('_DomRect', 'new DOMRect(#)', x);
+  static _DomRect _create_5() => JS('_DomRect', 'new DOMRect()');
+
+  // Shadowing definition.
+  num get height => JS("num", "#.height", this);
+
+  set height(num value) {
+    JS("void", "#.height = #", this, value);
+  }
+
+  // Shadowing definition.
+  num get width => JS("num", "#.width", this);
+
+  set width(num value) {
+    JS("void", "#.width = #", this, value);
+  }
+
+  // Shadowing definition.
+  num get x => JS("num", "#.x", this);
+
+  set x(num value) {
+    JS("void", "#.x = #", this, value);
+  }
+
+  // Shadowing definition.
+  num get y => JS("num", "#.y", this);
+
+  set y(num value) {
+    JS("void", "#.y = #", this, value);
+  }
+}
+
+/**
+ * This is the [Jenkins hash function][1] but using masking to keep
+ * values in SMI range.
+ *
+ * [1]: http://en.wikipedia.org/wiki/Jenkins_hash_function
+ *
+ * Use:
+ * Hash each value with the hash of the previous value, then get the final
+ * hash by calling finish.
+ *
+ *     var hash = 0;
+ *     for (var value in values) {
+ *       hash = JenkinsSmiHash.combine(hash, value.hashCode);
+ *     }
+ *     hash = JenkinsSmiHash.finish(hash);
+ */
+class _JenkinsSmiHash {
+  // TODO(11617): This class should be optimized and standardized elsewhere.
+
+  static int combine(int hash, int value) {
+    hash = 0x1fffffff & (hash + value);
+    hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10));
+    return hash ^ (hash >> 6);
+  }
+
+  static int finish(int hash) {
+    hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3));
+    hash = hash ^ (hash >> 11);
+    return 0x1fffffff & (hash + ((0x00003fff & hash) << 15));
+  }
+
+  static int hash2(a, b) => finish(combine(combine(0, a), b));
+
+  static int hash4(a, b, c, d) =>
+      finish(combine(combine(combine(combine(0, a), b), c), d));
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("EntrySync")
+abstract class _EntrySync extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory _EntrySync._() {
+    throw new UnsupportedError("Not supported");
+  }
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("FileEntrySync")
+abstract class _FileEntrySync extends _EntrySync {
+  // To suppress missing implicit constructor warnings.
+  factory _FileEntrySync._() {
+    throw new UnsupportedError("Not supported");
+  }
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("FileReaderSync")
+abstract class _FileReaderSync extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory _FileReaderSync._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory _FileReaderSync() {
+    return _FileReaderSync._create_1();
+  }
+  static _FileReaderSync _create_1() =>
+      JS('_FileReaderSync', 'new FileReaderSync()');
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("FileWriterSync")
+abstract class _FileWriterSync extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory _FileWriterSync._() {
+    throw new UnsupportedError("Not supported");
+  }
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("GamepadList")
+class _GamepadList extends Interceptor
+    with ListMixin<Gamepad>, ImmutableListMixin<Gamepad>
+    implements List<Gamepad>, JavaScriptIndexingBehavior<Gamepad> {
+  // To suppress missing implicit constructor warnings.
+  factory _GamepadList._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  int get length => JS("int", "#.length", this);
+
+  Gamepad operator [](int index) {
+    if (JS("bool", "# >>> 0 !== # || # >= #", index, index, index, length))
+      throw new RangeError.index(index, this);
+    return JS("Gamepad|Null", "#[#]", this, index);
+  }
+
+  void operator []=(int index, Gamepad value) {
+    throw new UnsupportedError("Cannot assign element of immutable List.");
+  }
+  // -- start List<Gamepad> mixins.
+  // Gamepad is the element type.
+
+  set length(int value) {
+    throw new UnsupportedError("Cannot resize immutable List.");
+  }
+
+  Gamepad get first {
+    if (this.length > 0) {
+      return JS('Gamepad|Null', '#[0]', this);
+    }
+    throw new StateError("No elements");
+  }
+
+  Gamepad get last {
+    int len = this.length;
+    if (len > 0) {
+      return JS('Gamepad|Null', '#[#]', this, len - 1);
+    }
+    throw new StateError("No elements");
+  }
+
+  Gamepad get single {
+    int len = this.length;
+    if (len == 1) {
+      return JS('Gamepad|Null', '#[0]', this);
+    }
+    if (len == 0) throw new StateError("No elements");
+    throw new StateError("More than one element");
+  }
+
+  Gamepad elementAt(int index) => this[index];
+  // -- end List<Gamepad> mixins.
+
+  Gamepad item(int index) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// http://www.whatwg.org/specs/web-apps/current-work/multipage/obsolete.html#dom-document-all
+@deprecated // deprecated
+@Native("HTMLAllCollection")
+abstract class _HTMLAllCollection extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory _HTMLAllCollection._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  @JSName('item')
+  Element _item(int index) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// http://www.whatwg.org/specs/web-apps/current-work/multipage/obsolete.html#dir
+@deprecated // deprecated
+@Native("HTMLDirectoryElement")
+abstract class _HTMLDirectoryElement extends HtmlElement {
+  // To suppress missing implicit constructor warnings.
+  factory _HTMLDirectoryElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  _HTMLDirectoryElement.created() : super.created();
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// http://www.whatwg.org/specs/web-apps/current-work/multipage/obsolete.html#htmlfontelement
+@deprecated // deprecated
+@Native("HTMLFontElement")
+abstract class _HTMLFontElement extends HtmlElement {
+  // To suppress missing implicit constructor warnings.
+  factory _HTMLFontElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  _HTMLFontElement.created() : super.created();
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// http://www.whatwg.org/specs/web-apps/current-work/multipage/obsolete.html#htmlframeelement
+@deprecated // deprecated
+@Native("HTMLFrameElement")
+abstract class _HTMLFrameElement extends HtmlElement {
+  // To suppress missing implicit constructor warnings.
+  factory _HTMLFrameElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  _HTMLFrameElement.created() : super.created();
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// http://www.whatwg.org/specs/web-apps/current-work/multipage/obsolete.html#frameset
+@deprecated // deprecated
+@Native("HTMLFrameSetElement")
+abstract class _HTMLFrameSetElement extends HtmlElement
+    implements WindowEventHandlers {
+  // To suppress missing implicit constructor warnings.
+  factory _HTMLFrameSetElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  _HTMLFrameSetElement.created() : super.created();
+}
+
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// http://www.whatwg.org/specs/web-apps/current-work/multipage/obsolete.html#the-marquee-element
+@deprecated // deprecated
+@Native("HTMLMarqueeElement")
+abstract class _HTMLMarqueeElement extends HtmlElement {
+  // To suppress missing implicit constructor warnings.
+  factory _HTMLMarqueeElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  _HTMLMarqueeElement.created() : super.created();
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("Mojo")
+abstract class _Mojo extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory _Mojo._() {
+    throw new UnsupportedError("Not supported");
+  }
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("MojoHandle")
+abstract class _MojoHandle extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory _MojoHandle._() {
+    throw new UnsupportedError("Not supported");
+  }
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("MojoInterfaceInterceptor")
+abstract class _MojoInterfaceInterceptor extends EventTarget {
+  // To suppress missing implicit constructor warnings.
+  factory _MojoInterfaceInterceptor._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory _MojoInterfaceInterceptor(String interfaceName, [String scope]) {
+    if (scope != null) {
+      return _MojoInterfaceInterceptor._create_1(interfaceName, scope);
+    }
+    return _MojoInterfaceInterceptor._create_2(interfaceName);
+  }
+  static _MojoInterfaceInterceptor _create_1(interfaceName, scope) => JS(
+      '_MojoInterfaceInterceptor',
+      'new MojoInterfaceInterceptor(#,#)',
+      interfaceName,
+      scope);
+  static _MojoInterfaceInterceptor _create_2(interfaceName) => JS(
+      '_MojoInterfaceInterceptor',
+      'new MojoInterfaceInterceptor(#)',
+      interfaceName);
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("MojoInterfaceRequestEvent")
+abstract class _MojoInterfaceRequestEvent extends Event {
+  // To suppress missing implicit constructor warnings.
+  factory _MojoInterfaceRequestEvent._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory _MojoInterfaceRequestEvent(String type, [Map eventInitDict]) {
+    if (eventInitDict != null) {
+      var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+      return _MojoInterfaceRequestEvent._create_1(type, eventInitDict_1);
+    }
+    return _MojoInterfaceRequestEvent._create_2(type);
+  }
+  static _MojoInterfaceRequestEvent _create_1(type, eventInitDict) => JS(
+      '_MojoInterfaceRequestEvent',
+      'new MojoInterfaceRequestEvent(#,#)',
+      type,
+      eventInitDict);
+  static _MojoInterfaceRequestEvent _create_2(type) => JS(
+      '_MojoInterfaceRequestEvent', 'new MojoInterfaceRequestEvent(#)', type);
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("MojoWatcher")
+abstract class _MojoWatcher extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory _MojoWatcher._() {
+    throw new UnsupportedError("Not supported");
+  }
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("NFC")
+abstract class _NFC extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory _NFC._() {
+    throw new UnsupportedError("Not supported");
+  }
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// http://dom.spec.whatwg.org/#namednodemap
+@deprecated // deprecated
+@Native("NamedNodeMap,MozNamedAttrMap")
+class _NamedNodeMap extends Interceptor
+    with ListMixin<Node>, ImmutableListMixin<Node>
+    implements JavaScriptIndexingBehavior<Node>, List<Node> {
+  // To suppress missing implicit constructor warnings.
+  factory _NamedNodeMap._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  int get length => JS("int", "#.length", this);
+
+  Node operator [](int index) {
+    if (JS("bool", "# >>> 0 !== # || # >= #", index, index, index, length))
+      throw new RangeError.index(index, this);
+    return JS("Node", "#[#]", this, index);
+  }
+
+  void operator []=(int index, Node value) {
+    throw new UnsupportedError("Cannot assign element of immutable List.");
+  }
+  // -- start List<Node> mixins.
+  // Node is the element type.
+
+  set length(int value) {
+    throw new UnsupportedError("Cannot resize immutable List.");
+  }
+
+  Node get first {
+    if (this.length > 0) {
+      return JS('Node', '#[0]', this);
+    }
+    throw new StateError("No elements");
+  }
+
+  Node get last {
+    int len = this.length;
+    if (len > 0) {
+      return JS('Node', '#[#]', this, len - 1);
+    }
+    throw new StateError("No elements");
+  }
+
+  Node get single {
+    int len = this.length;
+    if (len == 1) {
+      return JS('Node', '#[0]', this);
+    }
+    if (len == 0) throw new StateError("No elements");
+    throw new StateError("More than one element");
+  }
+
+  Node elementAt(int index) => this[index];
+  // -- end List<Node> mixins.
+
+  _Attr getNamedItem(String name) native;
+
+  _Attr getNamedItemNS(String namespaceURI, String localName) native;
+
+  _Attr item(int index) native;
+
+  _Attr removeNamedItem(String name) native;
+
+  _Attr removeNamedItemNS(String namespaceURI, String localName) native;
+
+  _Attr setNamedItem(_Attr attr) native;
+
+  _Attr setNamedItemNS(_Attr attr) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@deprecated // nonstandard
+@Native("PagePopupController")
+abstract class _PagePopupController extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory _PagePopupController._() {
+    throw new UnsupportedError("Not supported");
+  }
+}
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Omit RadioNodeList for dart2js.  The Dart Form and FieldSet APIs don't
+// currently expose an API the returns RadioNodeList.  The only use of a
+// RadioNodeList is to get the selected value and it will be cleaner to
+// introduce a different API for that purpose.
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("Report")
+class _Report extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory _Report._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final ReportBody body;
+
+  final String type;
+
+  final String url;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("Request")
+class _Request extends Body {
+  // To suppress missing implicit constructor warnings.
+  factory _Request._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory _Request(Object input, [Map requestInitDict]) {
+    if (requestInitDict != null) {
+      var requestInitDict_1 = convertDartToNative_Dictionary(requestInitDict);
+      return _Request._create_1(input, requestInitDict_1);
+    }
+    return _Request._create_2(input);
+  }
+  static _Request _create_1(input, requestInitDict) =>
+      JS('_Request', 'new Request(#,#)', input, requestInitDict);
+  static _Request _create_2(input) => JS('_Request', 'new Request(#)', input);
+
+  final String cache;
+
+  final String credentials;
+
+  final Headers headers;
+
+  final String integrity;
+
+  final String mode;
+
+  final String redirect;
+
+  final String referrer;
+
+  final String referrerPolicy;
+
+  final String url;
+
+  _Request clone() native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// https://chromiumcodereview.appspot.com/14773025/
+@deprecated // experimental
+@Native("ResourceProgressEvent")
+abstract class _ResourceProgressEvent extends ProgressEvent {
+  // To suppress missing implicit constructor warnings.
+  factory _ResourceProgressEvent._() {
+    throw new UnsupportedError("Not supported");
+  }
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("Response")
+abstract class _Response extends Body {
+  // To suppress missing implicit constructor warnings.
+  factory _Response._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory _Response([Object body, Map init]) {
+    if (init != null) {
+      var init_1 = convertDartToNative_Dictionary(init);
+      return _Response._create_1(body, init_1);
+    }
+    if (body != null) {
+      return _Response._create_2(body);
+    }
+    return _Response._create_3();
+  }
+  static _Response _create_1(body, init) =>
+      JS('_Response', 'new Response(#,#)', body, init);
+  static _Response _create_2(body) => JS('_Response', 'new Response(#)', body);
+  static _Response _create_3() => JS('_Response', 'new Response()');
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("SpeechRecognitionResultList")
+class _SpeechRecognitionResultList extends Interceptor
+    with
+        ListMixin<SpeechRecognitionResult>,
+        ImmutableListMixin<SpeechRecognitionResult>
+    implements
+        JavaScriptIndexingBehavior<SpeechRecognitionResult>,
+        List<SpeechRecognitionResult> {
+  // To suppress missing implicit constructor warnings.
+  factory _SpeechRecognitionResultList._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  int get length => JS("int", "#.length", this);
+
+  SpeechRecognitionResult operator [](int index) {
+    if (JS("bool", "# >>> 0 !== # || # >= #", index, index, index, length))
+      throw new RangeError.index(index, this);
+    return JS("SpeechRecognitionResult", "#[#]", this, index);
+  }
+
+  void operator []=(int index, SpeechRecognitionResult value) {
+    throw new UnsupportedError("Cannot assign element of immutable List.");
+  }
+  // -- start List<SpeechRecognitionResult> mixins.
+  // SpeechRecognitionResult is the element type.
+
+  set length(int value) {
+    throw new UnsupportedError("Cannot resize immutable List.");
+  }
+
+  SpeechRecognitionResult get first {
+    if (this.length > 0) {
+      return JS('SpeechRecognitionResult', '#[0]', this);
+    }
+    throw new StateError("No elements");
+  }
+
+  SpeechRecognitionResult get last {
+    int len = this.length;
+    if (len > 0) {
+      return JS('SpeechRecognitionResult', '#[#]', this, len - 1);
+    }
+    throw new StateError("No elements");
+  }
+
+  SpeechRecognitionResult get single {
+    int len = this.length;
+    if (len == 1) {
+      return JS('SpeechRecognitionResult', '#[0]', this);
+    }
+    if (len == 0) throw new StateError("No elements");
+    throw new StateError("More than one element");
+  }
+
+  SpeechRecognitionResult elementAt(int index) => this[index];
+  // -- end List<SpeechRecognitionResult> mixins.
+
+  SpeechRecognitionResult item(int index) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("StyleSheetList")
+class _StyleSheetList extends Interceptor
+    with ListMixin<StyleSheet>, ImmutableListMixin<StyleSheet>
+    implements List<StyleSheet>, JavaScriptIndexingBehavior<StyleSheet> {
+  // To suppress missing implicit constructor warnings.
+  factory _StyleSheetList._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  int get length => JS("int", "#.length", this);
+
+  StyleSheet operator [](int index) {
+    if (JS("bool", "# >>> 0 !== # || # >= #", index, index, index, length))
+      throw new RangeError.index(index, this);
+    return JS("StyleSheet", "#[#]", this, index);
+  }
+
+  void operator []=(int index, StyleSheet value) {
+    throw new UnsupportedError("Cannot assign element of immutable List.");
+  }
+  // -- start List<StyleSheet> mixins.
+  // StyleSheet is the element type.
+
+  set length(int value) {
+    throw new UnsupportedError("Cannot resize immutable List.");
+  }
+
+  StyleSheet get first {
+    if (this.length > 0) {
+      return JS('StyleSheet', '#[0]', this);
+    }
+    throw new StateError("No elements");
+  }
+
+  StyleSheet get last {
+    int len = this.length;
+    if (len > 0) {
+      return JS('StyleSheet', '#[#]', this, len - 1);
+    }
+    throw new StateError("No elements");
+  }
+
+  StyleSheet get single {
+    int len = this.length;
+    if (len == 1) {
+      return JS('StyleSheet', '#[0]', this);
+    }
+    if (len == 0) throw new StateError("No elements");
+    throw new StateError("More than one element");
+  }
+
+  StyleSheet elementAt(int index) => this[index];
+  // -- end List<StyleSheet> mixins.
+
+  CssStyleSheet __getter__(String name) native;
+
+  StyleSheet item(int index) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("SubtleCrypto")
+abstract class _SubtleCrypto extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory _SubtleCrypto._() {
+    throw new UnsupportedError("Not supported");
+  }
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("USB")
+abstract class _USB extends EventTarget {
+  // To suppress missing implicit constructor warnings.
+  factory _USB._() {
+    throw new UnsupportedError("Not supported");
+  }
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("USBAlternateInterface")
+abstract class _USBAlternateInterface extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory _USBAlternateInterface._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory _USBAlternateInterface(
+      _USBInterface deviceInterface, int alternateSetting) {
+    return _USBAlternateInterface._create_1(deviceInterface, alternateSetting);
+  }
+  static _USBAlternateInterface _create_1(deviceInterface, alternateSetting) =>
+      JS('_USBAlternateInterface', 'new USBAlternateInterface(#,#)',
+          deviceInterface, alternateSetting);
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("USBConfiguration")
+abstract class _USBConfiguration extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory _USBConfiguration._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory _USBConfiguration(_USBDevice device, int configurationValue) {
+    return _USBConfiguration._create_1(device, configurationValue);
+  }
+  static _USBConfiguration _create_1(device, configurationValue) => JS(
+      '_USBConfiguration',
+      'new USBConfiguration(#,#)',
+      device,
+      configurationValue);
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("USBConnectionEvent")
+abstract class _USBConnectionEvent extends Event {
+  // To suppress missing implicit constructor warnings.
+  factory _USBConnectionEvent._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory _USBConnectionEvent(String type, Map eventInitDict) {
+    var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+    return _USBConnectionEvent._create_1(type, eventInitDict_1);
+  }
+  static _USBConnectionEvent _create_1(type, eventInitDict) => JS(
+      '_USBConnectionEvent',
+      'new USBConnectionEvent(#,#)',
+      type,
+      eventInitDict);
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("USBDevice")
+abstract class _USBDevice extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory _USBDevice._() {
+    throw new UnsupportedError("Not supported");
+  }
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("USBEndpoint")
+abstract class _USBEndpoint extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory _USBEndpoint._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory _USBEndpoint(
+      _USBAlternateInterface alternate, int endpointNumber, String direction) {
+    return _USBEndpoint._create_1(alternate, endpointNumber, direction);
+  }
+  static _USBEndpoint _create_1(alternate, endpointNumber, direction) => JS(
+      '_USBEndpoint',
+      'new USBEndpoint(#,#,#)',
+      alternate,
+      endpointNumber,
+      direction);
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("USBInTransferResult")
+abstract class _USBInTransferResult extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory _USBInTransferResult._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory _USBInTransferResult(String status, [ByteData data]) {
+    if (data != null) {
+      return _USBInTransferResult._create_1(status, data);
+    }
+    return _USBInTransferResult._create_2(status);
+  }
+  static _USBInTransferResult _create_1(status, data) =>
+      JS('_USBInTransferResult', 'new USBInTransferResult(#,#)', status, data);
+  static _USBInTransferResult _create_2(status) =>
+      JS('_USBInTransferResult', 'new USBInTransferResult(#)', status);
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("USBInterface")
+abstract class _USBInterface extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory _USBInterface._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory _USBInterface(_USBConfiguration configuration, int interfaceNumber) {
+    return _USBInterface._create_1(configuration, interfaceNumber);
+  }
+  static _USBInterface _create_1(configuration, interfaceNumber) => JS(
+      '_USBInterface', 'new USBInterface(#,#)', configuration, interfaceNumber);
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("USBIsochronousInTransferPacket")
+abstract class _USBIsochronousInTransferPacket extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory _USBIsochronousInTransferPacket._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory _USBIsochronousInTransferPacket(String status, [ByteData data]) {
+    if (data != null) {
+      return _USBIsochronousInTransferPacket._create_1(status, data);
+    }
+    return _USBIsochronousInTransferPacket._create_2(status);
+  }
+  static _USBIsochronousInTransferPacket _create_1(status, data) => JS(
+      '_USBIsochronousInTransferPacket',
+      'new USBIsochronousInTransferPacket(#,#)',
+      status,
+      data);
+  static _USBIsochronousInTransferPacket _create_2(status) => JS(
+      '_USBIsochronousInTransferPacket',
+      'new USBIsochronousInTransferPacket(#)',
+      status);
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("USBIsochronousInTransferResult")
+abstract class _USBIsochronousInTransferResult extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory _USBIsochronousInTransferResult._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory _USBIsochronousInTransferResult(
+      List<_USBIsochronousInTransferPacket> packets,
+      [ByteData data]) {
+    if (data != null) {
+      return _USBIsochronousInTransferResult._create_1(packets, data);
+    }
+    return _USBIsochronousInTransferResult._create_2(packets);
+  }
+  static _USBIsochronousInTransferResult _create_1(packets, data) => JS(
+      '_USBIsochronousInTransferResult',
+      'new USBIsochronousInTransferResult(#,#)',
+      packets,
+      data);
+  static _USBIsochronousInTransferResult _create_2(packets) => JS(
+      '_USBIsochronousInTransferResult',
+      'new USBIsochronousInTransferResult(#)',
+      packets);
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("USBIsochronousOutTransferPacket")
+abstract class _USBIsochronousOutTransferPacket extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory _USBIsochronousOutTransferPacket._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory _USBIsochronousOutTransferPacket(String status, [int bytesWritten]) {
+    if (bytesWritten != null) {
+      return _USBIsochronousOutTransferPacket._create_1(status, bytesWritten);
+    }
+    return _USBIsochronousOutTransferPacket._create_2(status);
+  }
+  static _USBIsochronousOutTransferPacket _create_1(status, bytesWritten) => JS(
+      '_USBIsochronousOutTransferPacket',
+      'new USBIsochronousOutTransferPacket(#,#)',
+      status,
+      bytesWritten);
+  static _USBIsochronousOutTransferPacket _create_2(status) => JS(
+      '_USBIsochronousOutTransferPacket',
+      'new USBIsochronousOutTransferPacket(#)',
+      status);
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("USBIsochronousOutTransferResult")
+abstract class _USBIsochronousOutTransferResult extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory _USBIsochronousOutTransferResult._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory _USBIsochronousOutTransferResult(
+      List<_USBIsochronousOutTransferPacket> packets) {
+    return _USBIsochronousOutTransferResult._create_1(packets);
+  }
+  static _USBIsochronousOutTransferResult _create_1(packets) => JS(
+      '_USBIsochronousOutTransferResult',
+      'new USBIsochronousOutTransferResult(#)',
+      packets);
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("USBOutTransferResult")
+abstract class _USBOutTransferResult extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory _USBOutTransferResult._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory _USBOutTransferResult(String status, [int bytesWritten]) {
+    if (bytesWritten != null) {
+      return _USBOutTransferResult._create_1(status, bytesWritten);
+    }
+    return _USBOutTransferResult._create_2(status);
+  }
+  static _USBOutTransferResult _create_1(status, bytesWritten) => JS(
+      '_USBOutTransferResult',
+      'new USBOutTransferResult(#,#)',
+      status,
+      bytesWritten);
+  static _USBOutTransferResult _create_2(status) =>
+      JS('_USBOutTransferResult', 'new USBOutTransferResult(#)', status);
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+abstract class _WindowTimers extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory _WindowTimers._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  int _setInterval_String(String handler, [int timeout, Object arguments]);
+
+  int _setTimeout_String(String handler, [int timeout, Object arguments]);
+
+  void _clearInterval([int handle]);
+
+  void _clearTimeout([int handle]);
+
+  int _setInterval(Object handler, [int timeout]);
+
+  int _setTimeout(Object handler, [int timeout]);
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("WorkerLocation")
+abstract class _WorkerLocation extends Interceptor implements UrlUtilsReadOnly {
+  // To suppress missing implicit constructor warnings.
+  factory _WorkerLocation._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  // From URLUtilsReadOnly
+
+}
+
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("WorkerNavigator")
+abstract class _WorkerNavigator extends NavigatorConcurrentHardware
+    implements NavigatorOnLine, NavigatorID {
+  // To suppress missing implicit constructor warnings.
+  factory _WorkerNavigator._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  // From NavigatorID
+
+  // From NavigatorOnLine
+
+}
+
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("Worklet")
+abstract class _Worklet extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory _Worklet._() {
+    throw new UnsupportedError("Not supported");
+  }
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+abstract class _AttributeMap extends MapBase<String, String> {
+  final Element _element;
+
+  _AttributeMap(this._element);
+
+  void addAll(Map<String, String> other) {
+    other.forEach((k, v) {
+      this[k] = v;
+    });
+  }
+
+  Map<K, V> cast<K, V>() => Map.castFrom<String, String, K, V>(this);
+  bool containsValue(Object value) {
+    for (var v in this.values) {
+      if (value == v) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  String putIfAbsent(String key, String ifAbsent()) {
+    if (!containsKey(key)) {
+      this[key] = ifAbsent();
+    }
+    return this[key];
+  }
+
+  void clear() {
+    for (var key in keys) {
+      remove(key);
+    }
+  }
+
+  void forEach(void f(String key, String value)) {
+    for (var key in keys) {
+      var value = this[key];
+      f(key, value);
+    }
+  }
+
+  Iterable<String> get keys {
+    // TODO: generate a lazy collection instead.
+    var attributes = _element._attributes;
+    var keys = <String>[];
+    for (int i = 0, len = attributes.length; i < len; i++) {
+      _Attr attr = attributes[i];
+      if (_matches(attr)) {
+        keys.add(attr.name);
+      }
+    }
+    return keys;
+  }
+
+  Iterable<String> get values {
+    // TODO: generate a lazy collection instead.
+    var attributes = _element._attributes;
+    var values = <String>[];
+    for (int i = 0, len = attributes.length; i < len; i++) {
+      _Attr attr = attributes[i];
+      if (_matches(attr)) {
+        values.add(attr.value);
+      }
+    }
+    return values;
+  }
+
+  /**
+   * Returns true if there is no {key, value} pair in the map.
+   */
+  bool get isEmpty {
+    return length == 0;
+  }
+
+  /**
+   * Returns true if there is at least one {key, value} pair in the map.
+   */
+  bool get isNotEmpty => !isEmpty;
+
+  /**
+   * Checks to see if the node should be included in this map.
+   */
+  bool _matches(_Attr node);
+}
+
+/**
+ * Wrapper to expose [Element.attributes] as a typed map.
+ */
+class _ElementAttributeMap extends _AttributeMap {
+  _ElementAttributeMap(Element element) : super(element);
+
+  bool containsKey(Object key) {
+    return _element._hasAttribute(key);
+  }
+
+  String operator [](Object key) {
+    return _element.getAttribute(key);
+  }
+
+  void operator []=(String key, String value) {
+    _element.setAttribute(key, value);
+  }
+
+  @pragma('dart2js:tryInline')
+  String remove(Object key) => key is String ? _remove(_element, key) : null;
+
+  /**
+   * The number of {key, value} pairs in the map.
+   */
+  int get length {
+    return keys.length;
+  }
+
+  bool _matches(_Attr node) => node._namespaceUri == null;
+
+  // Inline this because almost all call sites of [remove] do not use [value],
+  // and the annotations on the `getAttribute` call allow it to be removed.
+  @pragma('dart2js:tryInline')
+  static String _remove(Element element, String key) {
+    String value = JS(
+        // throws:null(1) is not accurate since [key] could be malformed, but
+        // [key] is checked again by `removeAttributeNS`.
+        'returns:String|Null;depends:all;effects:none;throws:null(1)',
+        '#.getAttribute(#)',
+        element,
+        key);
+    JS('', '#.removeAttribute(#)', element, key);
+    return value;
+  }
+}
+
+/**
+ * Wrapper to expose namespaced attributes as a typed map.
+ */
+class _NamespacedAttributeMap extends _AttributeMap {
+  final String _namespace;
+
+  _NamespacedAttributeMap(Element element, this._namespace) : super(element);
+
+  bool containsKey(Object key) {
+    return _element._hasAttributeNS(_namespace, key);
+  }
+
+  String operator [](Object key) {
+    return _element.getAttributeNS(_namespace, key);
+  }
+
+  void operator []=(String key, String value) {
+    _element.setAttributeNS(_namespace, key, value);
+  }
+
+  @pragma('dart2js:tryInline')
+  String remove(Object key) =>
+      key is String ? _remove(_namespace, _element, key) : null;
+
+  /**
+   * The number of {key, value} pairs in the map.
+   */
+  int get length {
+    return keys.length;
+  }
+
+  bool _matches(_Attr node) => node._namespaceUri == _namespace;
+
+  // Inline this because almost all call sites of [remove] do not use the
+  // returned [value], and the annotations on the `getAttributeNS` call allow it
+  // to be removed.
+  @pragma('dart2js:tryInline')
+  static String _remove(String namespace, Element element, String key) {
+    String value = JS(
+        // throws:null(1) is not accurate since [key] could be malformed, but
+        // [key] is checked again by `removeAttributeNS`.
+        'returns:String|Null;depends:all;effects:none;throws:null(1)',
+        '#.getAttributeNS(#, #)',
+        element,
+        namespace,
+        key);
+    JS('', '#.removeAttributeNS(#, #)', element, namespace, key);
+    return value;
+  }
+}
+
+/**
+ * Provides a Map abstraction on top of data-* attributes, similar to the
+ * dataSet in the old DOM.
+ */
+class _DataAttributeMap extends MapBase<String, String> {
+  final Map<String, String> _attributes;
+
+  _DataAttributeMap(this._attributes);
+
+  // interface Map
+
+  void addAll(Map<String, String> other) {
+    other.forEach((k, v) {
+      this[k] = v;
+    });
+  }
+
+  Map<K, V> cast<K, V>() => Map.castFrom<String, String, K, V>(this);
+  // TODO: Use lazy iterator when it is available on Map.
+  bool containsValue(Object value) => values.any((v) => v == value);
+
+  bool containsKey(Object key) => _attributes.containsKey(_attr(key));
+
+  String operator [](Object key) => _attributes[_attr(key)];
+
+  void operator []=(String key, String value) {
+    _attributes[_attr(key)] = value;
+  }
+
+  String putIfAbsent(String key, String ifAbsent()) =>
+      _attributes.putIfAbsent(_attr(key), ifAbsent);
+
+  String remove(Object key) => _attributes.remove(_attr(key));
+
+  void clear() {
+    // Needs to operate on a snapshot since we are mutating the collection.
+    for (String key in keys) {
+      remove(key);
+    }
+  }
+
+  void forEach(void f(String key, String value)) {
+    _attributes.forEach((String key, String value) {
+      if (_matches(key)) {
+        f(_strip(key), value);
+      }
+    });
+  }
+
+  Iterable<String> get keys {
+    final keys = <String>[];
+    _attributes.forEach((String key, String value) {
+      if (_matches(key)) {
+        keys.add(_strip(key));
+      }
+    });
+    return keys;
+  }
+
+  Iterable<String> get values {
+    final values = <String>[];
+    _attributes.forEach((String key, String value) {
+      if (_matches(key)) {
+        values.add(value);
+      }
+    });
+    return values;
+  }
+
+  int get length => keys.length;
+
+  // TODO: Use lazy iterator when it is available on Map.
+  bool get isEmpty => length == 0;
+
+  bool get isNotEmpty => !isEmpty;
+
+  // Helpers.
+  String _attr(String key) => 'data-${_toHyphenedName(key)}';
+  bool _matches(String key) => key.startsWith('data-');
+  String _strip(String key) => _toCamelCase(key.substring(5));
+
+  /**
+   * Converts a string name with hyphens into an identifier, by removing hyphens
+   * and capitalizing the following letter. Optionally [startUppercase] to
+   * capitalize the first letter.
+   */
+  String _toCamelCase(String hyphenedName, {bool startUppercase: false}) {
+    var segments = hyphenedName.split('-');
+    int start = startUppercase ? 0 : 1;
+    for (int i = start; i < segments.length; i++) {
+      var segment = segments[i];
+      if (segment.length > 0) {
+        // Character between 'a'..'z' mapped to 'A'..'Z'
+        segments[i] = '${segment[0].toUpperCase()}${segment.substring(1)}';
+      }
+    }
+    return segments.join('');
+  }
+
+  /** Reverse of [toCamelCase]. */
+  String _toHyphenedName(String word) {
+    var sb = new StringBuffer();
+    for (int i = 0; i < word.length; i++) {
+      var lower = word[i].toLowerCase();
+      if (word[i] != lower && i > 0) sb.write('-');
+      sb.write(lower);
+    }
+    return sb.toString();
+  }
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/**
+ * An object that can be drawn to a 2D canvas rendering context.
+ *
+ * The image drawn to the canvas depends on the type of this object:
+ *
+ * * If this object is an [ImageElement], then this element's image is
+ * drawn to the canvas. If this element is an animated image, then this
+ * element's poster frame is drawn. If this element has no poster frame, then
+ * the first frame of animation is drawn.
+ *
+ * * If this object is a [VideoElement], then the frame at this element's current
+ * playback position is drawn to the canvas.
+ *
+ * * If this object is a [CanvasElement], then this element's bitmap is drawn to
+ * the canvas.
+ *
+ * **Note:** Currently all versions of Internet Explorer do not support
+ * drawing a video element to a canvas. You may also encounter problems drawing
+ * a video to a canvas in Firefox if the source of the video is a data URL.
+ *
+ * ## See also
+ *
+ * * [CanvasRenderingContext2D.drawImage]
+ * * [CanvasRenderingContext2D.drawImageToRect]
+ * * [CanvasRenderingContext2D.drawImageScaled]
+ * * [CanvasRenderingContext2D.drawImageScaledFromSource]
+ *
+ * ## Other resources
+ *
+ * * [Image sources for 2D rendering
+ *   contexts](https://html.spec.whatwg.org/multipage/scripting.html#image-sources-for-2d-rendering-contexts)
+ *   from WHATWG.
+ * * [Drawing images](https://html.spec.whatwg.org/multipage/scripting.html#dom-context-2d-drawimage)
+ *   from WHATWG.
+ */
+abstract class CanvasImageSource {}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/**
+ * Top-level container for a browser tab or window.
+ *
+ * In a web browser, a [WindowBase] object represents any browser window. This
+ * object contains the window's state and its relation to other
+ * windows, such as which window opened this window.
+ *
+ * **Note:** This class represents any window, while [Window] is
+ * used to access the properties and content of the current window or tab.
+ *
+ * ## See also
+ *
+ * * [Window]
+ *
+ * ## Other resources
+ *
+ * * [DOM Window](https://developer.mozilla.org/en-US/docs/DOM/window) from MDN.
+ * * [Window](http://www.w3.org/TR/Window/) from the W3C.
+ */
+abstract class WindowBase implements EventTarget {
+  // Fields.
+
+  /**
+   * The current location of this window.
+   *
+   *     Location currentLocation = window.location;
+   *     print(currentLocation.href); // 'http://www.example.com:80/'
+   */
+  LocationBase get location;
+
+  /**
+   * The current session history for this window.
+   *
+   * ## Other resources
+   *
+   * * [Session history and navigation
+   *   specification](https://html.spec.whatwg.org/multipage/browsers.html#history)
+   *   from WHATWG.
+   */
+  HistoryBase get history;
+
+  /**
+   * Indicates whether this window has been closed.
+   *
+   *     print(window.closed); // 'false'
+   *     window.close();
+   *     print(window.closed); // 'true'
+   */
+  bool get closed;
+
+  /**
+   * A reference to the window that opened this one.
+   *
+   *     Window thisWindow = window;
+   *     WindowBase otherWindow = thisWindow.open('http://www.example.com/', 'foo');
+   *     print(otherWindow.opener == thisWindow); // 'true'
+   */
+  WindowBase get opener;
+
+  /**
+   * A reference to the parent of this window.
+   *
+   * If this [WindowBase] has no parent, [parent] will return a reference to
+   * the [WindowBase] itself.
+   *
+   *     IFrameElement myIFrame = new IFrameElement();
+   *     window.document.body.elements.add(myIFrame);
+   *     print(myIframe.contentWindow.parent == window) // 'true'
+   *
+   *     print(window.parent == window) // 'true'
+   */
+  WindowBase get parent;
+
+  /**
+   * A reference to the topmost window in the window hierarchy.
+   *
+   * If this [WindowBase] is the topmost [WindowBase], [top] will return a
+   * reference to the [WindowBase] itself.
+   *
+   *     // Add an IFrame to the current window.
+   *     IFrameElement myIFrame = new IFrameElement();
+   *     window.document.body.elements.add(myIFrame);
+   *
+   *     // Add an IFrame inside of the other IFrame.
+   *     IFrameElement innerIFrame = new IFrameElement();
+   *     myIFrame.elements.add(innerIFrame);
+   *
+   *     print(myIframe.contentWindow.top == window) // 'true'
+   *     print(innerIFrame.contentWindow.top == window) // 'true'
+   *
+   *     print(window.top == window) // 'true'
+   */
+  WindowBase get top;
+
+  // Methods.
+  /**
+   * Closes the window.
+   *
+   * This method should only succeed if the [WindowBase] object is
+   * **script-closeable** and the window calling [close] is allowed to navigate
+   * the window.
+   *
+   * A window is script-closeable if it is either a window
+   * that was opened by another window, or if it is a window with only one
+   * document in its history.
+   *
+   * A window might not be allowed to navigate, and therefore close, another
+   * window due to browser security features.
+   *
+   *     var other = window.open('http://www.example.com', 'foo');
+   *     // Closes other window, as it is script-closeable.
+   *     other.close();
+   *     print(other.closed); // 'true'
+   *
+   *     var newLocation = window.location
+   *         ..href = 'http://www.mysite.com';
+   *     window.location = newLocation;
+   *     // Does not close this window, as the history has changed.
+   *     window.close();
+   *     print(window.closed); // 'false'
+   *
+   * See also:
+   *
+   * * [Window close discussion](http://www.w3.org/TR/html5/browsers.html#dom-window-close) from the W3C
+   */
+  void close();
+
+  /**
+   * Sends a cross-origin message.
+   *
+   * ## Other resources
+   *
+   * * [window.postMessage](https://developer.mozilla.org/en-US/docs/Web/API/Window.postMessage)
+   *   from MDN.
+   * * [Cross-document messaging](https://html.spec.whatwg.org/multipage/comms.html#web-messaging)
+   *   from WHATWG.
+   */
+  void postMessage(var message, String targetOrigin,
+      [List<MessagePort> messagePorts]);
+}
+
+abstract class LocationBase {
+  void set href(String val);
+}
+
+abstract class HistoryBase {
+  void back();
+  void forward();
+  void go(int distance);
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/** A Set that stores the CSS class names for an element. */
+abstract class CssClassSet implements Set<String> {
+  /**
+   * Adds the class [value] to the element if it is not on it, removes it if it
+   * is.
+   *
+   * 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.
+   *
+   * If this corresponds to one element, returns `true` if [value] is present
+   * after the operation, and returns `false` if [value] is absent after the
+   * operation.
+   *
+   * If this corresponds to many elements, `null` is always returned.
+   *
+   * [value] must be a valid 'token' representing a single class, i.e. a
+   * non-empty string containing no whitespace.  To toggle multiple classes, use
+   * [toggleAll].
+   */
+  bool toggle(String value, [bool shouldAdd]);
+
+  /**
+   * Returns [:true:] if classes cannot be added or removed from this
+   * [:CssClassSet:].
+   */
+  bool get frozen;
+
+  /**
+   * Determine if this element contains the class [value].
+   *
+   * This is the Dart equivalent of jQuery's
+   * [hasClass](http://api.jquery.com/hasClass/).
+   *
+   * [value] must be a valid 'token' representing a single class, i.e. a
+   * non-empty string containing no whitespace.
+   */
+  bool contains(Object value);
+
+  /**
+   * Add the class [value] to element.
+   *
+   * [add] and [addAll] are the Dart equivalent of jQuery's
+   * [addClass](http://api.jquery.com/addClass/).
+   *
+   * If this CssClassSet corresponds to one element. Returns true if [value] was
+   * added to the set, otherwise false.
+   *
+   * If this corresponds to many elements, `null` is always returned.
+   *
+   * [value] must be a valid 'token' representing a single class, i.e. a
+   * non-empty string containing no whitespace.  To add multiple classes use
+   * [addAll].
+   */
+  bool add(String value);
+
+  /**
+   * Remove the class [value] from element, and return true on successful
+   * removal.
+   *
+   * [remove] and [removeAll] are the Dart equivalent of jQuery's
+   * [removeClass](http://api.jquery.com/removeClass/).
+   *
+   * [value] must be a valid 'token' representing a single class, i.e. a
+   * non-empty string containing no whitespace.  To remove multiple classes, use
+   * [removeAll].
+   */
+  bool remove(Object value);
+
+  /**
+   * Add all classes specified in [iterable] to element.
+   *
+   * [add] and [addAll] are the Dart equivalent of jQuery's
+   * [addClass](http://api.jquery.com/addClass/).
+   *
+   * Each element of [iterable] must be a valid 'token' representing a single
+   * class, i.e. a non-empty string containing no whitespace.
+   */
+  void addAll(Iterable<String> iterable);
+
+  /**
+   * Remove all classes specified in [iterable] from element.
+   *
+   * [remove] and [removeAll] are the Dart equivalent of jQuery's
+   * [removeClass](http://api.jquery.com/removeClass/).
+   *
+   * Each element of [iterable] must be a valid 'token' representing a single
+   * class, i.e. a non-empty string containing no whitespace.
+   */
+  void removeAll(Iterable<Object> iterable);
+
+  /**
+   * Toggles all classes specified in [iterable] on element.
+   *
+   * Iterate through [iterable]'s items, and add it if it is not on it, or
+   * remove it if it is. This is the Dart equivalent of jQuery's
+   * [toggleClass](http://api.jquery.com/toggleClass/).
+   * 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.
+   *
+   * Each element of [iterable] must be a valid 'token' representing a single
+   * class, i.e. a non-empty string containing no whitespace.
+   */
+  void toggleAll(Iterable<String> iterable, [bool shouldAdd]);
+}
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/**
+ * A rectangle representing all the content of the element in the
+ * [box model](http://www.w3.org/TR/CSS2/box.html).
+ */
+class _ContentCssRect extends CssRect {
+  _ContentCssRect(Element element) : super(element);
+
+  num get height =>
+      _element.offsetHeight + _addOrSubtractToBoxModel(_HEIGHT, _CONTENT);
+
+  num get width =>
+      _element.offsetWidth + _addOrSubtractToBoxModel(_WIDTH, _CONTENT);
+
+  /**
+   * Set the height to `newHeight`.
+   *
+   * newHeight can be either a [num] representing the height in pixels or a
+   * [Dimension] object. Values of newHeight that are less than zero are
+   * converted to effectively setting the height to 0. This is equivalent to the
+   * `height` function in jQuery and the calculated `height` CSS value,
+   * converted to a num in pixels.
+   */
+  set height(dynamic newHeight) {
+    if (newHeight is Dimension) {
+      Dimension newHeightAsDimension = newHeight;
+      if (newHeightAsDimension.value < 0) newHeight = new Dimension.px(0);
+      _element.style.height = newHeight.toString();
+    } else if (newHeight is num) {
+      if (newHeight < 0) newHeight = 0;
+      _element.style.height = '${newHeight}px';
+    } else {
+      throw new ArgumentError("newHeight is not a Dimension or num");
+    }
+  }
+
+  /**
+   * Set the current computed width in pixels of this element.
+   *
+   * newWidth can be either a [num] representing the width in pixels or a
+   * [Dimension] object. This is equivalent to the `width` function in jQuery
+   * and the calculated
+   * `width` CSS value, converted to a dimensionless num in pixels.
+   */
+  set width(dynamic newWidth) {
+    if (newWidth is Dimension) {
+      Dimension newWidthAsDimension = newWidth;
+      if (newWidthAsDimension.value < 0) newWidth = new Dimension.px(0);
+      _element.style.width = newWidth.toString();
+    } else if (newWidth is num) {
+      if (newWidth < 0) newWidth = 0;
+      _element.style.width = '${newWidth}px';
+    } else {
+      throw new ArgumentError("newWidth is not a Dimension or num");
+    }
+  }
+
+  num get left =>
+      _element.getBoundingClientRect().left -
+      _addOrSubtractToBoxModel(['left'], _CONTENT);
+  num get top =>
+      _element.getBoundingClientRect().top -
+      _addOrSubtractToBoxModel(['top'], _CONTENT);
+}
+
+/**
+ * A list of element content rectangles in the
+ * [box model](http://www.w3.org/TR/CSS2/box.html).
+ */
+class _ContentCssListRect extends _ContentCssRect {
+  List<Element> _elementList;
+
+  _ContentCssListRect(List<Element> elementList) : super(elementList.first) {
+    _elementList = elementList;
+  }
+
+  /**
+   * Set the height to `newHeight`.
+   *
+   * Values of newHeight that are less than zero are converted to effectively
+   * setting the height to 0. This is equivalent to the `height`
+   * function in jQuery and the calculated `height` CSS value, converted to a
+   * num in pixels.
+   */
+  set height(newHeight) {
+    _elementList.forEach((e) => e.contentEdge.height = newHeight);
+  }
+
+  /**
+   * Set the current computed width in pixels of this element.
+   *
+   * This is equivalent to the `width` function in jQuery and the calculated
+   * `width` CSS value, converted to a dimensionless num in pixels.
+   */
+  set width(newWidth) {
+    _elementList.forEach((e) => e.contentEdge.width = newWidth);
+  }
+}
+
+/**
+ * A rectangle representing the dimensions of the space occupied by the
+ * element's content + padding in the
+ * [box model](http://www.w3.org/TR/CSS2/box.html).
+ */
+class _PaddingCssRect extends CssRect {
+  _PaddingCssRect(element) : super(element);
+  num get height =>
+      _element.offsetHeight + _addOrSubtractToBoxModel(_HEIGHT, _PADDING);
+  num get width =>
+      _element.offsetWidth + _addOrSubtractToBoxModel(_WIDTH, _PADDING);
+
+  num get left =>
+      _element.getBoundingClientRect().left -
+      _addOrSubtractToBoxModel(['left'], _PADDING);
+  num get top =>
+      _element.getBoundingClientRect().top -
+      _addOrSubtractToBoxModel(['top'], _PADDING);
+}
+
+/**
+ * A rectangle representing the dimensions of the space occupied by the
+ * element's content + padding + border in the
+ * [box model](http://www.w3.org/TR/CSS2/box.html).
+ */
+class _BorderCssRect extends CssRect {
+  _BorderCssRect(element) : super(element);
+  num get height => _element.offsetHeight;
+  num get width => _element.offsetWidth;
+
+  num get left => _element.getBoundingClientRect().left;
+  num get top => _element.getBoundingClientRect().top;
+}
+
+/**
+ * A rectangle representing the dimensions of the space occupied by the
+ * element's content + padding + border + margin in the
+ * [box model](http://www.w3.org/TR/CSS2/box.html).
+ */
+class _MarginCssRect extends CssRect {
+  _MarginCssRect(element) : super(element);
+  num get height =>
+      _element.offsetHeight + _addOrSubtractToBoxModel(_HEIGHT, _MARGIN);
+  num get width =>
+      _element.offsetWidth + _addOrSubtractToBoxModel(_WIDTH, _MARGIN);
+
+  num get left =>
+      _element.getBoundingClientRect().left -
+      _addOrSubtractToBoxModel(['left'], _MARGIN);
+  num get top =>
+      _element.getBoundingClientRect().top -
+      _addOrSubtractToBoxModel(['top'], _MARGIN);
+}
+
+/**
+ * A class for representing CSS dimensions.
+ *
+ * In contrast to the more general purpose [Rectangle] class, this class's
+ * values are mutable, so one can change the height of an element
+ * programmatically.
+ *
+ * _Important_ _note_: use of these methods will perform CSS calculations that
+ * can trigger a browser reflow. Therefore, use of these properties _during_ an
+ * animation frame is discouraged. See also:
+ * [Browser Reflow](https://developers.google.com/speed/articles/reflow)
+ */
+abstract class CssRect implements Rectangle<num> {
+  Element _element;
+
+  CssRect(this._element);
+
+  num get left;
+
+  num get top;
+
+  /**
+   * The height of this rectangle.
+   *
+   * This is equivalent to the `height` function in jQuery and the calculated
+   * `height` CSS value, converted to a dimensionless num in pixels. Unlike
+   * [getBoundingClientRect], `height` will return the same numerical width if
+   * the element is hidden or not.
+   */
+  num get height;
+
+  /**
+   * The width of this rectangle.
+   *
+   * This is equivalent to the `width` function in jQuery and the calculated
+   * `width` CSS value, converted to a dimensionless num in pixels. Unlike
+   * [getBoundingClientRect], `width` will return the same numerical width if
+   * the element is hidden or not.
+   */
+  num get width;
+
+  /**
+   * Set the height to `newHeight`.
+   *
+   * newHeight can be either a [num] representing the height in pixels or a
+   * [Dimension] object. Values of newHeight that are less than zero are
+   * converted to effectively setting the height to 0. This is equivalent to the
+   * `height` function in jQuery and the calculated `height` CSS value,
+   * converted to a num in pixels.
+   *
+   * Note that only the content height can actually be set via this method.
+   */
+  set height(dynamic newHeight) {
+    throw new UnsupportedError("Can only set height for content rect.");
+  }
+
+  /**
+   * Set the current computed width in pixels of this element.
+   *
+   * newWidth can be either a [num] representing the width in pixels or a
+   * [Dimension] object. This is equivalent to the `width` function in jQuery
+   * and the calculated
+   * `width` CSS value, converted to a dimensionless num in pixels.
+   *
+   * Note that only the content width can be set via this method.
+   */
+  set width(dynamic newWidth) {
+    throw new UnsupportedError("Can only set width for content rect.");
+  }
+
+  /**
+   * Return a value that is used to modify the initial height or width
+   * measurement of an element. Depending on the value (ideally an enum) passed
+   * to augmentingMeasurement, we may need to add or subtract margin, padding,
+   * or border values, depending on the measurement we're trying to obtain.
+   */
+  num _addOrSubtractToBoxModel(
+      List<String> dimensions, String augmentingMeasurement) {
+    // getComputedStyle always returns pixel values (hence, computed), so we're
+    // always dealing with pixels in this method.
+    var styles = _element.getComputedStyle();
+
+    var val = 0;
+
+    for (String measurement in dimensions) {
+      // The border-box and default box model both exclude margin in the regular
+      // height/width calculation, so add it if we want it for this measurement.
+      if (augmentingMeasurement == _MARGIN) {
+        val += new Dimension.css(
+                styles.getPropertyValue('$augmentingMeasurement-$measurement'))
+            .value;
+      }
+
+      // The border-box includes padding and border, so remove it if we want
+      // just the content itself.
+      if (augmentingMeasurement == _CONTENT) {
+        val -= new Dimension.css(
+                styles.getPropertyValue('${_PADDING}-$measurement'))
+            .value;
+      }
+
+      // At this point, we don't wan't to augment with border or margin,
+      // so remove border.
+      if (augmentingMeasurement != _MARGIN) {
+        val -= new Dimension.css(
+                styles.getPropertyValue('border-${measurement}-width'))
+            .value;
+      }
+    }
+    return val;
+  }
+
+  // TODO(jacobr): these methods are duplicated from _RectangleBase in dart:math
+  // Ideally we would provide a RectangleMixin class that provides this implementation.
+  // In an ideal world we would exp
+  /** The x-coordinate of the right edge. */
+  num get right => left + width;
+  /** The y-coordinate of the bottom edge. */
+  num get bottom => top + height;
+
+  String toString() {
+    return 'Rectangle ($left, $top) $width x $height';
+  }
+
+  bool operator ==(other) {
+    if (other is! Rectangle) return false;
+    return left == other.left &&
+        top == other.top &&
+        right == other.right &&
+        bottom == other.bottom;
+  }
+
+  int get hashCode => _JenkinsSmiHash.hash4(
+      left.hashCode, top.hashCode, right.hashCode, bottom.hashCode);
+
+  /**
+   * Computes the intersection of `this` and [other].
+   *
+   * The intersection of two axis-aligned rectangles, if any, is always another
+   * axis-aligned rectangle.
+   *
+   * Returns the intersection of this and `other`, or `null` if they don't
+   * intersect.
+   */
+  Rectangle<num> intersection(Rectangle<num> other) {
+    var x0 = max(left, other.left);
+    var x1 = min(left + width, other.left + other.width);
+
+    if (x0 <= x1) {
+      var y0 = max(top, other.top);
+      var y1 = min(top + height, other.top + other.height);
+
+      if (y0 <= y1) {
+        return new Rectangle<num>(x0, y0, x1 - x0, y1 - y0);
+      }
+    }
+    return null;
+  }
+
+  /**
+   * Returns true if `this` intersects [other].
+   */
+  bool intersects(Rectangle<num> other) {
+    return (left <= other.left + other.width &&
+        other.left <= left + width &&
+        top <= other.top + other.height &&
+        other.top <= top + height);
+  }
+
+  /**
+   * Returns a new rectangle which completely contains `this` and [other].
+   */
+  Rectangle<num> boundingBox(Rectangle<num> other) {
+    var right = max(this.left + this.width, other.left + other.width);
+    var bottom = max(this.top + this.height, other.top + other.height);
+
+    var left = min(this.left, other.left);
+    var top = min(this.top, other.top);
+
+    return new Rectangle<num>(left, top, right - left, bottom - top);
+  }
+
+  /**
+   * Tests whether `this` entirely contains [another].
+   */
+  bool containsRectangle(Rectangle<num> another) {
+    return left <= another.left &&
+        left + width >= another.left + another.width &&
+        top <= another.top &&
+        top + height >= another.top + another.height;
+  }
+
+  /**
+   * Tests whether [another] is inside or along the edges of `this`.
+   */
+  bool containsPoint(Point<num> another) {
+    return another.x >= left &&
+        another.x <= left + width &&
+        another.y >= top &&
+        another.y <= top + height;
+  }
+
+  Point<num> get topLeft => new Point<num>(this.left, this.top);
+  Point<num> get topRight => new Point<num>(this.left + this.width, this.top);
+  Point<num> get bottomRight =>
+      new Point<num>(this.left + this.width, this.top + this.height);
+  Point<num> get bottomLeft =>
+      new Point<num>(this.left, this.top + this.height);
+}
+
+final _HEIGHT = ['top', 'bottom'];
+final _WIDTH = ['right', 'left'];
+final _CONTENT = 'content';
+final _PADDING = 'padding';
+final _MARGIN = 'margin';
+// Copyright (c) 2015, 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.
+
+/**
+ * A set (union) of the CSS classes that are present in a set of elements.
+ * Implemented separately from _ElementCssClassSet for performance.
+ */
+class _MultiElementCssClassSet extends CssClassSetImpl {
+  final Iterable<Element> _elementIterable;
+
+  // TODO(sra): Perhaps we should store the DomTokenList instead.
+  final List<CssClassSetImpl> _sets;
+
+  factory _MultiElementCssClassSet(Iterable<Element> elements) {
+    return new _MultiElementCssClassSet._(elements,
+        new List<CssClassSetImpl>.from(elements.map((Element e) => e.classes)));
+  }
+
+  _MultiElementCssClassSet._(this._elementIterable, this._sets);
+
+  Set<String> readClasses() {
+    var s = new LinkedHashSet<String>();
+    _sets.forEach((CssClassSetImpl e) => s.addAll(e.readClasses()));
+    return s;
+  }
+
+  void writeClasses(Set<String> s) {
+    var classes = s.join(' ');
+    for (Element e in _elementIterable) {
+      e.className = classes;
+    }
+  }
+
+  /**
+   * Helper method used to modify the set of css classes on this element.
+   *
+   *   f - callback with:
+   *   s - a Set of all the css class name currently on this element.
+   *
+   *   After f returns, the modified set is written to the
+   *       className property of this element.
+   */
+  modify(f(Set<String> s)) {
+    _sets.forEach((CssClassSetImpl e) => e.modify(f));
+  }
+
+  /**
+   * Adds the class [value] to the element if it is not on it, removes it if it
+   * is.
+   *
+   * TODO(sra): It seems wrong to collect a 'changed' flag like this when the
+   * underlying toggle returns an 'is set' flag.
+   */
+  bool toggle(String value, [bool shouldAdd]) => _sets.fold(
+      false,
+      (bool changed, CssClassSetImpl e) =>
+          e.toggle(value, shouldAdd) || changed);
+
+  /**
+   * Remove the class [value] from element, and return true on successful
+   * removal.
+   *
+   * This is the Dart equivalent of jQuery's
+   * [removeClass](http://api.jquery.com/removeClass/).
+   */
+  bool remove(Object value) => _sets.fold(
+      false, (bool changed, CssClassSetImpl e) => e.remove(value) || changed);
+}
+
+class _ElementCssClassSet extends CssClassSetImpl {
+  final Element _element;
+
+  _ElementCssClassSet(this._element);
+
+  Set<String> readClasses() {
+    var s = new LinkedHashSet<String>();
+    var classname = _element.className;
+
+    for (String name in classname.split(' ')) {
+      String trimmed = name.trim();
+      if (!trimmed.isEmpty) {
+        s.add(trimmed);
+      }
+    }
+    return s;
+  }
+
+  void writeClasses(Set<String> s) {
+    _element.className = s.join(' ');
+  }
+
+  int get length => _classListLength(_classListOf(_element));
+  bool get isEmpty => length == 0;
+  bool get isNotEmpty => length != 0;
+
+  void clear() {
+    _element.className = '';
+  }
+
+  bool contains(Object value) {
+    return _contains(_element, value);
+  }
+
+  bool add(String value) {
+    return _add(_element, value);
+  }
+
+  bool remove(Object value) {
+    return value is String && _remove(_element, value);
+  }
+
+  bool toggle(String value, [bool shouldAdd]) {
+    return _toggle(_element, value, shouldAdd);
+  }
+
+  void addAll(Iterable<String> iterable) {
+    _addAll(_element, iterable);
+  }
+
+  void removeAll(Iterable<Object> iterable) {
+    _removeAll(_element, iterable);
+  }
+
+  void retainAll(Iterable<Object> iterable) {
+    _removeWhere(_element, iterable.toSet().contains, false);
+  }
+
+  void removeWhere(bool test(String name)) {
+    _removeWhere(_element, test, true);
+  }
+
+  void retainWhere(bool test(String name)) {
+    _removeWhere(_element, test, false);
+  }
+
+  static bool _contains(Element _element, Object value) {
+    return value is String && _classListContains(_classListOf(_element), value);
+  }
+
+  @pragma('dart2js:tryInline')
+  static bool _add(Element _element, String value) {
+    DomTokenList list = _classListOf(_element);
+    // Compute returned result independently of action upon the set.
+    bool added = !_classListContainsBeforeAddOrRemove(list, value);
+    _classListAdd(list, value);
+    return added;
+  }
+
+  @pragma('dart2js:tryInline')
+  static bool _remove(Element _element, String value) {
+    DomTokenList list = _classListOf(_element);
+    bool removed = _classListContainsBeforeAddOrRemove(list, value);
+    _classListRemove(list, value);
+    return removed;
+  }
+
+  static bool _toggle(Element _element, String value, bool shouldAdd) {
+    // There is no value that can be passed as the second argument of
+    // DomTokenList.toggle that behaves the same as passing one argument.
+    // `null` is seen as false, meaning 'remove'.
+    return shouldAdd == null
+        ? _toggleDefault(_element, value)
+        : _toggleOnOff(_element, value, shouldAdd);
+  }
+
+  static bool _toggleDefault(Element _element, String value) {
+    DomTokenList list = _classListOf(_element);
+    return _classListToggle1(list, value);
+  }
+
+  static bool _toggleOnOff(Element _element, String value, bool shouldAdd) {
+    DomTokenList list = _classListOf(_element);
+    // IE's toggle does not take a second parameter. We would prefer:
+    //
+    //    return _classListToggle2(list, value, shouldAdd);
+    //
+    if (shouldAdd) {
+      _classListAdd(list, value);
+      return true;
+    } else {
+      _classListRemove(list, value);
+      return false;
+    }
+  }
+
+  static void _addAll(Element _element, Iterable<String> iterable) {
+    DomTokenList list = _classListOf(_element);
+    for (String value in iterable) {
+      _classListAdd(list, value);
+    }
+  }
+
+  static void _removeAll(Element _element, Iterable<Object> iterable) {
+    DomTokenList list = _classListOf(_element);
+    for (String value in iterable) {
+      _classListRemove(list, value);
+    }
+  }
+
+  static void _removeWhere(
+      Element _element, bool test(String name), bool doRemove) {
+    DomTokenList list = _classListOf(_element);
+    int i = 0;
+    while (i < _classListLength(list)) {
+      String item = list.item(i);
+      if (doRemove == test(item)) {
+        _classListRemove(list, item);
+      } else {
+        ++i;
+      }
+    }
+  }
+
+  // A collection of static methods for DomTokenList. These methods are a
+  // work-around for the lack of annotations to express the full behaviour of
+  // the DomTokenList methods.
+
+  static DomTokenList _classListOf(Element e) => JS(
+      'returns:DomTokenList;creates:DomTokenList;effects:none;depends:all;',
+      '#.classList',
+      e);
+
+  static int _classListLength(DomTokenList list) =>
+      JS('returns:JSUInt31;effects:none;depends:all;', '#.length', list);
+
+  static bool _classListContains(DomTokenList list, String value) =>
+      JS('returns:bool;effects:none;depends:all', '#.contains(#)', list, value);
+
+  static bool _classListContainsBeforeAddOrRemove(
+          DomTokenList list, String value) =>
+      // 'throws:never' is a lie, since 'contains' will throw on an illegal
+      // token.  However, we always call this function immediately prior to
+      // add/remove/toggle with the same token.  Often the result of 'contains'
+      // is unused and the lie makes it possible for the 'contains' instruction
+      // to be removed.
+      JS('returns:bool;effects:none;depends:all;throws:null(1)',
+          '#.contains(#)', list, value);
+
+  static void _classListAdd(DomTokenList list, String value) {
+    // list.add(value);
+    JS('', '#.add(#)', list, value);
+  }
+
+  static void _classListRemove(DomTokenList list, String value) {
+    // list.remove(value);
+    JS('', '#.remove(#)', list, value);
+  }
+
+  static bool _classListToggle1(DomTokenList list, String value) {
+    return JS('bool', '#.toggle(#)', list, value);
+  }
+
+  static bool _classListToggle2(
+      DomTokenList list, String value, bool shouldAdd) {
+    return JS('bool', '#.toggle(#, #)', list, value, shouldAdd);
+  }
+}
+
+/**
+ * Class representing a
+ * [length measurement](https://developer.mozilla.org/en-US/docs/Web/CSS/length)
+ * in CSS.
+ */
+class Dimension {
+  num _value;
+  String _unit;
+
+  /** Set this CSS Dimension to a percentage `value`. */
+  Dimension.percent(this._value) : _unit = '%';
+
+  /** Set this CSS Dimension to a pixel `value`. */
+  Dimension.px(this._value) : _unit = 'px';
+
+  /** Set this CSS Dimension to a pica `value`. */
+  Dimension.pc(this._value) : _unit = 'pc';
+
+  /** Set this CSS Dimension to a point `value`. */
+  Dimension.pt(this._value) : _unit = 'pt';
+
+  /** Set this CSS Dimension to an inch `value`. */
+  Dimension.inch(this._value) : _unit = 'in';
+
+  /** Set this CSS Dimension to a centimeter `value`. */
+  Dimension.cm(this._value) : _unit = 'cm';
+
+  /** Set this CSS Dimension to a millimeter `value`. */
+  Dimension.mm(this._value) : _unit = 'mm';
+
+  /**
+   * Set this CSS Dimension to the specified number of ems.
+   *
+   * 1em is equal to the current font size. (So 2ems is equal to double the font
+   * size). This is useful for producing website layouts that scale nicely with
+   * the user's desired font size.
+   */
+  Dimension.em(this._value) : _unit = 'em';
+
+  /**
+   * Set this CSS Dimension to the specified number of x-heights.
+   *
+   * One ex is equal to the x-height of a font's baseline to its mean line,
+   * generally the height of the letter "x" in the font, which is usually about
+   * half the font-size.
+   */
+  Dimension.ex(this._value) : _unit = 'ex';
+
+  /**
+   * Construct a Dimension object from the valid, simple CSS string `cssValue`
+   * that represents a distance measurement.
+   *
+   * This constructor is intended as a convenience method for working with
+   * simplistic CSS length measurements. Non-numeric values such as `auto` or
+   * `inherit` or invalid CSS will cause this constructor to throw a
+   * FormatError.
+   */
+  Dimension.css(String cssValue) {
+    if (cssValue == '') cssValue = '0px';
+    if (cssValue.endsWith('%')) {
+      _unit = '%';
+    } else {
+      _unit = cssValue.substring(cssValue.length - 2);
+    }
+    if (cssValue.contains('.')) {
+      _value =
+          double.parse(cssValue.substring(0, cssValue.length - _unit.length));
+    } else {
+      _value = int.parse(cssValue.substring(0, cssValue.length - _unit.length));
+    }
+  }
+
+  /** Print out the CSS String representation of this value. */
+  String toString() {
+    return '${_value}${_unit}';
+  }
+
+  /** Return a unitless, numerical value of this CSS value. */
+  num get value => this._value;
+}
+// Copyright (c) 2011, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+typedef EventListener(Event event);
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/**
+ * A factory to expose DOM events as Streams.
+ */
+class EventStreamProvider<T extends Event> {
+  final String _eventType;
+
+  const EventStreamProvider(this._eventType);
+
+  /**
+   * Gets a [Stream] for this event type, on the specified target.
+   *
+   * This will always return a broadcast stream so multiple listeners can be
+   * used simultaneously.
+   *
+   * This may be used to capture DOM events:
+   *
+   *     Element.keyDownEvent.forTarget(element, useCapture: true).listen(...);
+   *
+   *     // Alternate method:
+   *     Element.keyDownEvent.forTarget(element).capture(...);
+   *
+   * Or for listening to an event which will bubble through the DOM tree:
+   *
+   *     MediaElement.pauseEvent.forTarget(document.body).listen(...);
+   *
+   * See also:
+   *
+   * * [EventTarget.addEventListener](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener)
+   *   from MDN.
+   */
+  Stream<T> forTarget(EventTarget e, {bool useCapture: false}) =>
+      new _EventStream<T>(e, _eventType, useCapture);
+
+  /**
+   * Gets an [ElementEventStream] for this event type, on the specified element.
+   *
+   * This will always return a broadcast stream so multiple listeners can be
+   * used simultaneously.
+   *
+   * This may be used to capture DOM events:
+   *
+   *     Element.keyDownEvent.forElement(element, useCapture: true).listen(...);
+   *
+   *     // Alternate method:
+   *     Element.keyDownEvent.forElement(element).capture(...);
+   *
+   * Or for listening to an event which will bubble through the DOM tree:
+   *
+   *     MediaElement.pauseEvent.forElement(document.body).listen(...);
+   *
+   * See also:
+   *
+   * * [EventTarget.addEventListener](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener)
+   *   from MDN.
+   */
+  ElementStream<T> forElement(Element e, {bool useCapture: false}) {
+    return new _ElementEventStreamImpl<T>(e, _eventType, useCapture);
+  }
+
+  /**
+   * Gets an [ElementEventStream] for this event type, on the list of elements.
+   *
+   * This will always return a broadcast stream so multiple listeners can be
+   * used simultaneously.
+   *
+   * This may be used to capture DOM events:
+   *
+   *     Element.keyDownEvent._forElementList(element, useCapture: true).listen(...);
+   *
+   * See also:
+   *
+   * * [EventTarget.addEventListener](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener)
+   *   from MDN.
+   */
+  ElementStream<T> _forElementList(ElementList<Element> e,
+      {bool useCapture: false}) {
+    return new _ElementListEventStreamImpl<T>(e, _eventType, useCapture);
+  }
+
+  /**
+   * Gets the type of the event which this would listen for on the specified
+   * event target.
+   *
+   * The target is necessary because some browsers may use different event names
+   * for the same purpose and the target allows differentiating browser support.
+   */
+  String getEventType(EventTarget target) {
+    return _eventType;
+  }
+}
+
+/** A specialized Stream available to [Element]s to enable event delegation. */
+abstract class ElementStream<T extends Event> implements Stream<T> {
+  /**
+   * Return a stream that only fires when the particular event fires for
+   * elements matching the specified CSS selector.
+   *
+   * This is the Dart equivalent to jQuery's
+   * [delegate](http://api.jquery.com/delegate/).
+   */
+  Stream<T> matches(String selector);
+
+  /**
+   * Adds a capturing subscription to this stream.
+   *
+   * If the target of the event is a descendant of the element from which this
+   * stream derives then [onData] is called before the event propagates down to
+   * the target. This is the opposite of bubbling behavior, where the event
+   * is first processed for the event target and then bubbles upward.
+   *
+   * ## Other resources
+   *
+   * * [Event Capture](http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-flow-capture)
+   *   from the W3C DOM Events specification.
+   */
+  StreamSubscription<T> capture(void onData(T event));
+}
+
+/**
+ * Adapter for exposing DOM events as Dart streams.
+ */
+class _EventStream<T extends Event> extends Stream<T> {
+  final EventTarget _target;
+  final String _eventType;
+  final bool _useCapture;
+
+  _EventStream(this._target, this._eventType, this._useCapture);
+
+  // DOM events are inherently multi-subscribers.
+  Stream<T> asBroadcastStream(
+          {void onListen(StreamSubscription<T> subscription),
+          void onCancel(StreamSubscription<T> subscription)}) =>
+      this;
+  bool get isBroadcast => true;
+
+  // TODO(9757): Inlining should be smart and inline only when inlining would
+  // enable scalar replacement of an immediately allocated receiver.
+  @pragma('dart2js:tryInline')
+  StreamSubscription<T> listen(void onData(T event),
+      {Function onError, void onDone(), bool cancelOnError}) {
+    return new _EventStreamSubscription<T>(
+        this._target, this._eventType, onData, this._useCapture);
+  }
+}
+
+bool _matchesWithAncestors(Event event, String selector) {
+  var target = event.target;
+  return target is Element ? target.matchesWithAncestors(selector) : false;
+}
+
+/**
+ * Adapter for exposing DOM Element events as streams, while also allowing
+ * event delegation.
+ */
+class _ElementEventStreamImpl<T extends Event> extends _EventStream<T>
+    implements ElementStream<T> {
+  _ElementEventStreamImpl(target, eventType, useCapture)
+      : super(target, eventType, useCapture);
+
+  Stream<T> matches(String selector) =>
+      this.where((event) => _matchesWithAncestors(event, selector)).map((e) {
+        e._selector = selector;
+        return e;
+      });
+
+  StreamSubscription<T> capture(void onData(T event)) =>
+      new _EventStreamSubscription<T>(
+          this._target, this._eventType, onData, true);
+}
+
+/**
+ * Adapter for exposing events on a collection of DOM Elements as streams,
+ * while also allowing event delegation.
+ */
+class _ElementListEventStreamImpl<T extends Event> extends Stream<T>
+    implements ElementStream<T> {
+  final Iterable<Element> _targetList;
+  final bool _useCapture;
+  final String _eventType;
+
+  _ElementListEventStreamImpl(
+      this._targetList, this._eventType, this._useCapture);
+
+  Stream<T> matches(String selector) =>
+      this.where((event) => _matchesWithAncestors(event, selector)).map((e) {
+        e._selector = selector;
+        return e;
+      });
+
+  // Delegate all regular Stream behavior to a wrapped Stream.
+  StreamSubscription<T> listen(void onData(T event),
+      {Function onError, void onDone(), bool cancelOnError}) {
+    var pool = new _StreamPool<T>.broadcast();
+    for (var target in _targetList) {
+      pool.add(new _EventStream<T>(target, _eventType, _useCapture));
+    }
+    return pool.stream.listen(onData,
+        onError: onError, onDone: onDone, cancelOnError: cancelOnError);
+  }
+
+  StreamSubscription<T> capture(void onData(T event)) {
+    var pool = new _StreamPool<T>.broadcast();
+    for (var target in _targetList) {
+      pool.add(new _EventStream<T>(target, _eventType, true));
+    }
+    return pool.stream.listen(onData);
+  }
+
+  Stream<T> asBroadcastStream(
+          {void onListen(StreamSubscription<T> subscription),
+          void onCancel(StreamSubscription<T> subscription)}) =>
+      this;
+  bool get isBroadcast => true;
+}
+
+// We would like this to just be EventListener<T> but that typdef cannot
+// use generics until dartbug/26276 is fixed.
+typedef _EventListener<T extends Event>(T event);
+
+class _EventStreamSubscription<T extends Event> extends StreamSubscription<T> {
+  int _pauseCount = 0;
+  EventTarget _target;
+  final String _eventType;
+  EventListener _onData;
+  final bool _useCapture;
+
+  // TODO(leafp): It would be better to write this as
+  // _onData = onData == null ? null :
+  //   onData is void Function(Event)
+  //     ? _wrapZone<Event>(onData)
+  //     : _wrapZone<Event>((e) => onData(e as T))
+  // In order to support existing tests which pass the wrong type of events but
+  // use a more general listener, without causing as much slowdown for things
+  // which are typed correctly.  But this currently runs afoul of restrictions
+  // on is checks for compatibility with the VM.
+  _EventStreamSubscription(
+      this._target, this._eventType, void onData(T event), this._useCapture)
+      : _onData = onData == null
+            ? null
+            : _wrapZone<Event>((e) => (onData as dynamic)(e)) {
+    _tryResume();
+  }
+
+  Future cancel() {
+    if (_canceled) return null;
+
+    _unlisten();
+    // Clear out the target to indicate this is complete.
+    _target = null;
+    _onData = null;
+    return null;
+  }
+
+  bool get _canceled => _target == null;
+
+  void onData(void handleData(T event)) {
+    if (_canceled) {
+      throw new StateError("Subscription has been canceled.");
+    }
+    // Remove current event listener.
+    _unlisten();
+    _onData = _wrapZone<Event>(handleData);
+    _tryResume();
+  }
+
+  /// Has no effect.
+  void onError(Function handleError) {}
+
+  /// Has no effect.
+  void onDone(void handleDone()) {}
+
+  void pause([Future resumeSignal]) {
+    if (_canceled) return;
+    ++_pauseCount;
+    _unlisten();
+
+    if (resumeSignal != null) {
+      resumeSignal.whenComplete(resume);
+    }
+  }
+
+  bool get isPaused => _pauseCount > 0;
+
+  void resume() {
+    if (_canceled || !isPaused) return;
+    --_pauseCount;
+    _tryResume();
+  }
+
+  void _tryResume() {
+    if (_onData != null && !isPaused) {
+      _target.addEventListener(_eventType, _onData, _useCapture);
+    }
+  }
+
+  void _unlisten() {
+    if (_onData != null) {
+      _target.removeEventListener(_eventType, _onData, _useCapture);
+    }
+  }
+
+  Future<E> asFuture<E>([E futureValue]) {
+    // We just need a future that will never succeed or fail.
+    var completer = new Completer<E>();
+    return completer.future;
+  }
+}
+
+/**
+ * A stream of custom events, which enables the user to "fire" (add) their own
+ * custom events to a stream.
+ */
+abstract class CustomStream<T extends Event> implements Stream<T> {
+  /**
+   * Add the following custom event to the stream for dispatching to interested
+   * listeners.
+   */
+  void add(T event);
+}
+
+class _CustomEventStreamImpl<T extends Event> extends Stream<T>
+    implements CustomStream<T> {
+  StreamController<T> _streamController;
+  /** The type of event this stream is providing (e.g. "keydown"). */
+  String _type;
+
+  _CustomEventStreamImpl(String type) {
+    _type = type;
+    _streamController = new StreamController.broadcast(sync: true);
+  }
+
+  // Delegate all regular Stream behavior to our wrapped Stream.
+  StreamSubscription<T> listen(void onData(T event),
+      {Function onError, void onDone(), bool cancelOnError}) {
+    return _streamController.stream.listen(onData,
+        onError: onError, onDone: onDone, cancelOnError: cancelOnError);
+  }
+
+  Stream<T> asBroadcastStream(
+          {void onListen(StreamSubscription<T> subscription),
+          void onCancel(StreamSubscription<T> subscription)}) =>
+      _streamController.stream;
+
+  bool get isBroadcast => true;
+
+  void add(T event) {
+    if (event.type == _type) _streamController.add(event);
+  }
+}
+
+class _CustomKeyEventStreamImpl extends _CustomEventStreamImpl<KeyEvent>
+    implements CustomStream<KeyEvent> {
+  _CustomKeyEventStreamImpl(String type) : super(type);
+
+  void add(KeyEvent event) {
+    if (event.type == _type) {
+      event.currentTarget.dispatchEvent(event._parent);
+      _streamController.add(event);
+    }
+  }
+}
+
+/**
+ * A pool of streams whose events are unified and emitted through a central
+ * stream.
+ */
+// TODO (efortuna): Remove this when Issue 12218 is addressed.
+class _StreamPool<T> {
+  StreamController<T> _controller;
+
+  /// Subscriptions to the streams that make up the pool.
+  var _subscriptions = new Map<Stream<T>, StreamSubscription<T>>();
+
+  /**
+   * Creates a new stream pool where [stream] can be listened to more than
+   * once.
+   *
+   * Any events from buffered streams in the pool will be emitted immediately,
+   * regardless of whether [stream] has any subscribers.
+   */
+  _StreamPool.broadcast() {
+    _controller =
+        new StreamController<T>.broadcast(sync: true, onCancel: close);
+  }
+
+  /**
+   * The stream through which all events from streams in the pool are emitted.
+   */
+  Stream<T> get stream => _controller.stream;
+
+  /**
+   * Adds [stream] as a member of this pool.
+   *
+   * Any events from [stream] will be emitted through [this.stream]. If
+   * [stream] is sync, they'll be emitted synchronously; if [stream] is async,
+   * they'll be emitted asynchronously.
+   */
+  void add(Stream<T> stream) {
+    if (_subscriptions.containsKey(stream)) return;
+    _subscriptions[stream] = stream.listen(_controller.add,
+        onError: _controller.addError, onDone: () => remove(stream));
+  }
+
+  /** Removes [stream] as a member of this pool. */
+  void remove(Stream<T> stream) {
+    var subscription = _subscriptions.remove(stream);
+    if (subscription != null) subscription.cancel();
+  }
+
+  /** Removes all streams from this pool and closes [stream]. */
+  void close() {
+    for (var subscription in _subscriptions.values) {
+      subscription.cancel();
+    }
+    _subscriptions.clear();
+    _controller.close();
+  }
+}
+
+/**
+ * A factory to expose DOM events as streams, where the DOM event name has to
+ * be determined on the fly (for example, mouse wheel events).
+ */
+class _CustomEventStreamProvider<T extends Event>
+    implements EventStreamProvider<T> {
+  final _eventTypeGetter;
+  const _CustomEventStreamProvider(this._eventTypeGetter);
+
+  Stream<T> forTarget(EventTarget e, {bool useCapture: false}) {
+    return new _EventStream<T>(e, _eventTypeGetter(e), useCapture);
+  }
+
+  ElementStream<T> forElement(Element e, {bool useCapture: false}) {
+    return new _ElementEventStreamImpl<T>(e, _eventTypeGetter(e), useCapture);
+  }
+
+  ElementStream<T> _forElementList(ElementList<Element> e,
+      {bool useCapture: false}) {
+    return new _ElementListEventStreamImpl<T>(
+        e, _eventTypeGetter(e), useCapture);
+  }
+
+  String getEventType(EventTarget target) {
+    return _eventTypeGetter(target);
+  }
+
+  String get _eventType =>
+      throw new UnsupportedError('Access type through getEventType method.');
+}
+// DO NOT EDIT- this file is generated from running tool/generator.sh.
+
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/**
+ * A Dart DOM validator generated from Caja whitelists.
+ *
+ * This contains a whitelist of known HTML tagNames and attributes and will only
+ * accept known good values.
+ *
+ * See also:
+ *
+ * * <https://code.google.com/p/google-caja/wiki/CajaWhitelists>
+ */
+class _Html5NodeValidator implements NodeValidator {
+  static final Set<String> _allowedElements = new Set.from([
+    'A',
+    'ABBR',
+    'ACRONYM',
+    'ADDRESS',
+    'AREA',
+    'ARTICLE',
+    'ASIDE',
+    'AUDIO',
+    'B',
+    'BDI',
+    'BDO',
+    'BIG',
+    'BLOCKQUOTE',
+    'BR',
+    'BUTTON',
+    'CANVAS',
+    'CAPTION',
+    'CENTER',
+    'CITE',
+    'CODE',
+    'COL',
+    'COLGROUP',
+    'COMMAND',
+    'DATA',
+    'DATALIST',
+    'DD',
+    'DEL',
+    'DETAILS',
+    'DFN',
+    'DIR',
+    'DIV',
+    'DL',
+    'DT',
+    'EM',
+    'FIELDSET',
+    'FIGCAPTION',
+    'FIGURE',
+    'FONT',
+    'FOOTER',
+    'FORM',
+    'H1',
+    'H2',
+    'H3',
+    'H4',
+    'H5',
+    'H6',
+    'HEADER',
+    'HGROUP',
+    'HR',
+    'I',
+    'IFRAME',
+    'IMG',
+    'INPUT',
+    'INS',
+    'KBD',
+    'LABEL',
+    'LEGEND',
+    'LI',
+    'MAP',
+    'MARK',
+    'MENU',
+    'METER',
+    'NAV',
+    'NOBR',
+    'OL',
+    'OPTGROUP',
+    'OPTION',
+    'OUTPUT',
+    'P',
+    'PRE',
+    'PROGRESS',
+    'Q',
+    'S',
+    'SAMP',
+    'SECTION',
+    'SELECT',
+    'SMALL',
+    'SOURCE',
+    'SPAN',
+    'STRIKE',
+    'STRONG',
+    'SUB',
+    'SUMMARY',
+    'SUP',
+    'TABLE',
+    'TBODY',
+    'TD',
+    'TEXTAREA',
+    'TFOOT',
+    'TH',
+    'THEAD',
+    'TIME',
+    'TR',
+    'TRACK',
+    'TT',
+    'U',
+    'UL',
+    'VAR',
+    'VIDEO',
+    'WBR',
+  ]);
+
+  static const _standardAttributes = const <String>[
+    '*::class',
+    '*::dir',
+    '*::draggable',
+    '*::hidden',
+    '*::id',
+    '*::inert',
+    '*::itemprop',
+    '*::itemref',
+    '*::itemscope',
+    '*::lang',
+    '*::spellcheck',
+    '*::title',
+    '*::translate',
+    'A::accesskey',
+    'A::coords',
+    'A::hreflang',
+    'A::name',
+    'A::shape',
+    'A::tabindex',
+    'A::target',
+    'A::type',
+    'AREA::accesskey',
+    'AREA::alt',
+    'AREA::coords',
+    'AREA::nohref',
+    'AREA::shape',
+    'AREA::tabindex',
+    'AREA::target',
+    'AUDIO::controls',
+    'AUDIO::loop',
+    'AUDIO::mediagroup',
+    'AUDIO::muted',
+    'AUDIO::preload',
+    'BDO::dir',
+    'BODY::alink',
+    'BODY::bgcolor',
+    'BODY::link',
+    'BODY::text',
+    'BODY::vlink',
+    'BR::clear',
+    'BUTTON::accesskey',
+    'BUTTON::disabled',
+    'BUTTON::name',
+    'BUTTON::tabindex',
+    'BUTTON::type',
+    'BUTTON::value',
+    'CANVAS::height',
+    'CANVAS::width',
+    'CAPTION::align',
+    'COL::align',
+    'COL::char',
+    'COL::charoff',
+    'COL::span',
+    'COL::valign',
+    'COL::width',
+    'COLGROUP::align',
+    'COLGROUP::char',
+    'COLGROUP::charoff',
+    'COLGROUP::span',
+    'COLGROUP::valign',
+    'COLGROUP::width',
+    'COMMAND::checked',
+    'COMMAND::command',
+    'COMMAND::disabled',
+    'COMMAND::label',
+    'COMMAND::radiogroup',
+    'COMMAND::type',
+    'DATA::value',
+    'DEL::datetime',
+    'DETAILS::open',
+    'DIR::compact',
+    'DIV::align',
+    'DL::compact',
+    'FIELDSET::disabled',
+    'FONT::color',
+    'FONT::face',
+    'FONT::size',
+    'FORM::accept',
+    'FORM::autocomplete',
+    'FORM::enctype',
+    'FORM::method',
+    'FORM::name',
+    'FORM::novalidate',
+    'FORM::target',
+    'FRAME::name',
+    'H1::align',
+    'H2::align',
+    'H3::align',
+    'H4::align',
+    'H5::align',
+    'H6::align',
+    'HR::align',
+    'HR::noshade',
+    'HR::size',
+    'HR::width',
+    'HTML::version',
+    'IFRAME::align',
+    'IFRAME::frameborder',
+    'IFRAME::height',
+    'IFRAME::marginheight',
+    'IFRAME::marginwidth',
+    'IFRAME::width',
+    'IMG::align',
+    'IMG::alt',
+    'IMG::border',
+    'IMG::height',
+    'IMG::hspace',
+    'IMG::ismap',
+    'IMG::name',
+    'IMG::usemap',
+    'IMG::vspace',
+    'IMG::width',
+    'INPUT::accept',
+    'INPUT::accesskey',
+    'INPUT::align',
+    'INPUT::alt',
+    'INPUT::autocomplete',
+    'INPUT::autofocus',
+    'INPUT::checked',
+    'INPUT::disabled',
+    'INPUT::inputmode',
+    'INPUT::ismap',
+    'INPUT::list',
+    'INPUT::max',
+    'INPUT::maxlength',
+    'INPUT::min',
+    'INPUT::multiple',
+    'INPUT::name',
+    'INPUT::placeholder',
+    'INPUT::readonly',
+    'INPUT::required',
+    'INPUT::size',
+    'INPUT::step',
+    'INPUT::tabindex',
+    'INPUT::type',
+    'INPUT::usemap',
+    'INPUT::value',
+    'INS::datetime',
+    'KEYGEN::disabled',
+    'KEYGEN::keytype',
+    'KEYGEN::name',
+    'LABEL::accesskey',
+    'LABEL::for',
+    'LEGEND::accesskey',
+    'LEGEND::align',
+    'LI::type',
+    'LI::value',
+    'LINK::sizes',
+    'MAP::name',
+    'MENU::compact',
+    'MENU::label',
+    'MENU::type',
+    'METER::high',
+    'METER::low',
+    'METER::max',
+    'METER::min',
+    'METER::value',
+    'OBJECT::typemustmatch',
+    'OL::compact',
+    'OL::reversed',
+    'OL::start',
+    'OL::type',
+    'OPTGROUP::disabled',
+    'OPTGROUP::label',
+    'OPTION::disabled',
+    'OPTION::label',
+    'OPTION::selected',
+    'OPTION::value',
+    'OUTPUT::for',
+    'OUTPUT::name',
+    'P::align',
+    'PRE::width',
+    'PROGRESS::max',
+    'PROGRESS::min',
+    'PROGRESS::value',
+    'SELECT::autocomplete',
+    'SELECT::disabled',
+    'SELECT::multiple',
+    'SELECT::name',
+    'SELECT::required',
+    'SELECT::size',
+    'SELECT::tabindex',
+    'SOURCE::type',
+    'TABLE::align',
+    'TABLE::bgcolor',
+    'TABLE::border',
+    'TABLE::cellpadding',
+    'TABLE::cellspacing',
+    'TABLE::frame',
+    'TABLE::rules',
+    'TABLE::summary',
+    'TABLE::width',
+    'TBODY::align',
+    'TBODY::char',
+    'TBODY::charoff',
+    'TBODY::valign',
+    'TD::abbr',
+    'TD::align',
+    'TD::axis',
+    'TD::bgcolor',
+    'TD::char',
+    'TD::charoff',
+    'TD::colspan',
+    'TD::headers',
+    'TD::height',
+    'TD::nowrap',
+    'TD::rowspan',
+    'TD::scope',
+    'TD::valign',
+    'TD::width',
+    'TEXTAREA::accesskey',
+    'TEXTAREA::autocomplete',
+    'TEXTAREA::cols',
+    'TEXTAREA::disabled',
+    'TEXTAREA::inputmode',
+    'TEXTAREA::name',
+    'TEXTAREA::placeholder',
+    'TEXTAREA::readonly',
+    'TEXTAREA::required',
+    'TEXTAREA::rows',
+    'TEXTAREA::tabindex',
+    'TEXTAREA::wrap',
+    'TFOOT::align',
+    'TFOOT::char',
+    'TFOOT::charoff',
+    'TFOOT::valign',
+    'TH::abbr',
+    'TH::align',
+    'TH::axis',
+    'TH::bgcolor',
+    'TH::char',
+    'TH::charoff',
+    'TH::colspan',
+    'TH::headers',
+    'TH::height',
+    'TH::nowrap',
+    'TH::rowspan',
+    'TH::scope',
+    'TH::valign',
+    'TH::width',
+    'THEAD::align',
+    'THEAD::char',
+    'THEAD::charoff',
+    'THEAD::valign',
+    'TR::align',
+    'TR::bgcolor',
+    'TR::char',
+    'TR::charoff',
+    'TR::valign',
+    'TRACK::default',
+    'TRACK::kind',
+    'TRACK::label',
+    'TRACK::srclang',
+    'UL::compact',
+    'UL::type',
+    'VIDEO::controls',
+    'VIDEO::height',
+    'VIDEO::loop',
+    'VIDEO::mediagroup',
+    'VIDEO::muted',
+    'VIDEO::preload',
+    'VIDEO::width',
+  ];
+
+  static const _uriAttributes = const <String>[
+    'A::href',
+    'AREA::href',
+    'BLOCKQUOTE::cite',
+    'BODY::background',
+    'COMMAND::icon',
+    'DEL::cite',
+    'FORM::action',
+    'IMG::src',
+    'INPUT::src',
+    'INS::cite',
+    'Q::cite',
+    'VIDEO::poster',
+  ];
+
+  final UriPolicy uriPolicy;
+
+  static final Map<String, Function> _attributeValidators = {};
+
+  /**
+   * All known URI attributes will be validated against the UriPolicy, if
+   * [uriPolicy] is null then a default UriPolicy will be used.
+   */
+  _Html5NodeValidator({UriPolicy uriPolicy})
+      : uriPolicy = uriPolicy != null ? uriPolicy : new UriPolicy() {
+    if (_attributeValidators.isEmpty) {
+      for (var attr in _standardAttributes) {
+        _attributeValidators[attr] = _standardAttributeValidator;
+      }
+
+      for (var attr in _uriAttributes) {
+        _attributeValidators[attr] = _uriAttributeValidator;
+      }
+    }
+  }
+
+  bool allowsElement(Element element) {
+    return _allowedElements.contains(Element._safeTagName(element));
+  }
+
+  bool allowsAttribute(Element element, String attributeName, String value) {
+    var tagName = Element._safeTagName(element);
+    var validator = _attributeValidators['$tagName::$attributeName'];
+    if (validator == null) {
+      validator = _attributeValidators['*::$attributeName'];
+    }
+    if (validator == null) {
+      return false;
+    }
+    return validator(element, attributeName, value, this);
+  }
+
+  static bool _standardAttributeValidator(Element element, String attributeName,
+      String value, _Html5NodeValidator context) {
+    return true;
+  }
+
+  static bool _uriAttributeValidator(Element element, String attributeName,
+      String value, _Html5NodeValidator context) {
+    return context.uriPolicy.allowsUri(value);
+  }
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+abstract class ImmutableListMixin<E> implements List<E> {
+  // From Iterable<$E>:
+  Iterator<E> get iterator {
+    // Note: NodeLists are not fixed size. And most probably length shouldn't
+    // be cached in both iterator _and_ forEach method. For now caching it
+    // for consistency.
+    return new FixedSizeListIterator<E>(this);
+  }
+
+  // From List<E>:
+  void add(E value) {
+    throw new UnsupportedError("Cannot add to immutable List.");
+  }
+
+  void addAll(Iterable<E> iterable) {
+    throw new UnsupportedError("Cannot add to immutable List.");
+  }
+
+  void sort([int compare(E a, E b)]) {
+    throw new UnsupportedError("Cannot sort immutable List.");
+  }
+
+  void shuffle([Random random]) {
+    throw new UnsupportedError("Cannot shuffle immutable List.");
+  }
+
+  void insert(int index, E element) {
+    throw new UnsupportedError("Cannot add to immutable List.");
+  }
+
+  void insertAll(int index, Iterable<E> iterable) {
+    throw new UnsupportedError("Cannot add to immutable List.");
+  }
+
+  void setAll(int index, Iterable<E> iterable) {
+    throw new UnsupportedError("Cannot modify an immutable List.");
+  }
+
+  E removeAt(int pos) {
+    throw new UnsupportedError("Cannot remove from immutable List.");
+  }
+
+  E removeLast() {
+    throw new UnsupportedError("Cannot remove from immutable List.");
+  }
+
+  bool remove(Object object) {
+    throw new UnsupportedError("Cannot remove from immutable List.");
+  }
+
+  void removeWhere(bool test(E element)) {
+    throw new UnsupportedError("Cannot remove from immutable List.");
+  }
+
+  void retainWhere(bool test(E element)) {
+    throw new UnsupportedError("Cannot remove from immutable List.");
+  }
+
+  void setRange(int start, int end, Iterable<E> iterable, [int skipCount = 0]) {
+    throw new UnsupportedError("Cannot setRange on immutable List.");
+  }
+
+  void removeRange(int start, int end) {
+    throw new UnsupportedError("Cannot removeRange on immutable List.");
+  }
+
+  void replaceRange(int start, int end, Iterable<E> iterable) {
+    throw new UnsupportedError("Cannot modify an immutable List.");
+  }
+
+  void fillRange(int start, int end, [E fillValue]) {
+    throw new UnsupportedError("Cannot modify an immutable List.");
+  }
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/**
+ * Defines the keycode values for keys that are returned by
+ * KeyboardEvent.keyCode.
+ *
+ * Important note: There is substantial divergence in how different browsers
+ * handle keycodes and their variants in different locales/keyboard layouts. We
+ * provide these constants to help make code processing keys more readable.
+ */
+abstract class KeyCode {
+  // These constant names were borrowed from Closure's Keycode enumeration
+  // class.
+  // https://github.com/google/closure-library/blob/master/closure/goog/events/keycodes.js
+  static const int WIN_KEY_FF_LINUX = 0;
+  static const int MAC_ENTER = 3;
+  static const int BACKSPACE = 8;
+  static const int TAB = 9;
+  /** NUM_CENTER is also NUMLOCK for FF and Safari on Mac. */
+  static const int NUM_CENTER = 12;
+  static const int ENTER = 13;
+  static const int SHIFT = 16;
+  static const int CTRL = 17;
+  static const int ALT = 18;
+  static const int PAUSE = 19;
+  static const int CAPS_LOCK = 20;
+  static const int ESC = 27;
+  static const int SPACE = 32;
+  static const int PAGE_UP = 33;
+  static const int PAGE_DOWN = 34;
+  static const int END = 35;
+  static const int HOME = 36;
+  static const int LEFT = 37;
+  static const int UP = 38;
+  static const int RIGHT = 39;
+  static const int DOWN = 40;
+  static const int NUM_NORTH_EAST = 33;
+  static const int NUM_SOUTH_EAST = 34;
+  static const int NUM_SOUTH_WEST = 35;
+  static const int NUM_NORTH_WEST = 36;
+  static const int NUM_WEST = 37;
+  static const int NUM_NORTH = 38;
+  static const int NUM_EAST = 39;
+  static const int NUM_SOUTH = 40;
+  static const int PRINT_SCREEN = 44;
+  static const int INSERT = 45;
+  static const int NUM_INSERT = 45;
+  static const int DELETE = 46;
+  static const int NUM_DELETE = 46;
+  static const int ZERO = 48;
+  static const int ONE = 49;
+  static const int TWO = 50;
+  static const int THREE = 51;
+  static const int FOUR = 52;
+  static const int FIVE = 53;
+  static const int SIX = 54;
+  static const int SEVEN = 55;
+  static const int EIGHT = 56;
+  static const int NINE = 57;
+  static const int FF_SEMICOLON = 59;
+  static const int FF_EQUALS = 61;
+  /**
+   * CAUTION: The question mark is for US-keyboard layouts. It varies
+   * for other locales and keyboard layouts.
+   */
+  static const int QUESTION_MARK = 63;
+  static const int A = 65;
+  static const int B = 66;
+  static const int C = 67;
+  static const int D = 68;
+  static const int E = 69;
+  static const int F = 70;
+  static const int G = 71;
+  static const int H = 72;
+  static const int I = 73;
+  static const int J = 74;
+  static const int K = 75;
+  static const int L = 76;
+  static const int M = 77;
+  static const int N = 78;
+  static const int O = 79;
+  static const int P = 80;
+  static const int Q = 81;
+  static const int R = 82;
+  static const int S = 83;
+  static const int T = 84;
+  static const int U = 85;
+  static const int V = 86;
+  static const int W = 87;
+  static const int X = 88;
+  static const int Y = 89;
+  static const int Z = 90;
+  static const int META = 91;
+  static const int WIN_KEY_LEFT = 91;
+  static const int WIN_KEY_RIGHT = 92;
+  static const int CONTEXT_MENU = 93;
+  static const int NUM_ZERO = 96;
+  static const int NUM_ONE = 97;
+  static const int NUM_TWO = 98;
+  static const int NUM_THREE = 99;
+  static const int NUM_FOUR = 100;
+  static const int NUM_FIVE = 101;
+  static const int NUM_SIX = 102;
+  static const int NUM_SEVEN = 103;
+  static const int NUM_EIGHT = 104;
+  static const int NUM_NINE = 105;
+  static const int NUM_MULTIPLY = 106;
+  static const int NUM_PLUS = 107;
+  static const int NUM_MINUS = 109;
+  static const int NUM_PERIOD = 110;
+  static const int NUM_DIVISION = 111;
+  static const int F1 = 112;
+  static const int F2 = 113;
+  static const int F3 = 114;
+  static const int F4 = 115;
+  static const int F5 = 116;
+  static const int F6 = 117;
+  static const int F7 = 118;
+  static const int F8 = 119;
+  static const int F9 = 120;
+  static const int F10 = 121;
+  static const int F11 = 122;
+  static const int F12 = 123;
+  static const int NUMLOCK = 144;
+  static const int SCROLL_LOCK = 145;
+
+  // OS-specific media keys like volume controls and browser controls.
+  static const int FIRST_MEDIA_KEY = 166;
+  static const int LAST_MEDIA_KEY = 183;
+
+  /**
+   * CAUTION: This constant requires localization for other locales and keyboard
+   * layouts.
+   */
+  static const int SEMICOLON = 186;
+  /**
+   * CAUTION: This constant requires localization for other locales and keyboard
+   * layouts.
+   */
+  static const int DASH = 189;
+  /**
+   * CAUTION: This constant requires localization for other locales and keyboard
+   * layouts.
+   */
+  static const int EQUALS = 187;
+  /**
+   * CAUTION: This constant requires localization for other locales and keyboard
+   * layouts.
+   */
+  static const int COMMA = 188;
+  /**
+   * CAUTION: This constant requires localization for other locales and keyboard
+   * layouts.
+   */
+  static const int PERIOD = 190;
+  /**
+   * CAUTION: This constant requires localization for other locales and keyboard
+   * layouts.
+   */
+  static const int SLASH = 191;
+  /**
+   * CAUTION: This constant requires localization for other locales and keyboard
+   * layouts.
+   */
+  static const int APOSTROPHE = 192;
+  /**
+   * CAUTION: This constant requires localization for other locales and keyboard
+   * layouts.
+   */
+  static const int TILDE = 192;
+  /**
+   * CAUTION: This constant requires localization for other locales and keyboard
+   * layouts.
+   */
+  static const int SINGLE_QUOTE = 222;
+  /**
+   * CAUTION: This constant requires localization for other locales and keyboard
+   * layouts.
+   */
+  static const int OPEN_SQUARE_BRACKET = 219;
+  /**
+   * CAUTION: This constant requires localization for other locales and keyboard
+   * layouts.
+   */
+  static const int BACKSLASH = 220;
+  /**
+   * CAUTION: This constant requires localization for other locales and keyboard
+   * layouts.
+   */
+  static const int CLOSE_SQUARE_BRACKET = 221;
+  static const int WIN_KEY = 224;
+  static const int MAC_FF_META = 224;
+  static const int WIN_IME = 229;
+
+  /** A sentinel value if the keycode could not be determined. */
+  static const int UNKNOWN = -1;
+
+  /**
+   * Returns true if the keyCode produces a (US keyboard) character.
+   * Note: This does not (yet) cover characters on non-US keyboards (Russian,
+   * Hebrew, etc.).
+   */
+  static bool isCharacterKey(int keyCode) {
+    if ((keyCode >= ZERO && keyCode <= NINE) ||
+        (keyCode >= NUM_ZERO && keyCode <= NUM_MULTIPLY) ||
+        (keyCode >= A && keyCode <= Z)) {
+      return true;
+    }
+
+    // Safari sends zero key code for non-latin characters.
+    if (Device.isWebKit && keyCode == 0) {
+      return true;
+    }
+
+    return (keyCode == SPACE ||
+        keyCode == QUESTION_MARK ||
+        keyCode == NUM_PLUS ||
+        keyCode == NUM_MINUS ||
+        keyCode == NUM_PERIOD ||
+        keyCode == NUM_DIVISION ||
+        keyCode == SEMICOLON ||
+        keyCode == FF_SEMICOLON ||
+        keyCode == DASH ||
+        keyCode == EQUALS ||
+        keyCode == FF_EQUALS ||
+        keyCode == COMMA ||
+        keyCode == PERIOD ||
+        keyCode == SLASH ||
+        keyCode == APOSTROPHE ||
+        keyCode == SINGLE_QUOTE ||
+        keyCode == OPEN_SQUARE_BRACKET ||
+        keyCode == BACKSLASH ||
+        keyCode == CLOSE_SQUARE_BRACKET);
+  }
+
+  /**
+   * Experimental helper function for converting keyCodes to keyNames for the
+   * keyIdentifier attribute still used in browsers not updated with current
+   * spec. This is an imperfect conversion! It will need to be refined, but
+   * hopefully it can just completely go away once all the browsers update to
+   * follow the DOM3 spec.
+   */
+  static String _convertKeyCodeToKeyName(int keyCode) {
+    switch (keyCode) {
+      case KeyCode.ALT:
+        return _KeyName.ALT;
+      case KeyCode.BACKSPACE:
+        return _KeyName.BACKSPACE;
+      case KeyCode.CAPS_LOCK:
+        return _KeyName.CAPS_LOCK;
+      case KeyCode.CTRL:
+        return _KeyName.CONTROL;
+      case KeyCode.DELETE:
+        return _KeyName.DEL;
+      case KeyCode.DOWN:
+        return _KeyName.DOWN;
+      case KeyCode.END:
+        return _KeyName.END;
+      case KeyCode.ENTER:
+        return _KeyName.ENTER;
+      case KeyCode.ESC:
+        return _KeyName.ESC;
+      case KeyCode.F1:
+        return _KeyName.F1;
+      case KeyCode.F2:
+        return _KeyName.F2;
+      case KeyCode.F3:
+        return _KeyName.F3;
+      case KeyCode.F4:
+        return _KeyName.F4;
+      case KeyCode.F5:
+        return _KeyName.F5;
+      case KeyCode.F6:
+        return _KeyName.F6;
+      case KeyCode.F7:
+        return _KeyName.F7;
+      case KeyCode.F8:
+        return _KeyName.F8;
+      case KeyCode.F9:
+        return _KeyName.F9;
+      case KeyCode.F10:
+        return _KeyName.F10;
+      case KeyCode.F11:
+        return _KeyName.F11;
+      case KeyCode.F12:
+        return _KeyName.F12;
+      case KeyCode.HOME:
+        return _KeyName.HOME;
+      case KeyCode.INSERT:
+        return _KeyName.INSERT;
+      case KeyCode.LEFT:
+        return _KeyName.LEFT;
+      case KeyCode.META:
+        return _KeyName.META;
+      case KeyCode.NUMLOCK:
+        return _KeyName.NUM_LOCK;
+      case KeyCode.PAGE_DOWN:
+        return _KeyName.PAGE_DOWN;
+      case KeyCode.PAGE_UP:
+        return _KeyName.PAGE_UP;
+      case KeyCode.PAUSE:
+        return _KeyName.PAUSE;
+      case KeyCode.PRINT_SCREEN:
+        return _KeyName.PRINT_SCREEN;
+      case KeyCode.RIGHT:
+        return _KeyName.RIGHT;
+      case KeyCode.SCROLL_LOCK:
+        return _KeyName.SCROLL;
+      case KeyCode.SHIFT:
+        return _KeyName.SHIFT;
+      case KeyCode.SPACE:
+        return _KeyName.SPACEBAR;
+      case KeyCode.TAB:
+        return _KeyName.TAB;
+      case KeyCode.UP:
+        return _KeyName.UP;
+      case KeyCode.WIN_IME:
+      case KeyCode.WIN_KEY:
+      case KeyCode.WIN_KEY_LEFT:
+      case KeyCode.WIN_KEY_RIGHT:
+        return _KeyName.WIN;
+      default:
+        return _KeyName.UNIDENTIFIED;
+    }
+    return _KeyName.UNIDENTIFIED;
+  }
+}
+// Copyright (c) 2011, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/**
+ * Defines the standard key locations returned by
+ * KeyboardEvent.getKeyLocation.
+ */
+abstract class KeyLocation {
+  /**
+   * The event key is not distinguished as the left or right version
+   * of the key, and did not originate from the numeric keypad (or did not
+   * originate with a virtual key corresponding to the numeric keypad).
+   */
+  static const int STANDARD = 0;
+
+  /**
+   * The event key is in the left key location.
+   */
+  static const int LEFT = 1;
+
+  /**
+   * The event key is in the right key location.
+   */
+  static const int RIGHT = 2;
+
+  /**
+   * The event key originated on the numeric keypad or with a virtual key
+   * corresponding to the numeric keypad.
+   */
+  static const int NUMPAD = 3;
+
+  /**
+   * The event key originated on a mobile device, either on a physical
+   * keypad or a virtual keyboard.
+   */
+  static const int MOBILE = 4;
+
+  /**
+   * The event key originated on a game controller or a joystick on a mobile
+   * device.
+   */
+  static const int JOYSTICK = 5;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/**
+ * Defines the standard keyboard identifier names for keys that are returned
+ * by KeyboardEvent.getKeyboardIdentifier when the key does not have a direct
+ * unicode mapping.
+ */
+abstract class _KeyName {
+  /** The Accept (Commit, OK) key */
+  static const String ACCEPT = "Accept";
+
+  /** The Add key */
+  static const String ADD = "Add";
+
+  /** The Again key */
+  static const String AGAIN = "Again";
+
+  /** The All Candidates key */
+  static const String ALL_CANDIDATES = "AllCandidates";
+
+  /** The Alphanumeric key */
+  static const String ALPHANUMERIC = "Alphanumeric";
+
+  /** The Alt (Menu) key */
+  static const String ALT = "Alt";
+
+  /** The Alt-Graph key */
+  static const String ALT_GRAPH = "AltGraph";
+
+  /** The Application key */
+  static const String APPS = "Apps";
+
+  /** The ATTN key */
+  static const String ATTN = "Attn";
+
+  /** The Browser Back key */
+  static const String BROWSER_BACK = "BrowserBack";
+
+  /** The Browser Favorites key */
+  static const String BROWSER_FAVORTIES = "BrowserFavorites";
+
+  /** The Browser Forward key */
+  static const String BROWSER_FORWARD = "BrowserForward";
+
+  /** The Browser Home key */
+  static const String BROWSER_NAME = "BrowserHome";
+
+  /** The Browser Refresh key */
+  static const String BROWSER_REFRESH = "BrowserRefresh";
+
+  /** The Browser Search key */
+  static const String BROWSER_SEARCH = "BrowserSearch";
+
+  /** The Browser Stop key */
+  static const String BROWSER_STOP = "BrowserStop";
+
+  /** The Camera key */
+  static const String CAMERA = "Camera";
+
+  /** The Caps Lock (Capital) key */
+  static const String CAPS_LOCK = "CapsLock";
+
+  /** The Clear key */
+  static const String CLEAR = "Clear";
+
+  /** The Code Input key */
+  static const String CODE_INPUT = "CodeInput";
+
+  /** The Compose key */
+  static const String COMPOSE = "Compose";
+
+  /** The Control (Ctrl) key */
+  static const String CONTROL = "Control";
+
+  /** The Crsel key */
+  static const String CRSEL = "Crsel";
+
+  /** The Convert key */
+  static const String CONVERT = "Convert";
+
+  /** The Copy key */
+  static const String COPY = "Copy";
+
+  /** The Cut key */
+  static const String CUT = "Cut";
+
+  /** The Decimal key */
+  static const String DECIMAL = "Decimal";
+
+  /** The Divide key */
+  static const String DIVIDE = "Divide";
+
+  /** The Down Arrow key */
+  static const String DOWN = "Down";
+
+  /** The diagonal Down-Left Arrow key */
+  static const String DOWN_LEFT = "DownLeft";
+
+  /** The diagonal Down-Right Arrow key */
+  static const String DOWN_RIGHT = "DownRight";
+
+  /** The Eject key */
+  static const String EJECT = "Eject";
+
+  /** The End key */
+  static const String END = "End";
+
+  /**
+   * The Enter key. Note: This key value must also be used for the Return
+   *  (Macintosh numpad) key
+   */
+  static const String ENTER = "Enter";
+
+  /** The Erase EOF key */
+  static const String ERASE_EOF = "EraseEof";
+
+  /** The Execute key */
+  static const String EXECUTE = "Execute";
+
+  /** The Exsel key */
+  static const String EXSEL = "Exsel";
+
+  /** The Function switch key */
+  static const String FN = "Fn";
+
+  /** The F1 key */
+  static const String F1 = "F1";
+
+  /** The F2 key */
+  static const String F2 = "F2";
+
+  /** The F3 key */
+  static const String F3 = "F3";
+
+  /** The F4 key */
+  static const String F4 = "F4";
+
+  /** The F5 key */
+  static const String F5 = "F5";
+
+  /** The F6 key */
+  static const String F6 = "F6";
+
+  /** The F7 key */
+  static const String F7 = "F7";
+
+  /** The F8 key */
+  static const String F8 = "F8";
+
+  /** The F9 key */
+  static const String F9 = "F9";
+
+  /** The F10 key */
+  static const String F10 = "F10";
+
+  /** The F11 key */
+  static const String F11 = "F11";
+
+  /** The F12 key */
+  static const String F12 = "F12";
+
+  /** The F13 key */
+  static const String F13 = "F13";
+
+  /** The F14 key */
+  static const String F14 = "F14";
+
+  /** The F15 key */
+  static const String F15 = "F15";
+
+  /** The F16 key */
+  static const String F16 = "F16";
+
+  /** The F17 key */
+  static const String F17 = "F17";
+
+  /** The F18 key */
+  static const String F18 = "F18";
+
+  /** The F19 key */
+  static const String F19 = "F19";
+
+  /** The F20 key */
+  static const String F20 = "F20";
+
+  /** The F21 key */
+  static const String F21 = "F21";
+
+  /** The F22 key */
+  static const String F22 = "F22";
+
+  /** The F23 key */
+  static const String F23 = "F23";
+
+  /** The F24 key */
+  static const String F24 = "F24";
+
+  /** The Final Mode (Final) key used on some asian keyboards */
+  static const String FINAL_MODE = "FinalMode";
+
+  /** The Find key */
+  static const String FIND = "Find";
+
+  /** The Full-Width Characters key */
+  static const String FULL_WIDTH = "FullWidth";
+
+  /** The Half-Width Characters key */
+  static const String HALF_WIDTH = "HalfWidth";
+
+  /** The Hangul (Korean characters) Mode key */
+  static const String HANGUL_MODE = "HangulMode";
+
+  /** The Hanja (Korean characters) Mode key */
+  static const String HANJA_MODE = "HanjaMode";
+
+  /** The Help key */
+  static const String HELP = "Help";
+
+  /** The Hiragana (Japanese Kana characters) key */
+  static const String HIRAGANA = "Hiragana";
+
+  /** The Home key */
+  static const String HOME = "Home";
+
+  /** The Insert (Ins) key */
+  static const String INSERT = "Insert";
+
+  /** The Japanese-Hiragana key */
+  static const String JAPANESE_HIRAGANA = "JapaneseHiragana";
+
+  /** The Japanese-Katakana key */
+  static const String JAPANESE_KATAKANA = "JapaneseKatakana";
+
+  /** The Japanese-Romaji key */
+  static const String JAPANESE_ROMAJI = "JapaneseRomaji";
+
+  /** The Junja Mode key */
+  static const String JUNJA_MODE = "JunjaMode";
+
+  /** The Kana Mode (Kana Lock) key */
+  static const String KANA_MODE = "KanaMode";
+
+  /**
+   * The Kanji (Japanese name for ideographic characters of Chinese origin)
+   * Mode key
+   */
+  static const String KANJI_MODE = "KanjiMode";
+
+  /** The Katakana (Japanese Kana characters) key */
+  static const String KATAKANA = "Katakana";
+
+  /** The Start Application One key */
+  static const String LAUNCH_APPLICATION_1 = "LaunchApplication1";
+
+  /** The Start Application Two key */
+  static const String LAUNCH_APPLICATION_2 = "LaunchApplication2";
+
+  /** The Start Mail key */
+  static const String LAUNCH_MAIL = "LaunchMail";
+
+  /** The Left Arrow key */
+  static const String LEFT = "Left";
+
+  /** The Menu key */
+  static const String MENU = "Menu";
+
+  /**
+   * The Meta key. Note: This key value shall be also used for the Apple
+   * Command key
+   */
+  static const String META = "Meta";
+
+  /** The Media Next Track key */
+  static const String MEDIA_NEXT_TRACK = "MediaNextTrack";
+
+  /** The Media Play Pause key */
+  static const String MEDIA_PAUSE_PLAY = "MediaPlayPause";
+
+  /** The Media Previous Track key */
+  static const String MEDIA_PREVIOUS_TRACK = "MediaPreviousTrack";
+
+  /** The Media Stop key */
+  static const String MEDIA_STOP = "MediaStop";
+
+  /** The Mode Change key */
+  static const String MODE_CHANGE = "ModeChange";
+
+  /** The Next Candidate function key */
+  static const String NEXT_CANDIDATE = "NextCandidate";
+
+  /** The Nonconvert (Don't Convert) key */
+  static const String NON_CONVERT = "Nonconvert";
+
+  /** The Number Lock key */
+  static const String NUM_LOCK = "NumLock";
+
+  /** The Page Down (Next) key */
+  static const String PAGE_DOWN = "PageDown";
+
+  /** The Page Up key */
+  static const String PAGE_UP = "PageUp";
+
+  /** The Paste key */
+  static const String PASTE = "Paste";
+
+  /** The Pause key */
+  static const String PAUSE = "Pause";
+
+  /** The Play key */
+  static const String PLAY = "Play";
+
+  /**
+   * The Power key. Note: Some devices may not expose this key to the
+   * operating environment
+   */
+  static const String POWER = "Power";
+
+  /** The Previous Candidate function key */
+  static const String PREVIOUS_CANDIDATE = "PreviousCandidate";
+
+  /** The Print Screen (PrintScrn, SnapShot) key */
+  static const String PRINT_SCREEN = "PrintScreen";
+
+  /** The Process key */
+  static const String PROCESS = "Process";
+
+  /** The Props key */
+  static const String PROPS = "Props";
+
+  /** The Right Arrow key */
+  static const String RIGHT = "Right";
+
+  /** The Roman Characters function key */
+  static const String ROMAN_CHARACTERS = "RomanCharacters";
+
+  /** The Scroll Lock key */
+  static const String SCROLL = "Scroll";
+
+  /** The Select key */
+  static const String SELECT = "Select";
+
+  /** The Select Media key */
+  static const String SELECT_MEDIA = "SelectMedia";
+
+  /** The Separator key */
+  static const String SEPARATOR = "Separator";
+
+  /** The Shift key */
+  static const String SHIFT = "Shift";
+
+  /** The Soft1 key */
+  static const String SOFT_1 = "Soft1";
+
+  /** The Soft2 key */
+  static const String SOFT_2 = "Soft2";
+
+  /** The Soft3 key */
+  static const String SOFT_3 = "Soft3";
+
+  /** The Soft4 key */
+  static const String SOFT_4 = "Soft4";
+
+  /** The Stop key */
+  static const String STOP = "Stop";
+
+  /** The Subtract key */
+  static const String SUBTRACT = "Subtract";
+
+  /** The Symbol Lock key */
+  static const String SYMBOL_LOCK = "SymbolLock";
+
+  /** The Up Arrow key */
+  static const String UP = "Up";
+
+  /** The diagonal Up-Left Arrow key */
+  static const String UP_LEFT = "UpLeft";
+
+  /** The diagonal Up-Right Arrow key */
+  static const String UP_RIGHT = "UpRight";
+
+  /** The Undo key */
+  static const String UNDO = "Undo";
+
+  /** The Volume Down key */
+  static const String VOLUME_DOWN = "VolumeDown";
+
+  /** The Volume Mute key */
+  static const String VOLUMN_MUTE = "VolumeMute";
+
+  /** The Volume Up key */
+  static const String VOLUMN_UP = "VolumeUp";
+
+  /** The Windows Logo key */
+  static const String WIN = "Win";
+
+  /** The Zoom key */
+  static const String ZOOM = "Zoom";
+
+  /**
+   * The Backspace (Back) key. Note: This key value shall be also used for the
+   * key labeled 'delete' MacOS keyboards when not modified by the 'Fn' key
+   */
+  static const String BACKSPACE = "Backspace";
+
+  /** The Horizontal Tabulation (Tab) key */
+  static const String TAB = "Tab";
+
+  /** The Cancel key */
+  static const String CANCEL = "Cancel";
+
+  /** The Escape (Esc) key */
+  static const String ESC = "Esc";
+
+  /** The Space (Spacebar) key:   */
+  static const String SPACEBAR = "Spacebar";
+
+  /**
+   * The Delete (Del) Key. Note: This key value shall be also used for the key
+   * labeled 'delete' MacOS keyboards when modified by the 'Fn' key
+   */
+  static const String DEL = "Del";
+
+  /** The Combining Grave Accent (Greek Varia, Dead Grave) key */
+  static const String DEAD_GRAVE = "DeadGrave";
+
+  /**
+   * The Combining Acute Accent (Stress Mark, Greek Oxia, Tonos, Dead Eacute)
+   * key
+   */
+  static const String DEAD_EACUTE = "DeadEacute";
+
+  /** The Combining Circumflex Accent (Hat, Dead Circumflex) key */
+  static const String DEAD_CIRCUMFLEX = "DeadCircumflex";
+
+  /** The Combining Tilde (Dead Tilde) key */
+  static const String DEAD_TILDE = "DeadTilde";
+
+  /** The Combining Macron (Long, Dead Macron) key */
+  static const String DEAD_MACRON = "DeadMacron";
+
+  /** The Combining Breve (Short, Dead Breve) key */
+  static const String DEAD_BREVE = "DeadBreve";
+
+  /** The Combining Dot Above (Derivative, Dead Above Dot) key */
+  static const String DEAD_ABOVE_DOT = "DeadAboveDot";
+
+  /**
+   * The Combining Diaeresis (Double Dot Abode, Umlaut, Greek Dialytika,
+   * Double Derivative, Dead Diaeresis) key
+   */
+  static const String DEAD_UMLAUT = "DeadUmlaut";
+
+  /** The Combining Ring Above (Dead Above Ring) key */
+  static const String DEAD_ABOVE_RING = "DeadAboveRing";
+
+  /** The Combining Double Acute Accent (Dead Doubleacute) key */
+  static const String DEAD_DOUBLEACUTE = "DeadDoubleacute";
+
+  /** The Combining Caron (Hacek, V Above, Dead Caron) key */
+  static const String DEAD_CARON = "DeadCaron";
+
+  /** The Combining Cedilla (Dead Cedilla) key */
+  static const String DEAD_CEDILLA = "DeadCedilla";
+
+  /** The Combining Ogonek (Nasal Hook, Dead Ogonek) key */
+  static const String DEAD_OGONEK = "DeadOgonek";
+
+  /**
+   * The Combining Greek Ypogegrammeni (Greek Non-Spacing Iota Below, Iota
+   * Subscript, Dead Iota) key
+   */
+  static const String DEAD_IOTA = "DeadIota";
+
+  /**
+   * The Combining Katakana-Hiragana Voiced Sound Mark (Dead Voiced Sound) key
+   */
+  static const String DEAD_VOICED_SOUND = "DeadVoicedSound";
+
+  /**
+   * The Combining Katakana-Hiragana Semi-Voiced Sound Mark (Dead Semivoiced
+   * Sound) key
+   */
+  static const String DEC_SEMIVOICED_SOUND = "DeadSemivoicedSound";
+
+  /**
+   * Key value used when an implementation is unable to identify another key
+   * value, due to either hardware, platform, or software constraints
+   */
+  static const String UNIDENTIFIED = "Unidentified";
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/**
+ * Internal class that does the actual calculations to determine keyCode and
+ * charCode for keydown, keypress, and keyup events for all browsers.
+ */
+class _KeyboardEventHandler extends EventStreamProvider<KeyEvent> {
+  // This code inspired by Closure's KeyHandling library.
+  // https://github.com/google/closure-library/blob/master/closure/goog/events/keyhandler.js
+
+  /**
+   * The set of keys that have been pressed down without seeing their
+   * corresponding keyup event.
+   */
+  final List<KeyEvent> _keyDownList = <KeyEvent>[];
+
+  /** The type of KeyEvent we are tracking (keyup, keydown, keypress). */
+  final String _type;
+
+  /** The element we are watching for events to happen on. */
+  final EventTarget _target;
+
+  // The distance to shift from upper case alphabet Roman letters to lower case.
+  static final int _ROMAN_ALPHABET_OFFSET = "a".codeUnits[0] - "A".codeUnits[0];
+
+  /** Custom Stream (Controller) to produce KeyEvents for the stream. */
+  _CustomKeyEventStreamImpl _stream;
+
+  static const _EVENT_TYPE = 'KeyEvent';
+
+  /**
+   * An enumeration of key identifiers currently part of the W3C draft for DOM3
+   * and their mappings to keyCodes.
+   * https://www.w3.org/TR/2003/NOTE-DOM-Level-3-Events-20031107/keyset.html#KeySet-Set
+   */
+  static const Map<String, int> _keyIdentifier = const {
+    'Up': KeyCode.UP,
+    'Down': KeyCode.DOWN,
+    'Left': KeyCode.LEFT,
+    'Right': KeyCode.RIGHT,
+    'Enter': KeyCode.ENTER,
+    'F1': KeyCode.F1,
+    'F2': KeyCode.F2,
+    'F3': KeyCode.F3,
+    'F4': KeyCode.F4,
+    'F5': KeyCode.F5,
+    'F6': KeyCode.F6,
+    'F7': KeyCode.F7,
+    'F8': KeyCode.F8,
+    'F9': KeyCode.F9,
+    'F10': KeyCode.F10,
+    'F11': KeyCode.F11,
+    'F12': KeyCode.F12,
+    'U+007F': KeyCode.DELETE,
+    'Home': KeyCode.HOME,
+    'End': KeyCode.END,
+    'PageUp': KeyCode.PAGE_UP,
+    'PageDown': KeyCode.PAGE_DOWN,
+    'Insert': KeyCode.INSERT
+  };
+
+  /** Return a stream for KeyEvents for the specified target. */
+  // Note: this actually functions like a factory constructor.
+  CustomStream<KeyEvent> forTarget(EventTarget e, {bool useCapture: false}) {
+    var handler =
+        new _KeyboardEventHandler.initializeAllEventListeners(_type, e);
+    return handler._stream;
+  }
+
+  /**
+   * General constructor, performs basic initialization for our improved
+   * KeyboardEvent controller.
+   */
+  _KeyboardEventHandler(this._type)
+      : _stream = new _CustomKeyEventStreamImpl('event'),
+        _target = null,
+        super(_EVENT_TYPE);
+
+  /**
+   * Hook up all event listeners under the covers so we can estimate keycodes
+   * and charcodes when they are not provided.
+   */
+  _KeyboardEventHandler.initializeAllEventListeners(this._type, this._target)
+      : super(_EVENT_TYPE) {
+    Element.keyDownEvent
+        .forTarget(_target, useCapture: true)
+        .listen(processKeyDown);
+    Element.keyPressEvent
+        .forTarget(_target, useCapture: true)
+        .listen(processKeyPress);
+    Element.keyUpEvent
+        .forTarget(_target, useCapture: true)
+        .listen(processKeyUp);
+    _stream = new _CustomKeyEventStreamImpl(_type);
+  }
+
+  /** Determine if caps lock is one of the currently depressed keys. */
+  bool get _capsLockOn =>
+      _keyDownList.any((var element) => element.keyCode == KeyCode.CAPS_LOCK);
+
+  /**
+   * Given the previously recorded keydown key codes, see if we can determine
+   * the keycode of this keypress [event]. (Generally browsers only provide
+   * charCode information for keypress events, but with a little
+   * reverse-engineering, we can also determine the keyCode.) Returns
+   * KeyCode.UNKNOWN if the keycode could not be determined.
+   */
+  int _determineKeyCodeForKeypress(KeyboardEvent event) {
+    // Note: This function is a work in progress. We'll expand this function
+    // once we get more information about other keyboards.
+    for (var prevEvent in _keyDownList) {
+      if (prevEvent._shadowCharCode == event.charCode) {
+        return prevEvent.keyCode;
+      }
+      if ((event.shiftKey || _capsLockOn) &&
+          event.charCode >= "A".codeUnits[0] &&
+          event.charCode <= "Z".codeUnits[0] &&
+          event.charCode + _ROMAN_ALPHABET_OFFSET ==
+              prevEvent._shadowCharCode) {
+        return prevEvent.keyCode;
+      }
+    }
+    return KeyCode.UNKNOWN;
+  }
+
+  /**
+   * Given the character code returned from a keyDown [event], try to ascertain
+   * and return the corresponding charCode for the character that was pressed.
+   * This information is not shown to the user, but used to help polyfill
+   * keypress events.
+   */
+  int _findCharCodeKeyDown(KeyboardEvent event) {
+    if (event.location == 3) {
+      // Numpad keys.
+      switch (event.keyCode) {
+        case KeyCode.NUM_ZERO:
+          // Even though this function returns _charCodes_, for some cases the
+          // KeyCode == the charCode we want, in which case we use the keycode
+          // constant for readability.
+          return KeyCode.ZERO;
+        case KeyCode.NUM_ONE:
+          return KeyCode.ONE;
+        case KeyCode.NUM_TWO:
+          return KeyCode.TWO;
+        case KeyCode.NUM_THREE:
+          return KeyCode.THREE;
+        case KeyCode.NUM_FOUR:
+          return KeyCode.FOUR;
+        case KeyCode.NUM_FIVE:
+          return KeyCode.FIVE;
+        case KeyCode.NUM_SIX:
+          return KeyCode.SIX;
+        case KeyCode.NUM_SEVEN:
+          return KeyCode.SEVEN;
+        case KeyCode.NUM_EIGHT:
+          return KeyCode.EIGHT;
+        case KeyCode.NUM_NINE:
+          return KeyCode.NINE;
+        case KeyCode.NUM_MULTIPLY:
+          return 42; // Char code for *
+        case KeyCode.NUM_PLUS:
+          return 43; // +
+        case KeyCode.NUM_MINUS:
+          return 45; // -
+        case KeyCode.NUM_PERIOD:
+          return 46; // .
+        case KeyCode.NUM_DIVISION:
+          return 47; // /
+      }
+    } else if (event.keyCode >= 65 && event.keyCode <= 90) {
+      // Set the "char code" for key down as the lower case letter. Again, this
+      // will not show up for the user, but will be helpful in estimating
+      // keyCode locations and other information during the keyPress event.
+      return event.keyCode + _ROMAN_ALPHABET_OFFSET;
+    }
+    switch (event.keyCode) {
+      case KeyCode.SEMICOLON:
+        return KeyCode.FF_SEMICOLON;
+      case KeyCode.EQUALS:
+        return KeyCode.FF_EQUALS;
+      case KeyCode.COMMA:
+        return 44; // Ascii value for ,
+      case KeyCode.DASH:
+        return 45; // -
+      case KeyCode.PERIOD:
+        return 46; // .
+      case KeyCode.SLASH:
+        return 47; // /
+      case KeyCode.APOSTROPHE:
+        return 96; // `
+      case KeyCode.OPEN_SQUARE_BRACKET:
+        return 91; // [
+      case KeyCode.BACKSLASH:
+        return 92; // \
+      case KeyCode.CLOSE_SQUARE_BRACKET:
+        return 93; // ]
+      case KeyCode.SINGLE_QUOTE:
+        return 39; // '
+    }
+    return event.keyCode;
+  }
+
+  /**
+   * Returns true if the key fires a keypress event in the current browser.
+   */
+  bool _firesKeyPressEvent(KeyEvent event) {
+    if (!Device.isIE && !Device.isWebKit) {
+      return true;
+    }
+
+    if (Device.userAgent.contains('Mac') && event.altKey) {
+      return KeyCode.isCharacterKey(event.keyCode);
+    }
+
+    // Alt but not AltGr which is represented as Alt+Ctrl.
+    if (event.altKey && !event.ctrlKey) {
+      return false;
+    }
+
+    // Saves Ctrl or Alt + key for IE and WebKit, which won't fire keypress.
+    if (!event.shiftKey &&
+        (_keyDownList.last.keyCode == KeyCode.CTRL ||
+            _keyDownList.last.keyCode == KeyCode.ALT ||
+            Device.userAgent.contains('Mac') &&
+                _keyDownList.last.keyCode == KeyCode.META)) {
+      return false;
+    }
+
+    // Some keys with Ctrl/Shift do not issue keypress in WebKit.
+    if (Device.isWebKit &&
+        event.ctrlKey &&
+        event.shiftKey &&
+        (event.keyCode == KeyCode.BACKSLASH ||
+            event.keyCode == KeyCode.OPEN_SQUARE_BRACKET ||
+            event.keyCode == KeyCode.CLOSE_SQUARE_BRACKET ||
+            event.keyCode == KeyCode.TILDE ||
+            event.keyCode == KeyCode.SEMICOLON ||
+            event.keyCode == KeyCode.DASH ||
+            event.keyCode == KeyCode.EQUALS ||
+            event.keyCode == KeyCode.COMMA ||
+            event.keyCode == KeyCode.PERIOD ||
+            event.keyCode == KeyCode.SLASH ||
+            event.keyCode == KeyCode.APOSTROPHE ||
+            event.keyCode == KeyCode.SINGLE_QUOTE)) {
+      return false;
+    }
+
+    switch (event.keyCode) {
+      case KeyCode.ENTER:
+        // IE9 does not fire keypress on ENTER.
+        return !Device.isIE;
+      case KeyCode.ESC:
+        return !Device.isWebKit;
+    }
+
+    return KeyCode.isCharacterKey(event.keyCode);
+  }
+
+  /**
+   * Normalize the keycodes to the IE KeyCodes (this is what Chrome, IE, and
+   * Opera all use).
+   */
+  int _normalizeKeyCodes(KeyboardEvent event) {
+    // Note: This may change once we get input about non-US keyboards.
+    if (Device.isFirefox) {
+      switch (event.keyCode) {
+        case KeyCode.FF_EQUALS:
+          return KeyCode.EQUALS;
+        case KeyCode.FF_SEMICOLON:
+          return KeyCode.SEMICOLON;
+        case KeyCode.MAC_FF_META:
+          return KeyCode.META;
+        case KeyCode.WIN_KEY_FF_LINUX:
+          return KeyCode.WIN_KEY;
+      }
+    }
+    return event.keyCode;
+  }
+
+  /** Handle keydown events. */
+  void processKeyDown(KeyboardEvent e) {
+    // Ctrl-Tab and Alt-Tab can cause the focus to be moved to another window
+    // before we've caught a key-up event.  If the last-key was one of these
+    // we reset the state.
+    if (_keyDownList.length > 0 &&
+        (_keyDownList.last.keyCode == KeyCode.CTRL && !e.ctrlKey ||
+            _keyDownList.last.keyCode == KeyCode.ALT && !e.altKey ||
+            Device.userAgent.contains('Mac') &&
+                _keyDownList.last.keyCode == KeyCode.META &&
+                !e.metaKey)) {
+      _keyDownList.clear();
+    }
+
+    var event = new KeyEvent.wrap(e);
+    event._shadowKeyCode = _normalizeKeyCodes(event);
+    // Technically a "keydown" event doesn't have a charCode. This is
+    // calculated nonetheless to provide us with more information in giving
+    // as much information as possible on keypress about keycode and also
+    // charCode.
+    event._shadowCharCode = _findCharCodeKeyDown(event);
+    if (_keyDownList.length > 0 &&
+        event.keyCode != _keyDownList.last.keyCode &&
+        !_firesKeyPressEvent(event)) {
+      // Some browsers have quirks not firing keypress events where all other
+      // browsers do. This makes them more consistent.
+      processKeyPress(e);
+    }
+    _keyDownList.add(event);
+    _stream.add(event);
+  }
+
+  /** Handle keypress events. */
+  void processKeyPress(KeyboardEvent event) {
+    var e = new KeyEvent.wrap(event);
+    // IE reports the character code in the keyCode field for keypress events.
+    // There are two exceptions however, Enter and Escape.
+    if (Device.isIE) {
+      if (e.keyCode == KeyCode.ENTER || e.keyCode == KeyCode.ESC) {
+        e._shadowCharCode = 0;
+      } else {
+        e._shadowCharCode = e.keyCode;
+      }
+    } else if (Device.isOpera) {
+      // Opera reports the character code in the keyCode field.
+      e._shadowCharCode = KeyCode.isCharacterKey(e.keyCode) ? e.keyCode : 0;
+    }
+    // Now we guesstimate about what the keycode is that was actually
+    // pressed, given previous keydown information.
+    e._shadowKeyCode = _determineKeyCodeForKeypress(e);
+
+    // Correct the key value for certain browser-specific quirks.
+    if (e._shadowKeyIdentifier != null &&
+        _keyIdentifier.containsKey(e._shadowKeyIdentifier)) {
+      // This is needed for Safari Windows because it currently doesn't give a
+      // keyCode/which for non printable keys.
+      e._shadowKeyCode = _keyIdentifier[e._shadowKeyIdentifier];
+    }
+    e._shadowAltKey = _keyDownList.any((var element) => element.altKey);
+    _stream.add(e);
+  }
+
+  /** Handle keyup events. */
+  void processKeyUp(KeyboardEvent event) {
+    var e = new KeyEvent.wrap(event);
+    KeyboardEvent toRemove = null;
+    for (var key in _keyDownList) {
+      if (key.keyCode == e.keyCode) {
+        toRemove = key;
+      }
+    }
+    if (toRemove != null) {
+      _keyDownList.removeWhere((element) => element == toRemove);
+    } else if (_keyDownList.length > 0) {
+      // This happens when we've reached some international keyboard case we
+      // haven't accounted for or we haven't correctly eliminated all browser
+      // inconsistencies. Filing bugs on when this is reached is welcome!
+      _keyDownList.removeLast();
+    }
+    _stream.add(e);
+  }
+}
+
+/**
+ * Records KeyboardEvents that occur on a particular element, and provides a
+ * stream of outgoing KeyEvents with cross-browser consistent keyCode and
+ * charCode values despite the fact that a multitude of browsers that have
+ * varying keyboard default behavior.
+ *
+ * Example usage:
+ *
+ *     KeyboardEventStream.onKeyDown(document.body).listen(
+ *         keydownHandlerTest);
+ *
+ * This class is very much a work in progress, and we'd love to get information
+ * on how we can make this class work with as many international keyboards as
+ * possible. Bugs welcome!
+ */
+class KeyboardEventStream {
+  /** Named constructor to produce a stream for onKeyPress events. */
+  static CustomStream<KeyEvent> onKeyPress(EventTarget target) =>
+      new _KeyboardEventHandler('keypress').forTarget(target);
+
+  /** Named constructor to produce a stream for onKeyUp events. */
+  static CustomStream<KeyEvent> onKeyUp(EventTarget target) =>
+      new _KeyboardEventHandler('keyup').forTarget(target);
+
+  /** Named constructor to produce a stream for onKeyDown events. */
+  static CustomStream<KeyEvent> onKeyDown(EventTarget target) =>
+      new _KeyboardEventHandler('keydown').forTarget(target);
+}
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/**
+ * Class which helps construct standard node validation policies.
+ *
+ * By default this will not accept anything, but the 'allow*' functions can be
+ * used to expand what types of elements or attributes are allowed.
+ *
+ * All allow functions are additive- elements will be accepted if they are
+ * accepted by any specific rule.
+ *
+ * It is important to remember that sanitization is not just intended to prevent
+ * cross-site scripting attacks, but also to prevent information from being
+ * displayed in unexpected ways. For example something displaying basic
+ * formatted text may not expect `<video>` tags to appear. In this case an
+ * empty NodeValidatorBuilder with just [allowTextElements] might be
+ * appropriate.
+ */
+class NodeValidatorBuilder implements NodeValidator {
+  final List<NodeValidator> _validators = <NodeValidator>[];
+
+  NodeValidatorBuilder() {}
+
+  /**
+   * Creates a new NodeValidatorBuilder which accepts common constructs.
+   *
+   * By default this will accept HTML5 elements and attributes with the default
+   * [UriPolicy] and templating elements.
+   *
+   * Notable syntax which is filtered:
+   *
+   * * Only known-good HTML5 elements and attributes are allowed.
+   * * All URLs must be same-origin, use [allowNavigation] and [allowImages] to
+   * specify additional URI policies.
+   * * Inline-styles are not allowed.
+   * * Custom element tags are disallowed, use [allowCustomElement].
+   * * Custom tags extensions are disallowed, use [allowTagExtension].
+   * * SVG Elements are not allowed, use [allowSvg].
+   *
+   * For scenarios where the HTML should only contain formatted text
+   * [allowTextElements] is more appropriate.
+   *
+   * Use [allowSvg] to allow SVG elements.
+   */
+  NodeValidatorBuilder.common() {
+    allowHtml5();
+    allowTemplating();
+  }
+
+  /**
+   * Allows navigation elements- Form and Anchor tags, along with common
+   * attributes.
+   *
+   * The UriPolicy can be used to restrict the locations the navigation elements
+   * are allowed to direct to. By default this will use the default [UriPolicy].
+   */
+  void allowNavigation([UriPolicy uriPolicy]) {
+    if (uriPolicy == null) {
+      uriPolicy = new UriPolicy();
+    }
+    add(new _SimpleNodeValidator.allowNavigation(uriPolicy));
+  }
+
+  /**
+   * Allows image elements.
+   *
+   * The UriPolicy can be used to restrict the locations the images may be
+   * loaded from. By default this will use the default [UriPolicy].
+   */
+  void allowImages([UriPolicy uriPolicy]) {
+    if (uriPolicy == null) {
+      uriPolicy = new UriPolicy();
+    }
+    add(new _SimpleNodeValidator.allowImages(uriPolicy));
+  }
+
+  /**
+   * Allow basic text elements.
+   *
+   * This allows a subset of HTML5 elements, specifically just these tags and
+   * no attributes.
+   *
+   * * B
+   * * BLOCKQUOTE
+   * * BR
+   * * EM
+   * * H1
+   * * H2
+   * * H3
+   * * H4
+   * * H5
+   * * H6
+   * * HR
+   * * I
+   * * LI
+   * * OL
+   * * P
+   * * SPAN
+   * * UL
+   */
+  void allowTextElements() {
+    add(new _SimpleNodeValidator.allowTextElements());
+  }
+
+  /**
+   * Allow inline styles on elements.
+   *
+   * If [tagName] is not specified then this allows inline styles on all
+   * elements. Otherwise tagName limits the styles to the specified elements.
+   */
+  void allowInlineStyles({String tagName}) {
+    if (tagName == null) {
+      tagName = '*';
+    } else {
+      tagName = tagName.toUpperCase();
+    }
+    add(new _SimpleNodeValidator(null, allowedAttributes: ['$tagName::style']));
+  }
+
+  /**
+   * Allow common safe HTML5 elements and attributes.
+   *
+   * This list is based off of the Caja whitelists at:
+   * https://code.google.com/p/google-caja/wiki/CajaWhitelists.
+   *
+   * Common things which are not allowed are script elements, style attributes
+   * and any script handlers.
+   */
+  void allowHtml5({UriPolicy uriPolicy}) {
+    add(new _Html5NodeValidator(uriPolicy: uriPolicy));
+  }
+
+  /**
+   * Allow SVG elements and attributes except for known bad ones.
+   */
+  void allowSvg() {
+    add(new _SvgNodeValidator());
+  }
+
+  /**
+   * Allow custom elements with the specified tag name and specified attributes.
+   *
+   * This will allow the elements as custom tags (such as <x-foo></x-foo>),
+   * but will not allow tag extensions. Use [allowTagExtension] to allow
+   * tag extensions.
+   */
+  void allowCustomElement(String tagName,
+      {UriPolicy uriPolicy,
+      Iterable<String> attributes,
+      Iterable<String> uriAttributes}) {
+    var tagNameUpper = tagName.toUpperCase();
+    var attrs = attributes
+        ?.map<String>((name) => '$tagNameUpper::${name.toLowerCase()}');
+    var uriAttrs = uriAttributes
+        ?.map<String>((name) => '$tagNameUpper::${name.toLowerCase()}');
+    if (uriPolicy == null) {
+      uriPolicy = new UriPolicy();
+    }
+
+    add(new _CustomElementNodeValidator(
+        uriPolicy, [tagNameUpper], attrs, uriAttrs, false, true));
+  }
+
+  /**
+   * Allow custom tag extensions with the specified type name and specified
+   * attributes.
+   *
+   * This will allow tag extensions (such as <div is="x-foo"></div>),
+   * but will not allow custom tags. Use [allowCustomElement] to allow
+   * custom tags.
+   */
+  void allowTagExtension(String tagName, String baseName,
+      {UriPolicy uriPolicy,
+      Iterable<String> attributes,
+      Iterable<String> uriAttributes}) {
+    var baseNameUpper = baseName.toUpperCase();
+    var tagNameUpper = tagName.toUpperCase();
+    var attrs = attributes
+        ?.map<String>((name) => '$baseNameUpper::${name.toLowerCase()}');
+    var uriAttrs = uriAttributes
+        ?.map<String>((name) => '$baseNameUpper::${name.toLowerCase()}');
+    if (uriPolicy == null) {
+      uriPolicy = new UriPolicy();
+    }
+
+    add(new _CustomElementNodeValidator(uriPolicy,
+        [tagNameUpper, baseNameUpper], attrs, uriAttrs, true, false));
+  }
+
+  void allowElement(String tagName,
+      {UriPolicy uriPolicy,
+      Iterable<String> attributes,
+      Iterable<String> uriAttributes}) {
+    allowCustomElement(tagName,
+        uriPolicy: uriPolicy,
+        attributes: attributes,
+        uriAttributes: uriAttributes);
+  }
+
+  /**
+   * Allow templating elements (such as <template> and template-related
+   * attributes.
+   *
+   * This still requires other validators to allow regular attributes to be
+   * bound (such as [allowHtml5]).
+   */
+  void allowTemplating() {
+    add(new _TemplatingNodeValidator());
+  }
+
+  /**
+   * Add an additional validator to the current list of validators.
+   *
+   * Elements and attributes will be accepted if they are accepted by any
+   * validators.
+   */
+  void add(NodeValidator validator) {
+    _validators.add(validator);
+  }
+
+  bool allowsElement(Element element) {
+    return _validators.any((v) => v.allowsElement(element));
+  }
+
+  bool allowsAttribute(Element element, String attributeName, String value) {
+    return _validators
+        .any((v) => v.allowsAttribute(element, attributeName, value));
+  }
+}
+
+class _SimpleNodeValidator implements NodeValidator {
+  final Set<String> allowedElements = new Set<String>();
+  final Set<String> allowedAttributes = new Set<String>();
+  final Set<String> allowedUriAttributes = new Set<String>();
+  final UriPolicy uriPolicy;
+
+  factory _SimpleNodeValidator.allowNavigation(UriPolicy uriPolicy) {
+    return new _SimpleNodeValidator(uriPolicy, allowedElements: const [
+      'A',
+      'FORM'
+    ], allowedAttributes: const [
+      'A::accesskey',
+      'A::coords',
+      'A::hreflang',
+      'A::name',
+      'A::shape',
+      'A::tabindex',
+      'A::target',
+      'A::type',
+      'FORM::accept',
+      'FORM::autocomplete',
+      'FORM::enctype',
+      'FORM::method',
+      'FORM::name',
+      'FORM::novalidate',
+      'FORM::target',
+    ], allowedUriAttributes: const [
+      'A::href',
+      'FORM::action',
+    ]);
+  }
+
+  factory _SimpleNodeValidator.allowImages(UriPolicy uriPolicy) {
+    return new _SimpleNodeValidator(uriPolicy, allowedElements: const [
+      'IMG'
+    ], allowedAttributes: const [
+      'IMG::align',
+      'IMG::alt',
+      'IMG::border',
+      'IMG::height',
+      'IMG::hspace',
+      'IMG::ismap',
+      'IMG::name',
+      'IMG::usemap',
+      'IMG::vspace',
+      'IMG::width',
+    ], allowedUriAttributes: const [
+      'IMG::src',
+    ]);
+  }
+
+  factory _SimpleNodeValidator.allowTextElements() {
+    return new _SimpleNodeValidator(null, allowedElements: const [
+      'B',
+      'BLOCKQUOTE',
+      'BR',
+      'EM',
+      'H1',
+      'H2',
+      'H3',
+      'H4',
+      'H5',
+      'H6',
+      'HR',
+      'I',
+      'LI',
+      'OL',
+      'P',
+      'SPAN',
+      'UL',
+    ]);
+  }
+
+  /**
+   * Elements must be uppercased tag names. For example `'IMG'`.
+   * Attributes must be uppercased tag name followed by :: followed by
+   * lowercase attribute name. For example `'IMG:src'`.
+   */
+  _SimpleNodeValidator(this.uriPolicy,
+      {Iterable<String> allowedElements,
+      Iterable<String> allowedAttributes,
+      Iterable<String> allowedUriAttributes}) {
+    this.allowedElements.addAll(allowedElements ?? const []);
+    allowedAttributes = allowedAttributes ?? const [];
+    allowedUriAttributes = allowedUriAttributes ?? const [];
+    var legalAttributes = allowedAttributes
+        .where((x) => !_Html5NodeValidator._uriAttributes.contains(x));
+    var extraUriAttributes = allowedAttributes
+        .where((x) => _Html5NodeValidator._uriAttributes.contains(x));
+    this.allowedAttributes.addAll(legalAttributes);
+    this.allowedUriAttributes.addAll(allowedUriAttributes);
+    this.allowedUriAttributes.addAll(extraUriAttributes);
+  }
+
+  bool allowsElement(Element element) {
+    return allowedElements.contains(Element._safeTagName(element));
+  }
+
+  bool allowsAttribute(Element element, String attributeName, String value) {
+    var tagName = Element._safeTagName(element);
+    if (allowedUriAttributes.contains('$tagName::$attributeName')) {
+      return uriPolicy.allowsUri(value);
+    } else if (allowedUriAttributes.contains('*::$attributeName')) {
+      return uriPolicy.allowsUri(value);
+    } else if (allowedAttributes.contains('$tagName::$attributeName')) {
+      return true;
+    } else if (allowedAttributes.contains('*::$attributeName')) {
+      return true;
+    } else if (allowedAttributes.contains('$tagName::*')) {
+      return true;
+    } else if (allowedAttributes.contains('*::*')) {
+      return true;
+    }
+    return false;
+  }
+}
+
+class _CustomElementNodeValidator extends _SimpleNodeValidator {
+  final bool allowTypeExtension;
+  final bool allowCustomTag;
+
+  _CustomElementNodeValidator(
+      UriPolicy uriPolicy,
+      Iterable<String> allowedElements,
+      Iterable<String> allowedAttributes,
+      Iterable<String> allowedUriAttributes,
+      bool allowTypeExtension,
+      bool allowCustomTag)
+      : this.allowTypeExtension = allowTypeExtension == true,
+        this.allowCustomTag = allowCustomTag == true,
+        super(uriPolicy,
+            allowedElements: allowedElements,
+            allowedAttributes: allowedAttributes,
+            allowedUriAttributes: allowedUriAttributes);
+
+  bool allowsElement(Element element) {
+    if (allowTypeExtension) {
+      var isAttr = element.attributes['is'];
+      if (isAttr != null) {
+        return allowedElements.contains(isAttr.toUpperCase()) &&
+            allowedElements.contains(Element._safeTagName(element));
+      }
+    }
+    return allowCustomTag &&
+        allowedElements.contains(Element._safeTagName(element));
+  }
+
+  bool allowsAttribute(Element element, String attributeName, String value) {
+    if (allowsElement(element)) {
+      if (allowTypeExtension &&
+          attributeName == 'is' &&
+          allowedElements.contains(value.toUpperCase())) {
+        return true;
+      }
+      return super.allowsAttribute(element, attributeName, value);
+    }
+    return false;
+  }
+}
+
+class _TemplatingNodeValidator extends _SimpleNodeValidator {
+  static const _TEMPLATE_ATTRS = const <String>[
+    'bind',
+    'if',
+    'ref',
+    'repeat',
+    'syntax'
+  ];
+
+  final Set<String> _templateAttrs;
+
+  _TemplatingNodeValidator()
+      : _templateAttrs = new Set<String>.from(_TEMPLATE_ATTRS),
+        super(null,
+            allowedElements: ['TEMPLATE'],
+            allowedAttributes:
+                _TEMPLATE_ATTRS.map((attr) => 'TEMPLATE::$attr')) {}
+
+  bool allowsAttribute(Element element, String attributeName, String value) {
+    if (super.allowsAttribute(element, attributeName, value)) {
+      return true;
+    }
+
+    if (attributeName == 'template' && value == "") {
+      return true;
+    }
+
+    if (element.attributes['template'] == "") {
+      return _templateAttrs.contains(attributeName);
+    }
+    return false;
+  }
+}
+
+class _SvgNodeValidator implements NodeValidator {
+  bool allowsElement(Element element) {
+    if (element is svg.ScriptElement) {
+      return false;
+    }
+    // Firefox 37 has issues with creating foreign elements inside a
+    // foreignobject tag as SvgElement. We don't want foreignobject contents
+    // anyway, so just remove the whole tree outright. And we can't rely
+    // on IE recognizing the SvgForeignObject type, so go by tagName. Bug 23144
+    if (element is svg.SvgElement &&
+        Element._safeTagName(element) == 'foreignObject') {
+      return false;
+    }
+    if (element is svg.SvgElement) {
+      return true;
+    }
+    return false;
+  }
+
+  bool allowsAttribute(Element element, String attributeName, String value) {
+    if (attributeName == 'is' || attributeName.startsWith('on')) {
+      return false;
+    }
+    return allowsElement(element);
+  }
+}
+// Copyright (c) 2011, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/**
+ * Contains the set of standard values returned by HTMLDocument.getReadyState.
+ */
+abstract class ReadyState {
+  /**
+   * Indicates the document is still loading and parsing.
+   */
+  static const String LOADING = "loading";
+
+  /**
+   * Indicates the document is finished parsing but is still loading
+   * subresources.
+   */
+  static const String INTERACTIVE = "interactive";
+
+  /**
+   * Indicates the document and all subresources have been loaded.
+   */
+  static const String COMPLETE = "complete";
+}
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/**
+ * A list which just wraps another list, for either intercepting list calls or
+ * retyping the list (for example, from List<A> to List<B> where B extends A).
+ */
+class _WrappedList<E extends Node> extends ListBase<E>
+    implements NodeListWrapper {
+  final List<Node> _list;
+
+  _WrappedList(this._list);
+
+  // Iterable APIs
+
+  Iterator<E> get iterator => new _WrappedIterator<E>(_list.iterator);
+
+  int get length => _list.length;
+
+  // Collection APIs
+
+  void add(E element) {
+    _list.add(element);
+  }
+
+  bool remove(Object element) => _list.remove(element);
+
+  void clear() {
+    _list.clear();
+  }
+
+  // List APIs
+
+  E operator [](int index) => _list[index];
+
+  void operator []=(int index, E value) {
+    _list[index] = value;
+  }
+
+  set length(int newLength) {
+    _list.length = newLength;
+  }
+
+  void sort([int compare(E a, E b)]) {
+    // Implicit downcast on argument from Node to E-extends-Node.
+    _list.sort((Node a, Node b) => compare(a, b));
+  }
+
+  int indexOf(Object element, [int start = 0]) => _list.indexOf(element, start);
+
+  int lastIndexOf(Object element, [int start]) =>
+      _list.lastIndexOf(element, start);
+
+  void insert(int index, E element) => _list.insert(index, element);
+
+  E removeAt(int index) => _list.removeAt(index);
+
+  void setRange(int start, int end, Iterable<E> iterable, [int skipCount = 0]) {
+    _list.setRange(start, end, iterable, skipCount);
+  }
+
+  void removeRange(int start, int end) {
+    _list.removeRange(start, end);
+  }
+
+  void replaceRange(int start, int end, Iterable<E> iterable) {
+    _list.replaceRange(start, end, iterable);
+  }
+
+  void fillRange(int start, int end, [E fillValue]) {
+    _list.fillRange(start, end, fillValue);
+  }
+
+  List<Node> get rawList => _list;
+}
+
+/**
+ * Iterator wrapper for _WrappedList.
+ */
+class _WrappedIterator<E extends Node> implements Iterator<E> {
+  Iterator<Node> _iterator;
+
+  _WrappedIterator(this._iterator);
+
+  bool moveNext() {
+    return _iterator.moveNext();
+  }
+
+  E get current => _iterator.current;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+class _HttpRequestUtils {
+  // Helper for factory HttpRequest.get
+  static HttpRequest get(
+      String url, onComplete(HttpRequest request), bool withCredentials) {
+    final request = new HttpRequest();
+    request.open('GET', url, async: true);
+
+    request.withCredentials = withCredentials;
+
+    request.onReadyStateChange.listen((e) {
+      if (request.readyState == HttpRequest.DONE) {
+        onComplete(request);
+      }
+    });
+
+    request.send();
+
+    return request;
+  }
+}
+// Copyright (c) 2011, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Iterator for arrays with fixed size.
+class FixedSizeListIterator<T> implements Iterator<T> {
+  final List<T> _array;
+  final int _length; // Cache array length for faster access.
+  int _position;
+  T _current;
+
+  FixedSizeListIterator(List<T> array)
+      : _array = array,
+        _position = -1,
+        _length = array.length;
+
+  bool moveNext() {
+    int nextPosition = _position + 1;
+    if (nextPosition < _length) {
+      _current = _array[nextPosition];
+      _position = nextPosition;
+      return true;
+    }
+    _current = null;
+    _position = _length;
+    return false;
+  }
+
+  T get current => _current;
+}
+
+// Iterator for arrays with variable size.
+class _VariableSizeListIterator<T> implements Iterator<T> {
+  final List<T> _array;
+  int _position;
+  T _current;
+
+  _VariableSizeListIterator(List<T> array)
+      : _array = array,
+        _position = -1;
+
+  bool moveNext() {
+    int nextPosition = _position + 1;
+    if (nextPosition < _array.length) {
+      _current = _array[nextPosition];
+      _position = nextPosition;
+      return true;
+    }
+    _current = null;
+    _position = _array.length;
+    return false;
+  }
+
+  T get current => _current;
+}
+// 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.
+
+class Console {
+  const Console._safe();
+  static const Console _safeConsole = const Console._safe();
+
+  bool get _isConsoleDefined => JS('bool', 'typeof console != "undefined"');
+
+  MemoryInfo get memory =>
+      _isConsoleDefined ? JS('MemoryInfo', 'window.console.memory') : null;
+
+  void assertCondition(bool condition, Object arg) => _isConsoleDefined
+      ? JS('void', 'window.console.assertCondition(#, #)', condition, arg)
+      : null;
+
+  void clear(Object arg) =>
+      _isConsoleDefined ? JS('void', 'window.console.clear(#)', arg) : null;
+
+  void count(Object arg) =>
+      _isConsoleDefined ? JS('void', 'window.console.count(#)', arg) : null;
+
+  void debug(Object arg) =>
+      _isConsoleDefined ? JS('void', 'window.console.debug(#)', arg) : null;
+
+  void dir(Object arg) =>
+      _isConsoleDefined ? JS('void', 'window.console.dir(#)', arg) : null;
+
+  void dirxml(Object arg) =>
+      _isConsoleDefined ? JS('void', 'window.console.dirxml(#)', arg) : null;
+
+  void error(Object arg) =>
+      _isConsoleDefined ? JS('void', 'window.console.error(#)', arg) : null;
+
+  void group(Object arg) =>
+      _isConsoleDefined ? JS('void', 'window.console.group(#)', arg) : null;
+
+  void groupCollapsed(Object arg) => _isConsoleDefined
+      ? JS('void', 'window.console.groupCollapsed(#)', arg)
+      : null;
+
+  void groupEnd() =>
+      _isConsoleDefined ? JS('void', 'window.console.groupEnd()') : null;
+
+  void info(Object arg) =>
+      _isConsoleDefined ? JS('void', 'window.console.info(#)', arg) : null;
+
+  void log(Object arg) =>
+      _isConsoleDefined ? JS('void', 'window.console.log(#)', arg) : null;
+
+  void markTimeline(Object arg) => _isConsoleDefined
+      ? JS('void', 'window.console.markTimeline(#)', arg)
+      : null;
+
+  void profile(String title) =>
+      _isConsoleDefined ? JS('void', 'window.console.profile(#)', title) : null;
+
+  void profileEnd(String title) => _isConsoleDefined
+      ? JS('void', 'window.console.profileEnd(#)', title)
+      : null;
+
+  void table(Object arg) =>
+      _isConsoleDefined ? JS('void', 'window.console.table(#)', arg) : null;
+
+  void time(String title) =>
+      _isConsoleDefined ? JS('void', 'window.console.time(#)', title) : null;
+
+  void timeEnd(String title) =>
+      _isConsoleDefined ? JS('void', 'window.console.timeEnd(#)', title) : null;
+
+  void timeStamp(Object arg) =>
+      _isConsoleDefined ? JS('void', 'window.console.timeStamp(#)', arg) : null;
+
+  void trace(Object arg) =>
+      _isConsoleDefined ? JS('void', 'window.console.trace(#)', arg) : null;
+
+  void warn(Object arg) =>
+      _isConsoleDefined ? JS('void', 'window.console.warn(#)', arg) : null;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Conversions for Window.  These check if the window is the local
+// window, and if it's not, wraps or unwraps it with a secure wrapper.
+// We need to test for EventTarget here as well as it's a base type.
+// We omit an unwrapper for Window as no methods take a non-local
+// window as a parameter.
+
+WindowBase _convertNativeToDart_Window(win) {
+  if (win == null) return null;
+  return _DOMWindowCrossFrame._createSafe(win);
+}
+
+EventTarget _convertNativeToDart_EventTarget(e) {
+  if (e == null) {
+    return null;
+  }
+  // Assume it's a Window if it contains the postMessage property.  It may be
+  // from a different frame - without a patched prototype - so we cannot
+  // rely on Dart type checking.
+  if (JS('bool', r'"postMessage" in #', e)) {
+    var window = _DOMWindowCrossFrame._createSafe(e);
+    // If it's a native window.
+    if (window is EventTarget) {
+      return window;
+    }
+    return null;
+  } else
+    return e;
+}
+
+EventTarget _convertDartToNative_EventTarget(e) {
+  if (e is _DOMWindowCrossFrame) {
+    return e._window;
+  } else {
+    return e;
+  }
+}
+
+_convertNativeToDart_XHR_Response(o) {
+  if (o is Document) {
+    return o;
+  }
+  return convertNativeToDart_SerializedScriptValue(o);
+}
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+_callConstructor(constructor, interceptor) {
+  return (receiver) {
+    setNativeSubclassDispatchRecord(receiver, interceptor);
+
+    // Mirrors uses the constructor property to cache lookups, so we need it to
+    // be set correctly, including on IE where it is not automatically picked
+    // up from the __proto__.
+    JS('', '#.constructor = #.__proto__.constructor', receiver, receiver);
+    return JS('', '#(#)', constructor, receiver);
+  };
+}
+
+_callAttached(receiver) {
+  return receiver.attached();
+}
+
+_callDetached(receiver) {
+  return receiver.detached();
+}
+
+_callAttributeChanged(receiver, name, oldValue, newValue) {
+  return receiver.attributeChanged(name, oldValue, newValue);
+}
+
+_makeCallbackMethod(callback) {
+  return JS(
+      '',
+      '''((function(invokeCallback) {
+             return function() {
+               return invokeCallback(this);
+             };
+          })(#))''',
+      convertDartClosureToJS(callback, 1));
+}
+
+_makeCallbackMethod3(callback) {
+  return JS(
+      '',
+      '''((function(invokeCallback) {
+             return function(arg1, arg2, arg3) {
+               return invokeCallback(this, arg1, arg2, arg3);
+             };
+          })(#))''',
+      convertDartClosureToJS(callback, 4));
+}
+
+/// Checks whether the given [element] correctly extends from the native class
+/// with the given [baseClassName]. This method will throw if the base class
+/// doesn't match, except when the element extends from `template` and it's base
+/// class is `HTMLUnknownElement`. This exclusion is needed to support extension
+/// of template elements (used heavily in Polymer 1.0) on IE11 when using the
+/// webcomponents-lite.js polyfill.
+void _checkExtendsNativeClassOrTemplate(
+    Element element, String extendsTag, String baseClassName) {
+  if (!JS('bool', '(# instanceof window[#])', element, baseClassName) &&
+      !((extendsTag == 'template' &&
+          JS('bool', '(# instanceof window["HTMLUnknownElement"])',
+              element)))) {
+    throw new UnsupportedError('extendsTag does not match base native class');
+  }
+}
+
+Function _registerCustomElement(context, document, String tag, [Map options]) {
+  // Function follows the same pattern as the following JavaScript code for
+  // registering a custom element.
+  //
+  //    var proto = Object.create(HTMLElement.prototype, {
+  //        createdCallback: {
+  //          value: function() {
+  //            window.console.log('here');
+  //          }
+  //        }
+  //    });
+  //    document.registerElement('x-foo', { prototype: proto });
+  //    ...
+  //    var e = document.createElement('x-foo');
+
+  var extendsTagName = '';
+  Type type;
+  if (options != null) {
+    extendsTagName = options['extends'];
+    type = options['prototype'];
+  }
+
+  var interceptorClass = findInterceptorConstructorForType(type);
+  if (interceptorClass == null) {
+    throw new ArgumentError(type);
+  }
+
+  var interceptor = JS('=Object', '#.prototype', interceptorClass);
+
+  var constructor = findConstructorForNativeSubclassType(type, 'created');
+  if (constructor == null) {
+    throw new ArgumentError("$type has no constructor called 'created'");
+  }
+
+  // Workaround for 13190- use an article element to ensure that HTMLElement's
+  // interceptor is resolved correctly.
+  getNativeInterceptor(new Element.tag('article'));
+
+  String baseClassName = findDispatchTagForInterceptorClass(interceptorClass);
+  if (baseClassName == null) {
+    throw new ArgumentError(type);
+  }
+
+  if (extendsTagName == null) {
+    if (baseClassName != 'HTMLElement') {
+      throw new UnsupportedError('Class must provide extendsTag if base '
+          'native class is not HtmlElement');
+    }
+  } else {
+    var element = document.createElement(extendsTagName);
+    _checkExtendsNativeClassOrTemplate(element, extendsTagName, baseClassName);
+  }
+
+  var baseConstructor = JS('=Object', '#[#]', context, baseClassName);
+
+  var properties = JS('=Object', '{}');
+
+  JS(
+      'void',
+      '#.createdCallback = #',
+      properties,
+      JS('=Object', '{value: #}',
+          _makeCallbackMethod(_callConstructor(constructor, interceptor))));
+  JS('void', '#.attachedCallback = #', properties,
+      JS('=Object', '{value: #}', _makeCallbackMethod(_callAttached)));
+  JS('void', '#.detachedCallback = #', properties,
+      JS('=Object', '{value: #}', _makeCallbackMethod(_callDetached)));
+  JS('void', '#.attributeChangedCallback = #', properties,
+      JS('=Object', '{value: #}', _makeCallbackMethod3(_callAttributeChanged)));
+
+  var baseProto = JS('=Object', '#.prototype', baseConstructor);
+  var proto = JS('=Object', 'Object.create(#, #)', baseProto, properties);
+
+  setNativeSubclassDispatchRecord(proto, interceptor);
+
+  var opts = JS('=Object', '{prototype: #}', proto);
+
+  if (extendsTagName != null) {
+    JS('=Object', '#.extends = #', opts, extendsTagName);
+  }
+
+  return JS(
+      'JavaScriptFunction', '#.registerElement(#, #)', document, tag, opts);
+}
+
+//// Called by Element.created to do validation & initialization.
+void _initializeCustomElement(Element e) {
+  // TODO(blois): Add validation that this is only in response to an upgrade.
+}
+
+/// Dart2JS implementation of ElementUpgrader
+class _JSElementUpgrader implements ElementUpgrader {
+  var _interceptor;
+  var _constructor;
+  var _nativeType;
+
+  _JSElementUpgrader(Document document, Type type, String extendsTag) {
+    var interceptorClass = findInterceptorConstructorForType(type);
+    if (interceptorClass == null) {
+      throw new ArgumentError(type);
+    }
+
+    _constructor = findConstructorForNativeSubclassType(type, 'created');
+    if (_constructor == null) {
+      throw new ArgumentError("$type has no constructor called 'created'");
+    }
+
+    // Workaround for 13190- use an article element to ensure that HTMLElement's
+    // interceptor is resolved correctly.
+    getNativeInterceptor(new Element.tag('article'));
+
+    var baseClassName = findDispatchTagForInterceptorClass(interceptorClass);
+    if (baseClassName == null) {
+      throw new ArgumentError(type);
+    }
+
+    if (extendsTag == null) {
+      if (baseClassName != 'HTMLElement') {
+        throw new UnsupportedError('Class must provide extendsTag if base '
+            'native class is not HtmlElement');
+      }
+      _nativeType = HtmlElement;
+    } else {
+      var element = document.createElement(extendsTag);
+      _checkExtendsNativeClassOrTemplate(element, extendsTag, baseClassName);
+      _nativeType = element.runtimeType;
+    }
+
+    _interceptor = JS('=Object', '#.prototype', interceptorClass);
+  }
+
+  Element upgrade(Element element) {
+    // Only exact type matches are supported- cannot be a subclass.
+    if (element.runtimeType != _nativeType) {
+      // Some browsers may represent non-upgraded elements <x-foo> as
+      // UnknownElement and not a plain HtmlElement.
+      if (_nativeType != HtmlElement || element.runtimeType != UnknownElement) {
+        throw new ArgumentError('element is not subclass of $_nativeType');
+      }
+    }
+
+    setNativeSubclassDispatchRecord(element, _interceptor);
+    JS('', '#(#)', _constructor, element);
+    return element;
+  }
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// TODO(vsm): Unify with Dartium version.
+class _DOMWindowCrossFrame implements WindowBase {
+  // Private window.  Note, this is a window in another frame, so it
+  // cannot be typed as "Window" as its prototype is not patched
+  // properly.  Its fields and methods can only be accessed via JavaScript.
+  final _window;
+
+  // Fields.
+  HistoryBase get history =>
+      _HistoryCrossFrame._createSafe(JS('HistoryBase', '#.history', _window));
+  LocationBase get location => _LocationCrossFrame._createSafe(
+      JS('LocationBase', '#.location', _window));
+
+  // TODO(vsm): Add frames to navigate subframes.  See 2312.
+
+  bool get closed => JS('bool', '#.closed', _window);
+
+  WindowBase get opener => _createSafe(JS('WindowBase', '#.opener', _window));
+
+  WindowBase get parent => _createSafe(JS('WindowBase', '#.parent', _window));
+
+  WindowBase get top => _createSafe(JS('WindowBase', '#.top', _window));
+
+  // Methods.
+  void close() => JS('void', '#.close()', _window);
+
+  void postMessage(var message, String targetOrigin,
+      [List messagePorts = null]) {
+    if (messagePorts == null) {
+      JS('void', '#.postMessage(#,#)', _window,
+          convertDartToNative_SerializedScriptValue(message), targetOrigin);
+    } else {
+      JS(
+          'void',
+          '#.postMessage(#,#,#)',
+          _window,
+          convertDartToNative_SerializedScriptValue(message),
+          targetOrigin,
+          messagePorts);
+    }
+  }
+
+  // Implementation support.
+  _DOMWindowCrossFrame(this._window);
+
+  static WindowBase _createSafe(w) {
+    if (identical(w, window)) {
+      return w;
+    } else {
+      // TODO(vsm): Cache or implement equality.
+      registerGlobalObject(w);
+      return new _DOMWindowCrossFrame(w);
+    }
+  }
+
+  // TODO(efortuna): Remove this method. dartbug.com/16814
+  Events get on => throw new UnsupportedError(
+      'You can only attach EventListeners to your own window.');
+  // TODO(efortuna): Remove this method. dartbug.com/16814
+  void _addEventListener(String type, EventListener listener,
+          [bool useCapture]) =>
+      throw new UnsupportedError(
+          'You can only attach EventListeners to your own window.');
+  // TODO(efortuna): Remove this method. dartbug.com/16814
+  void addEventListener(String type, EventListener listener,
+          [bool useCapture]) =>
+      throw new UnsupportedError(
+          'You can only attach EventListeners to your own window.');
+  // TODO(efortuna): Remove this method. dartbug.com/16814
+  bool dispatchEvent(Event event) => throw new UnsupportedError(
+      'You can only attach EventListeners to your own window.');
+  // TODO(efortuna): Remove this method. dartbug.com/16814
+  void _removeEventListener(String type, EventListener listener,
+          [bool useCapture]) =>
+      throw new UnsupportedError(
+          'You can only attach EventListeners to your own window.');
+  // TODO(efortuna): Remove this method. dartbug.com/16814
+  void removeEventListener(String type, EventListener listener,
+          [bool useCapture]) =>
+      throw new UnsupportedError(
+          'You can only attach EventListeners to your own window.');
+}
+
+class _LocationCrossFrame implements LocationBase {
+  // Private location.  Note, this is a location object in another frame, so it
+  // cannot be typed as "Location" as its prototype is not patched
+  // properly.  Its fields and methods can only be accessed via JavaScript.
+  var _location;
+
+  set href(String val) => _setHref(_location, val);
+  static void _setHref(location, val) {
+    JS('void', '#.href = #', location, val);
+  }
+
+  // Implementation support.
+  _LocationCrossFrame(this._location);
+
+  static LocationBase _createSafe(location) {
+    if (identical(location, window.location)) {
+      return location;
+    } else {
+      // TODO(vsm): Cache or implement equality.
+      return new _LocationCrossFrame(location);
+    }
+  }
+}
+
+class _HistoryCrossFrame implements HistoryBase {
+  // Private history.  Note, this is a history object in another frame, so it
+  // cannot be typed as "History" as its prototype is not patched
+  // properly.  Its fields and methods can only be accessed via JavaScript.
+  var _history;
+
+  void back() => JS('void', '#.back()', _history);
+
+  void forward() => JS('void', '#.forward()', _history);
+
+  void go(int distance) => JS('void', '#.go(#)', _history, distance);
+
+  // Implementation support.
+  _HistoryCrossFrame(this._history);
+
+  static HistoryBase _createSafe(h) {
+    if (identical(h, window.history)) {
+      return h;
+    } else {
+      // TODO(vsm): Cache or implement equality.
+      return new _HistoryCrossFrame(h);
+    }
+  }
+}
+
+/**
+ * A custom KeyboardEvent that attempts to eliminate cross-browser
+ * inconsistencies, and also provide both keyCode and charCode information
+ * for all key events (when such information can be determined).
+ *
+ * KeyEvent tries to provide a higher level, more polished keyboard event
+ * information on top of the "raw" [KeyboardEvent].
+ *
+ * The mechanics of using KeyEvents is a little different from the underlying
+ * [KeyboardEvent]. To use KeyEvents, you need to create a stream and then add
+ * KeyEvents to the stream, rather than using the [EventTarget.dispatchEvent].
+ * Here's an example usage:
+ *
+ *     // Initialize a stream for the KeyEvents:
+ *     var stream = KeyEvent.keyPressEvent.forTarget(document.body);
+ *     // Start listening to the stream of KeyEvents.
+ *     stream.listen((keyEvent) =>
+ *         window.console.log('KeyPress event detected ${keyEvent.charCode}'));
+ *     ...
+ *     // Add a new KeyEvent of someone pressing the 'A' key to the stream so
+ *     // listeners can know a KeyEvent happened.
+ *     stream.add(new KeyEvent('keypress', keyCode: 65, charCode: 97));
+ *
+ * This class is very much a work in progress, and we'd love to get information
+ * on how we can make this class work with as many international keyboards as
+ * possible. Bugs welcome!
+ */
+class KeyEvent extends _WrappedEvent implements KeyboardEvent {
+  /** The parent KeyboardEvent that this KeyEvent is wrapping and "fixing". */
+  KeyboardEvent _parent;
+
+  /** The "fixed" value of whether the alt key is being pressed. */
+  bool _shadowAltKey;
+
+  /** Calculated value of what the estimated charCode is for this event. */
+  int _shadowCharCode;
+
+  /** Calculated value of what the estimated keyCode is for this event. */
+  int _shadowKeyCode;
+
+  /** Calculated value of what the estimated keyCode is for this event. */
+  int get keyCode => _shadowKeyCode;
+
+  /** Calculated value of what the estimated charCode is for this event. */
+  int get charCode => this.type == 'keypress' ? _shadowCharCode : 0;
+
+  /** Calculated value of whether the alt key is pressed is for this event. */
+  bool get altKey => _shadowAltKey;
+
+  /** Calculated value of what the estimated keyCode is for this event. */
+  int get which => keyCode;
+
+  /** Accessor to the underlying keyCode value is the parent event. */
+  int get _realKeyCode => JS('int', '#.keyCode', _parent);
+
+  /** Accessor to the underlying charCode value is the parent event. */
+  int get _realCharCode => JS('int', '#.charCode', _parent);
+
+  /** Accessor to the underlying altKey value is the parent event. */
+  bool get _realAltKey => JS('bool', '#.altKey', _parent);
+
+  /** Shadows on top of the parent's currentTarget. */
+  EventTarget _currentTarget;
+
+  final InputDeviceCapabilities sourceCapabilities;
+
+  /**
+   * The value we want to use for this object's dispatch. Created here so it is
+   * only invoked once.
+   */
+  static final _keyboardEventDispatchRecord = _makeRecord();
+
+  /** Helper to statically create the dispatch record. */
+  static _makeRecord() {
+    var interceptor = JS_INTERCEPTOR_CONSTANT(KeyboardEvent);
+    return makeLeafDispatchRecord(interceptor);
+  }
+
+  /** Construct a KeyEvent with [parent] as the event we're emulating. */
+  KeyEvent.wrap(KeyboardEvent parent) : super(parent) {
+    _parent = parent;
+    _shadowAltKey = _realAltKey;
+    _shadowCharCode = _realCharCode;
+    _shadowKeyCode = _realKeyCode;
+    _currentTarget = _parent.currentTarget;
+  }
+
+  /** Programmatically create a new KeyEvent (and KeyboardEvent). */
+  factory KeyEvent(String type,
+      {Window view,
+      bool canBubble: true,
+      bool cancelable: true,
+      int keyCode: 0,
+      int charCode: 0,
+      int location: 1,
+      bool ctrlKey: false,
+      bool altKey: false,
+      bool shiftKey: false,
+      bool metaKey: false,
+      EventTarget currentTarget}) {
+    if (view == null) {
+      view = window;
+    }
+
+    var eventObj;
+
+    // Currently this works on everything but Safari. Safari throws an
+    // "Attempting to change access mechanism for an unconfigurable property"
+    // TypeError when trying to do the Object.defineProperty hack, so we avoid
+    // this branch if possible.
+    // Also, if we want this branch to work in FF, we also need to modify
+    // _initKeyboardEvent to also take charCode and keyCode values to
+    // initialize initKeyEvent.
+
+    eventObj = new Event.eventType('KeyboardEvent', type,
+        canBubble: canBubble, cancelable: cancelable);
+
+    // Chromium Hack
+    JS(
+        'void',
+        "Object.defineProperty(#, 'keyCode', {"
+            "  get : function() { return this.keyCodeVal; } })",
+        eventObj);
+    JS(
+        'void',
+        "Object.defineProperty(#, 'which', {"
+            "  get : function() { return this.keyCodeVal; } })",
+        eventObj);
+    JS(
+        'void',
+        "Object.defineProperty(#, 'charCode', {"
+            "  get : function() { return this.charCodeVal; } })",
+        eventObj);
+
+    var keyIdentifier = _convertToHexString(charCode, keyCode);
+    eventObj._initKeyboardEvent(type, canBubble, cancelable, view,
+        keyIdentifier, location, ctrlKey, altKey, shiftKey, metaKey);
+    JS('void', '#.keyCodeVal = #', eventObj, keyCode);
+    JS('void', '#.charCodeVal = #', eventObj, charCode);
+
+    // Tell dart2js that it smells like a KeyboardEvent!
+    setDispatchProperty(eventObj, _keyboardEventDispatchRecord);
+
+    var keyEvent = new KeyEvent.wrap(eventObj);
+    if (keyEvent._currentTarget == null) {
+      keyEvent._currentTarget = currentTarget == null ? window : currentTarget;
+    }
+    return keyEvent;
+  }
+
+  // Currently known to work on all browsers but IE.
+  static bool get canUseDispatchEvent => JS(
+      'bool',
+      '(typeof document.body.dispatchEvent == "function")'
+          '&& document.body.dispatchEvent.length > 0');
+
+  /** The currently registered target for this event. */
+  EventTarget get currentTarget => _currentTarget;
+
+  // This is an experimental method to be sure.
+  static String _convertToHexString(int charCode, int keyCode) {
+    if (charCode != -1) {
+      var hex = charCode.toRadixString(16); // Convert to hexadecimal.
+      StringBuffer sb = new StringBuffer('U+');
+      for (int i = 0; i < 4 - hex.length; i++) sb.write('0');
+      sb.write(hex);
+      return sb.toString();
+    } else {
+      return KeyCode._convertKeyCodeToKeyName(keyCode);
+    }
+  }
+
+  // TODO(efortuna): If KeyEvent is sufficiently successful that we want to make
+  // it the default keyboard event handling, move these methods over to Element.
+  /** Accessor to provide a stream of KeyEvents on the desired target. */
+  static EventStreamProvider<KeyEvent> keyDownEvent =
+      new _KeyboardEventHandler('keydown');
+  /** Accessor to provide a stream of KeyEvents on the desired target. */
+  static EventStreamProvider<KeyEvent> keyUpEvent =
+      new _KeyboardEventHandler('keyup');
+  /** Accessor to provide a stream of KeyEvents on the desired target. */
+  static EventStreamProvider<KeyEvent> keyPressEvent =
+      new _KeyboardEventHandler('keypress');
+
+  String get code => _parent.code;
+  /** True if the ctrl key is pressed during this event. */
+  bool get ctrlKey => _parent.ctrlKey;
+  int get detail => _parent.detail;
+  bool get isComposing => _parent.isComposing;
+  String get key => _parent.key;
+  /**
+   * Accessor to the part of the keyboard that the key was pressed from (one of
+   * KeyLocation.STANDARD, KeyLocation.RIGHT, KeyLocation.LEFT,
+   * KeyLocation.NUMPAD, KeyLocation.MOBILE, KeyLocation.JOYSTICK).
+   */
+  int get location => _parent.location;
+  /** True if the Meta (or Mac command) key is pressed during this event. */
+  bool get metaKey => _parent.metaKey;
+  /** True if the shift key was pressed during this event. */
+  bool get shiftKey => _parent.shiftKey;
+  Window get view => _parent.view;
+  void _initUIEvent(
+      String type, bool canBubble, bool cancelable, Window view, int detail) {
+    throw new UnsupportedError("Cannot initialize a UI Event from a KeyEvent.");
+  }
+
+  String get _shadowKeyIdentifier => JS('String', '#.keyIdentifier', _parent);
+
+  int get _charCode => charCode;
+  int get _keyCode => keyCode;
+  int get _which => which;
+
+  String get _keyIdentifier {
+    throw new UnsupportedError("keyIdentifier is unsupported.");
+  }
+
+  void _initKeyboardEvent(
+      String type,
+      bool canBubble,
+      bool cancelable,
+      Window view,
+      String keyIdentifier,
+      int location,
+      bool ctrlKey,
+      bool altKey,
+      bool shiftKey,
+      bool metaKey) {
+    throw new UnsupportedError(
+        "Cannot initialize a KeyboardEvent from a KeyEvent.");
+  }
+
+  bool getModifierState(String keyArgument) => throw new UnimplementedError();
+
+  bool get repeat => throw new UnimplementedError();
+  bool get isComposed => throw new UnimplementedError();
+  dynamic get _get_view => throw new UnimplementedError();
+}
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+class Platform {
+  /**
+   * Returns true if dart:typed_data types are supported on this
+   * browser.  If false, using these types will generate a runtime
+   * error.
+   */
+  static final supportsTypedData = JS('bool', '!!(window.ArrayBuffer)');
+
+  /**
+   * Returns true if SIMD types in dart:typed_data types are supported
+   * on this browser.  If false, using these types will generate a runtime
+   * error.
+   */
+  static final supportsSimd = false;
+}
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/**
+ * Helper class to implement custom events which wrap DOM events.
+ */
+class _WrappedEvent implements Event {
+  final Event wrapped;
+
+  /** The CSS selector involved with event delegation. */
+  String _selector;
+
+  _WrappedEvent(this.wrapped);
+
+  bool get bubbles => wrapped.bubbles;
+
+  bool get cancelable => wrapped.cancelable;
+
+  bool get composed => wrapped.composed;
+
+  EventTarget get currentTarget => wrapped.currentTarget;
+
+  bool get defaultPrevented => wrapped.defaultPrevented;
+
+  int get eventPhase => wrapped.eventPhase;
+
+  bool get isTrusted => wrapped.isTrusted;
+
+  EventTarget get target => wrapped.target;
+
+  double get timeStamp => wrapped.timeStamp;
+
+  String get type => wrapped.type;
+
+  void _initEvent(String type, [bool bubbles, bool cancelable]) {
+    throw new UnsupportedError('Cannot initialize this Event.');
+  }
+
+  void preventDefault() {
+    wrapped.preventDefault();
+  }
+
+  void stopImmediatePropagation() {
+    wrapped.stopImmediatePropagation();
+  }
+
+  void stopPropagation() {
+    wrapped.stopPropagation();
+  }
+
+  List<EventTarget> composedPath() => wrapped.composedPath();
+
+  /**
+   * A pointer to the element whose CSS selector matched within which an event
+   * was fired. If this Event was not associated with any Event delegation,
+   * accessing this value will throw an [UnsupportedError].
+   */
+  Element get matchingTarget {
+    if (_selector == null) {
+      throw new UnsupportedError('Cannot call matchingTarget if this Event did'
+          ' not arise as a result of event delegation.');
+    }
+    Element currentTarget = this.currentTarget;
+    Element target = this.target;
+    var matchedTarget;
+    do {
+      if (target.matches(_selector)) return target;
+      target = target.parent;
+    } while (target != null && target != currentTarget.parent);
+    throw new StateError('No selector matched for populating matchedTarget.');
+  }
+
+  /**
+   * This event's path, taking into account shadow DOM.
+   *
+   * ## Other resources
+   *
+   * * [Shadow DOM extensions to
+   *   Event](http://w3c.github.io/webcomponents/spec/shadow/#extensions-to-event)
+   *   from W3C.
+   */
+  // https://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/shadow/index.html#extensions-to-event
+  List<Node> get path => wrapped.path;
+
+  dynamic get _get_currentTarget => wrapped._get_currentTarget;
+
+  dynamic get _get_target => wrapped._get_target;
+}
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+void Function(T) _wrapZone<T>(void Function(T) callback) {
+  // For performance reasons avoid wrapping if we are in the root zone.
+  if (Zone.current == Zone.root) return callback;
+  if (callback == null) return null;
+  return Zone.current.bindUnaryCallbackGuarded(callback);
+}
+
+void Function(T1, T2) _wrapBinaryZone<T1, T2>(void Function(T1, T2) callback) {
+  // For performance reasons avoid wrapping if we are in the root zone.
+  if (Zone.current == Zone.root) return callback;
+  if (callback == null) return null;
+  return Zone.current.bindBinaryCallbackGuarded(callback);
+}
+
+/**
+ * Finds the first descendant element of this document that matches the
+ * specified group of selectors.
+ *
+ * Unless your webpage contains multiple documents, the top-level
+ * [querySelector]
+ * method behaves the same as this method, so you should use it instead to
+ * save typing a few characters.
+ *
+ * [selectors] should be a string using CSS selector syntax.
+ *
+ *     var element1 = document.querySelector('.className');
+ *     var element2 = document.querySelector('#id');
+ *
+ * For details about CSS selector syntax, see the
+ * [CSS selector specification](http://www.w3.org/TR/css3-selectors/).
+ */
+Element querySelector(String selectors) => document.querySelector(selectors);
+
+/**
+ * Finds all descendant elements of this document that match the specified
+ * group of selectors.
+ *
+ * Unless your webpage contains multiple documents, the top-level
+ * [querySelectorAll]
+ * method behaves the same as this method, so you should use it instead to
+ * save typing a few characters.
+ *
+ * [selectors] should be a string using CSS selector syntax.
+ *
+ *     var items = document.querySelectorAll('.itemClassName');
+ *
+ * For details about CSS selector syntax, see the
+ * [CSS selector specification](http://www.w3.org/TR/css3-selectors/).
+ */
+ElementList<T> querySelectorAll<T extends Element>(String selectors) =>
+    document.querySelectorAll(selectors);
+
+/// A utility for changing the Dart wrapper type for elements.
+abstract class ElementUpgrader {
+  /// Upgrade the specified element to be of the Dart type this was created for.
+  ///
+  /// After upgrading the element passed in is invalid and the returned value
+  /// should be used instead.
+  Element upgrade(Element element);
+}
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/**
+ * Interface used to validate that only accepted elements and attributes are
+ * allowed while parsing HTML strings into DOM nodes.
+ *
+ * In general, customization of validation behavior should be done via the
+ * [NodeValidatorBuilder] class to mitigate the chances of incorrectly
+ * implementing validation rules.
+ */
+abstract class NodeValidator {
+  /**
+   * Construct a default NodeValidator which only accepts whitelisted HTML5
+   * elements and attributes.
+   *
+   * If a uriPolicy is not specified then the default uriPolicy will be used.
+   */
+  factory NodeValidator({UriPolicy uriPolicy}) =>
+      new _Html5NodeValidator(uriPolicy: uriPolicy);
+
+  factory NodeValidator.throws(NodeValidator base) =>
+      new _ThrowsNodeValidator(base);
+
+  /**
+   * Returns true if the tagName is an accepted type.
+   */
+  bool allowsElement(Element element);
+
+  /**
+   * Returns true if the attribute is allowed.
+   *
+   * The attributeName parameter will always be in lowercase.
+   *
+   * See [allowsElement] for format of tagName.
+   */
+  bool allowsAttribute(Element element, String attributeName, String value);
+}
+
+/**
+ * Performs sanitization of a node tree after construction to ensure that it
+ * does not contain any disallowed elements or attributes.
+ *
+ * In general custom implementations of this class should not be necessary and
+ * all validation customization should be done in custom NodeValidators, but
+ * custom implementations of this class can be created to perform more complex
+ * tree sanitization.
+ */
+abstract class NodeTreeSanitizer {
+  /**
+   * Constructs a default tree sanitizer which will remove all elements and
+   * attributes which are not allowed by the provided validator.
+   */
+  factory NodeTreeSanitizer(NodeValidator validator) =>
+      new _ValidatingTreeSanitizer(validator);
+
+  /**
+   * Called with the root of the tree which is to be sanitized.
+   *
+   * This method needs to walk the entire tree and either remove elements and
+   * attributes which are not recognized as safe or throw an exception which
+   * will mark the entire tree as unsafe.
+   */
+  void sanitizeTree(Node node);
+
+  /**
+   * A sanitizer for trees that we trust. It does no validation and allows
+   * any elements. It is also more efficient, since it can pass the text
+   * directly through to the underlying APIs without creating a document
+   * fragment to be sanitized.
+   */
+  static const trusted = const _TrustedHtmlTreeSanitizer();
+}
+
+/**
+ * A sanitizer for trees that we trust. It does no validation and allows
+ * any elements.
+ */
+class _TrustedHtmlTreeSanitizer implements NodeTreeSanitizer {
+  const _TrustedHtmlTreeSanitizer();
+
+  sanitizeTree(Node node) {}
+}
+
+/**
+ * Defines the policy for what types of uris are allowed for particular
+ * attribute values.
+ *
+ * This can be used to provide custom rules such as allowing all http:// URIs
+ * for image attributes but only same-origin URIs for anchor tags.
+ */
+abstract class UriPolicy {
+  /**
+   * Constructs the default UriPolicy which is to only allow Uris to the same
+   * origin as the application was launched from.
+   *
+   * This will block all ftp: mailto: URIs. It will also block accessing
+   * https://example.com if the app is running from http://example.com.
+   */
+  factory UriPolicy() => new _SameOriginUriPolicy();
+
+  /**
+   * Checks if the uri is allowed on the specified attribute.
+   *
+   * The uri provided may or may not be a relative path.
+   */
+  bool allowsUri(String uri);
+}
+
+/**
+ * Allows URIs to the same origin as the current application was loaded from
+ * (such as https://example.com:80).
+ */
+class _SameOriginUriPolicy implements UriPolicy {
+  final AnchorElement _hiddenAnchor = new AnchorElement();
+  final Location _loc = window.location;
+
+  bool allowsUri(String uri) {
+    _hiddenAnchor.href = uri;
+    // IE leaves an empty hostname for same-origin URIs.
+    return (_hiddenAnchor.hostname == _loc.hostname &&
+            _hiddenAnchor.port == _loc.port &&
+            _hiddenAnchor.protocol == _loc.protocol) ||
+        (_hiddenAnchor.hostname == '' &&
+            _hiddenAnchor.port == '' &&
+            (_hiddenAnchor.protocol == ':' || _hiddenAnchor.protocol == ''));
+  }
+}
+
+class _ThrowsNodeValidator implements NodeValidator {
+  final NodeValidator validator;
+
+  _ThrowsNodeValidator(this.validator) {}
+
+  bool allowsElement(Element element) {
+    if (!validator.allowsElement(element)) {
+      throw new ArgumentError(Element._safeTagName(element));
+    }
+    return true;
+  }
+
+  bool allowsAttribute(Element element, String attributeName, String value) {
+    if (!validator.allowsAttribute(element, attributeName, value)) {
+      throw new ArgumentError(
+          '${Element._safeTagName(element)}[$attributeName="$value"]');
+    }
+  }
+}
+
+/**
+ * Standard tree sanitizer which validates a node tree against the provided
+ * validator and removes any nodes or attributes which are not allowed.
+ */
+class _ValidatingTreeSanitizer implements NodeTreeSanitizer {
+  NodeValidator validator;
+  _ValidatingTreeSanitizer(this.validator) {}
+
+  void sanitizeTree(Node node) {
+    void walk(Node node, Node parent) {
+      sanitizeNode(node, parent);
+
+      var child = node.lastChild;
+      while (null != child) {
+        var nextChild;
+        try {
+          // Child may be removed during the walk, and we may not
+          // even be able to get its previousNode.
+          nextChild = child.previousNode;
+        } catch (e) {
+          // Child appears bad, remove it. We want to check the rest of the
+          // children of node and, but we have no way of getting to the next
+          // child, so start again from the last child.
+          _removeNode(child, node);
+          child = null;
+          nextChild = node.lastChild;
+        }
+        if (child != null) walk(child, node);
+        child = nextChild;
+      }
+    }
+
+    walk(node, null);
+  }
+
+  /// Aggressively try to remove node.
+  void _removeNode(Node node, Node parent) {
+    // If we have the parent, it's presumably already passed more sanitization
+    // or is the fragment, so ask it to remove the child. And if that fails
+    // try to set the outer html.
+    if (parent == null) {
+      node.remove();
+    } else {
+      parent._removeChild(node);
+    }
+  }
+
+  /// Sanitize the element, assuming we can't trust anything about it.
+  void _sanitizeUntrustedElement(/* Element */ element, Node parent) {
+    // If the _hasCorruptedAttributes does not successfully return false,
+    // then we consider it corrupted and remove.
+    // TODO(alanknight): This is a workaround because on Firefox
+    // embed/object
+    // tags typeof is "function", not "object". We don't recognize them, and
+    // can't call methods. This does mean that you can't explicitly allow an
+    // embed tag. The only thing that will let it through is a null
+    // sanitizer that doesn't traverse the tree at all. But sanitizing while
+    // allowing embeds seems quite unlikely. This is also the reason that we
+    // can't declare the type of element, as an embed won't pass any type
+    // check in dart2js.
+    var corrupted = true;
+    var attrs;
+    var isAttr;
+    try {
+      // If getting/indexing attributes throws, count that as corrupt.
+      attrs = element.attributes;
+      isAttr = attrs['is'];
+      var corruptedTest1 = Element._hasCorruptedAttributes(element);
+
+      // On IE, erratically, the hasCorruptedAttributes test can return false,
+      // even though it clearly is corrupted. A separate copy of the test
+      // inlining just the basic check seems to help.
+      corrupted = corruptedTest1
+          ? true
+          : Element._hasCorruptedAttributesAdditionalCheck(element);
+    } catch (e) {}
+    var elementText = 'element unprintable';
+    try {
+      elementText = element.toString();
+    } catch (e) {}
+    try {
+      var elementTagName = Element._safeTagName(element);
+      _sanitizeElement(element, parent, corrupted, elementText, elementTagName,
+          attrs, isAttr);
+    } on ArgumentError {
+      // Thrown by _ThrowsNodeValidator
+      rethrow;
+    } catch (e) {
+      // Unexpected exception sanitizing -> remove
+      _removeNode(element, parent);
+      window.console.warn('Removing corrupted element $elementText');
+    }
+  }
+
+  /// Having done basic sanity checking on the element, and computed the
+  /// important attributes we want to check, remove it if it's not valid
+  /// or not allowed, either as a whole or particular attributes.
+  void _sanitizeElement(Element element, Node parent, bool corrupted,
+      String text, String tag, Map attrs, String isAttr) {
+    if (false != corrupted) {
+      _removeNode(element, parent);
+      window.console
+          .warn('Removing element due to corrupted attributes on <$text>');
+      return;
+    }
+    if (!validator.allowsElement(element)) {
+      _removeNode(element, parent);
+      window.console.warn('Removing disallowed element <$tag> from $parent');
+      return;
+    }
+
+    if (isAttr != null) {
+      if (!validator.allowsAttribute(element, 'is', isAttr)) {
+        _removeNode(element, parent);
+        window.console.warn('Removing disallowed type extension '
+            '<$tag is="$isAttr">');
+        return;
+      }
+    }
+
+    // TODO(blois): Need to be able to get all attributes, irrespective of
+    // XMLNS.
+    var keys = attrs.keys.toList();
+    for (var i = attrs.length - 1; i >= 0; --i) {
+      var name = keys[i];
+      if (!validator.allowsAttribute(
+          element, name.toLowerCase(), attrs[name])) {
+        window.console.warn('Removing disallowed attribute '
+            '<$tag $name="${attrs[name]}">');
+        attrs.remove(name);
+      }
+    }
+
+    if (element is TemplateElement) {
+      TemplateElement template = element;
+      sanitizeTree(template.content);
+    }
+  }
+
+  /// Sanitize the node and its children recursively.
+  void sanitizeNode(Node node, Node parent) {
+    switch (node.nodeType) {
+      case Node.ELEMENT_NODE:
+        _sanitizeUntrustedElement(node, parent);
+        break;
+      case Node.COMMENT_NODE:
+      case Node.DOCUMENT_FRAGMENT_NODE:
+      case Node.TEXT_NODE:
+      case Node.CDATA_SECTION_NODE:
+        break;
+      default:
+        _removeNode(node, parent);
+    }
+  }
+}
diff --git a/sdk_nnbd/lib/html/dartium/nativewrappers.dart b/sdk_nnbd/lib/html/dartium/nativewrappers.dart
new file mode 100644
index 0000000..b6d2dc4
--- /dev/null
+++ b/sdk_nnbd/lib/html/dartium/nativewrappers.dart
@@ -0,0 +1,13 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library nativewrappers;
+
+class NativeFieldWrapperClass1 {}
+
+class NativeFieldWrapperClass2 {}
+
+class NativeFieldWrapperClass3 {}
+
+class NativeFieldWrapperClass4 {}
diff --git a/sdk_nnbd/lib/html/html_common/conversions.dart b/sdk_nnbd/lib/html/html_common/conversions.dart
new file mode 100644
index 0000000..4c31efb
--- /dev/null
+++ b/sdk_nnbd/lib/html/html_common/conversions.dart
@@ -0,0 +1,359 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Conversions for IDBKey.
+//
+// Per http://www.w3.org/TR/IndexedDB/#key-construct
+//
+// "A value is said to be a valid key if it is one of the following types: Array
+// JavaScript objects [ECMA-262], DOMString [WEBIDL], Date [ECMA-262] or float
+// [WEBIDL]. However Arrays are only valid keys if every item in the array is
+// defined and is a valid key (i.e. sparse arrays can not be valid keys) and if
+// the Array doesn't directly or indirectly contain itself. Any non-numeric
+// properties are ignored, and thus does not affect whether the Array is a valid
+// key. Additionally, if the value is of type float, it is only a valid key if
+// it is not NaN, and if the value is of type Date it is only a valid key if its
+// [[PrimitiveValue]] internal property, as defined by [ECMA-262], is not NaN."
+
+// What is required is to ensure that an Lists in the key are actually
+// JavaScript arrays, and any Dates are JavaScript Dates.
+
+// Conversions for Window.  These check if the window is the local
+// window, and if it's not, wraps or unwraps it with a secure wrapper.
+// We need to test for EventTarget here as well as it's a base type.
+// We omit an unwrapper for Window as no methods take a non-local
+// window as a parameter.
+
+part of html_common;
+
+/// Converts a Dart value into a JavaScript SerializedScriptValue.
+convertDartToNative_SerializedScriptValue(value) {
+  return convertDartToNative_PrepareForStructuredClone(value);
+}
+
+/// Since the source object may be viewed via a JavaScript event listener the
+/// original may not be modified.
+convertNativeToDart_SerializedScriptValue(object) {
+  return convertNativeToDart_AcceptStructuredClone(object, mustCopy: true);
+}
+
+/**
+ * Converts a Dart value into a JavaScript SerializedScriptValue.  Returns the
+ * original input or a functional 'copy'.  Does not mutate the original.
+ *
+ * The main transformation is the translation of Dart Maps are converted to
+ * JavaScript Objects.
+ *
+ * The algorithm is essentially a dry-run of the structured clone algorithm
+ * described at
+ * http://www.whatwg.org/specs/web-apps/current-work/multipage/common-dom-interfaces.html#structured-clone
+ * https://www.khronos.org/registry/typedarray/specs/latest/#9
+ *
+ * Since the result of this function is expected to be passed only to JavaScript
+ * operations that perform the structured clone algorithm which does not mutate
+ * its output, the result may share structure with the input [value].
+ */
+abstract class _StructuredClone {
+  // TODO(sra): Replace slots with identity hash table.
+  var values = [];
+  var copies = []; // initially 'null', 'true' during initial DFS, then a copy.
+
+  int findSlot(value) {
+    int length = values.length;
+    for (int i = 0; i < length; i++) {
+      if (identical(values[i], value)) return i;
+    }
+    values.add(value);
+    copies.add(null);
+    return length;
+  }
+
+  readSlot(int i) => copies[i];
+  writeSlot(int i, x) {
+    copies[i] = x;
+  }
+
+  cleanupSlots() {} // Will be needed if we mark objects with a property.
+  bool cloneNotRequired(object);
+  newJsMap();
+  List newJsList(length);
+  void putIntoMap(map, key, value);
+
+  // Returns the input, or a clone of the input.
+  walk(e) {
+    if (e == null) return e;
+    if (e is bool) return e;
+    if (e is num) return e;
+    if (e is String) return e;
+    if (e is DateTime) {
+      return convertDartToNative_DateTime(e);
+    }
+    if (e is RegExp) {
+      // TODO(sra).
+      throw new UnimplementedError('structured clone of RegExp');
+    }
+
+    // The browser's internal structured cloning algorithm will copy certain
+    // types of object, but it will copy only its own implementations and not
+    // just any Dart implementations of the interface.
+
+    // TODO(sra): The JavaScript objects suitable for direct cloning by the
+    // structured clone algorithm could be tagged with an private interface.
+
+    if (e is File) return e;
+    if (e is Blob) return e;
+    if (e is FileList) return e;
+
+    // TODO(sra): Firefox: How to convert _TypedImageData on the other end?
+    if (e is ImageData) return e;
+    if (cloneNotRequired(e)) return e;
+
+    if (e is Map) {
+      var slot = findSlot(e);
+      var copy = readSlot(slot);
+      if (copy != null) return copy;
+      copy = newJsMap();
+      writeSlot(slot, copy);
+      e.forEach((key, value) {
+        putIntoMap(copy, key, walk(value));
+      });
+      return copy;
+    }
+
+    if (e is List) {
+      // Since a JavaScript Array is an instance of Dart List it is tempting
+      // in dart2js to avoid making a copy of the list if there is no need
+      // to copy anything reachable from the array.  However, the list may have
+      // non-native properties or methods from interceptors and such, e.g.
+      // an immutability marker. So we  had to stop doing that.
+      var slot = findSlot(e);
+      var copy = JS('returns:List|Null;creates:;', '#', readSlot(slot));
+      if (copy != null) return copy;
+      copy = copyList(e, slot);
+      return copy;
+    }
+
+    throw new UnimplementedError('structured clone of other type');
+  }
+
+  List copyList(List e, int slot) {
+    int i = 0;
+    int length = e.length;
+    var copy = newJsList(length);
+    writeSlot(slot, copy);
+    for (; i < length; i++) {
+      copy[i] = walk(e[i]);
+    }
+    return copy;
+  }
+
+  convertDartToNative_PrepareForStructuredClone(value) {
+    var copy = walk(value);
+    cleanupSlots();
+    return copy;
+  }
+}
+
+/**
+ * Converts a native value into a Dart object.
+ *
+ * If [mustCopy] is [:false:], may return the original input.  May mutate the
+ * original input (but will be idempotent if mutation occurs).  It is assumed
+ * that this conversion happens on native serializable script values such values
+ * from native DOM calls.
+ *
+ * [object] is the result of a structured clone operation.
+ *
+ * If necessary, JavaScript Dates are converted into Dart Dates.
+ *
+ * If [mustCopy] is [:true:], the entire object is copied and the original input
+ * is not mutated.  This should be the case where Dart and JavaScript code can
+ * access the value, for example, via multiple event listeners for
+ * MessageEvents.  Mutating the object to make it more 'Dart-like' would corrupt
+ * the value as seen from the JavaScript listeners.
+ */
+abstract class _AcceptStructuredClone {
+  // TODO(sra): Replace slots with identity hash table.
+  var values = [];
+  var copies = []; // initially 'null', 'true' during initial DFS, then a copy.
+  bool mustCopy = false;
+
+  int findSlot(value) {
+    int length = values.length;
+    for (int i = 0; i < length; i++) {
+      if (identicalInJs(values[i], value)) return i;
+    }
+    values.add(value);
+    copies.add(null);
+    return length;
+  }
+
+  /// Are the two objects identical, but taking into account that two JsObject
+  /// wrappers may not be identical, but their underlying Js Object might be.
+  bool identicalInJs(a, b);
+  readSlot(int i) => copies[i];
+  writeSlot(int i, x) {
+    copies[i] = x;
+  }
+
+  /// Iterate over the JS properties.
+  forEachJsField(object, action(key, value));
+
+  /// Create a new Dart list of the given length. May create a native List or
+  /// a JsArray, depending if we're in Dartium or dart2js.
+  List newDartList(length);
+
+  walk(e) {
+    if (e == null) return e;
+    if (e is bool) return e;
+    if (e is num) return e;
+    if (e is String) return e;
+
+    if (isJavaScriptDate(e)) {
+      return convertNativeToDart_DateTime(e);
+    }
+
+    if (isJavaScriptRegExp(e)) {
+      // TODO(sra).
+      throw new UnimplementedError('structured clone of RegExp');
+    }
+
+    if (isJavaScriptPromise(e)) {
+      return convertNativePromiseToDartFuture(e);
+    }
+
+    if (isJavaScriptSimpleObject(e)) {
+      // TODO(sra): If mustCopy is false, swizzle the prototype for one of a Map
+      // implementation that uses the properties as storage.
+      var slot = findSlot(e);
+      var copy = readSlot(slot);
+      if (copy != null) return copy;
+      copy = {};
+
+      writeSlot(slot, copy);
+      forEachJsField(e, (key, value) => copy[key] = walk(value));
+      return copy;
+    }
+
+    if (isJavaScriptArray(e)) {
+      var l = JS<List>('returns:List;creates:;', '#', e);
+      var slot = findSlot(l);
+      var copy = JS<List>('returns:List|Null;creates:;', '#', readSlot(slot));
+      if (copy != null) return copy;
+
+      int length = l.length;
+      // Since a JavaScript Array is an instance of Dart List, we can modify it
+      // in-place unless we must copy.
+      copy = mustCopy ? newDartList(length) : l;
+      writeSlot(slot, copy);
+
+      for (int i = 0; i < length; i++) {
+        copy[i] = walk(l[i]);
+      }
+      return copy;
+    }
+
+    // Assume anything else is already a valid Dart object, either by having
+    // already been processed, or e.g. a cloneable native class.
+    return e;
+  }
+
+  convertNativeToDart_AcceptStructuredClone(object, {mustCopy: false}) {
+    this.mustCopy = mustCopy;
+    var copy = walk(object);
+    return copy;
+  }
+}
+
+// Conversions for ContextAttributes.
+//
+// On Firefox, the returned ContextAttributes is a plain object.
+class ContextAttributes {
+  bool alpha;
+  bool antialias;
+  bool depth;
+  bool premultipliedAlpha;
+  bool preserveDrawingBuffer;
+  bool stencil;
+  bool failIfMajorPerformanceCaveat;
+
+  ContextAttributes(
+      this.alpha,
+      this.antialias,
+      this.depth,
+      this.failIfMajorPerformanceCaveat,
+      this.premultipliedAlpha,
+      this.preserveDrawingBuffer,
+      this.stencil);
+}
+
+convertNativeToDart_ContextAttributes(nativeContextAttributes) {
+  // On Firefox the above test fails because ContextAttributes is a plain
+  // object so we create a _TypedContextAttributes.
+
+  return new ContextAttributes(
+      JS('var', '#.alpha', nativeContextAttributes),
+      JS('var', '#.antialias', nativeContextAttributes),
+      JS('var', '#.depth', nativeContextAttributes),
+      JS('var', '#.failIfMajorPerformanceCaveat', nativeContextAttributes),
+      JS('var', '#.premultipliedAlpha', nativeContextAttributes),
+      JS('var', '#.preserveDrawingBuffer', nativeContextAttributes),
+      JS('var', '#.stencil', nativeContextAttributes));
+}
+
+// Conversions for ImageData
+//
+// On Firefox, the returned ImageData is a plain object.
+
+class _TypedImageData implements ImageData {
+  final Uint8ClampedList data;
+  final int height;
+  final int width;
+
+  _TypedImageData(this.data, this.height, this.width);
+}
+
+ImageData convertNativeToDart_ImageData(nativeImageData) {
+  // None of the native getters that return ImageData are declared as returning
+  // [ImageData] since that is incorrect for FireFox, which returns a plain
+  // Object.  So we need something that tells the compiler that the ImageData
+  // class has been instantiated.
+  // TODO(sra): Remove this when all the ImageData returning APIs have been
+  // annotated as returning the union ImageData + Object.
+  JS('ImageData', '0');
+
+  if (nativeImageData is ImageData) {
+    // Fix for Issue 16069: on IE, the `data` field is a CanvasPixelArray which
+    // has Array as the constructor property.  This interferes with finding the
+    // correct interceptor.  Fix it by overwriting the constructor property.
+    var data = nativeImageData.data;
+    if (JS('bool', '#.constructor === Array', data)) {
+      if (JS('bool', 'typeof CanvasPixelArray !== "undefined"')) {
+        JS('void', '#.constructor = CanvasPixelArray', data);
+        // This TypedArray property is missing from CanvasPixelArray.
+        JS('void', '#.BYTES_PER_ELEMENT = 1', data);
+      }
+    }
+
+    return nativeImageData;
+  }
+
+  // On Firefox the above test fails because [nativeImageData] is a plain
+  // object.  So we create a _TypedImageData.
+
+  return new _TypedImageData(
+      JS('NativeUint8ClampedList', '#.data', nativeImageData),
+      JS('var', '#.height', nativeImageData),
+      JS('var', '#.width', nativeImageData));
+}
+
+// We can get rid of this conversion if _TypedImageData implements the fields
+// with native names.
+convertDartToNative_ImageData(ImageData imageData) {
+  if (imageData is _TypedImageData) {
+    return JS('', '{data: #, height: #, width: #}', imageData.data,
+        imageData.height, imageData.width);
+  }
+  return imageData;
+}
diff --git a/sdk_nnbd/lib/html/html_common/conversions_dart2js.dart b/sdk_nnbd/lib/html/html_common/conversions_dart2js.dart
new file mode 100644
index 0000000..36153cf
--- /dev/null
+++ b/sdk_nnbd/lib/html/html_common/conversions_dart2js.dart
@@ -0,0 +1,106 @@
+part of html_common;
+
+/// Converts a JavaScript object with properties into a Dart Map.
+/// Not suitable for nested objects.
+Map<String, dynamic> convertNativeToDart_Dictionary(object) {
+  if (object == null) return null;
+  var dict = <String, dynamic>{};
+  var keys = JS('JSExtendableArray', 'Object.getOwnPropertyNames(#)', object);
+  for (final key in keys) {
+    dict[key] = JS('var', '#[#]', object, key);
+  }
+  return dict;
+}
+
+/// Converts a flat Dart map into a JavaScript object with properties.
+convertDartToNative_Dictionary(Map dict, [void postCreate(Object f)]) {
+  if (dict == null) return null;
+  var object = JS('var', '{}');
+  if (postCreate != null) {
+    postCreate(object);
+  }
+  dict.forEach((key, value) {
+    JS('void', '#[#] = #', object, key, value);
+  });
+  return object;
+}
+
+/**
+ * Ensures that the input is a JavaScript Array.
+ *
+ * Creates a new JavaScript array if necessary, otherwise returns the original.
+ */
+List convertDartToNative_StringArray(List<String> input) {
+  // TODO(sra).  Implement this.
+  return input;
+}
+
+DateTime convertNativeToDart_DateTime(date) {
+  var millisSinceEpoch = JS('int', '#.getTime()', date);
+  return new DateTime.fromMillisecondsSinceEpoch(millisSinceEpoch, isUtc: true);
+}
+
+convertDartToNative_DateTime(DateTime date) {
+  return JS('', 'new Date(#)', date.millisecondsSinceEpoch);
+}
+
+convertDartToNative_PrepareForStructuredClone(value) =>
+    new _StructuredCloneDart2Js()
+        .convertDartToNative_PrepareForStructuredClone(value);
+
+convertNativeToDart_AcceptStructuredClone(object, {mustCopy: false}) =>
+    new _AcceptStructuredCloneDart2Js()
+        .convertNativeToDart_AcceptStructuredClone(object, mustCopy: mustCopy);
+
+class _StructuredCloneDart2Js extends _StructuredClone {
+  newJsMap() => JS('var', '{}');
+  putIntoMap(map, key, value) => JS('void', '#[#] = #', map, key, value);
+  newJsList(length) => JS('JSExtendableArray', 'new Array(#)', length);
+  cloneNotRequired(e) =>
+      (e is NativeByteBuffer || e is NativeTypedData || e is MessagePort);
+}
+
+class _AcceptStructuredCloneDart2Js extends _AcceptStructuredClone {
+  List newJsList(length) => JS('JSExtendableArray', 'new Array(#)', length);
+  List newDartList(length) => newJsList(length);
+  bool identicalInJs(a, b) => identical(a, b);
+
+  void forEachJsField(object, action(key, value)) {
+    for (final key in JS('JSExtendableArray', 'Object.keys(#)', object)) {
+      action(key, JS('var', '#[#]', object, key));
+    }
+  }
+}
+
+bool isJavaScriptDate(value) => JS('bool', '# instanceof Date', value);
+bool isJavaScriptRegExp(value) => JS('bool', '# instanceof RegExp', value);
+bool isJavaScriptArray(value) => JS('bool', '# instanceof Array', value);
+bool isJavaScriptSimpleObject(value) {
+  var proto = JS('', 'Object.getPrototypeOf(#)', value);
+  return JS('bool', '# === Object.prototype', proto) ||
+      JS('bool', '# === null', proto);
+}
+
+bool isImmutableJavaScriptArray(value) =>
+    JS('bool', r'!!(#.immutable$list)', value);
+bool isJavaScriptPromise(value) =>
+    JS('bool', r'typeof Promise != "undefined" && # instanceof Promise', value);
+
+Future convertNativePromiseToDartFuture(promise) {
+  var completer = new Completer();
+  var then = convertDartClosureToJS((result) => completer.complete(result), 1);
+  var error =
+      convertDartClosureToJS((result) => completer.completeError(result), 1);
+  var newPromise = JS('', '#.then(#)["catch"](#)', promise, then, error);
+  return completer.future;
+}
+
+const String _serializedScriptValue = 'num|String|bool|'
+    'JSExtendableArray|=Object|'
+    'Blob|File|NativeByteBuffer|NativeTypedData|MessagePort'
+    // TODO(sra): Add Date, RegExp.
+    ;
+const annotation_Creates_SerializedScriptValue =
+    const Creates(_serializedScriptValue);
+const annotation_Returns_SerializedScriptValue =
+    const Returns(_serializedScriptValue);
diff --git a/sdk_nnbd/lib/html/html_common/css_class_set.dart b/sdk_nnbd/lib/html/html_common/css_class_set.dart
new file mode 100644
index 0000000..2286057
--- /dev/null
+++ b/sdk_nnbd/lib/html/html_common/css_class_set.dart
@@ -0,0 +1,242 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of html_common;
+
+abstract class CssClassSetImpl extends SetBase<String> implements CssClassSet {
+  static final RegExp _validTokenRE = new RegExp(r'^\S+$');
+
+  String _validateToken(String value) {
+    if (_validTokenRE.hasMatch(value)) return value;
+    throw new ArgumentError.value(value, 'value', 'Not a valid class token');
+  }
+
+  String toString() {
+    return readClasses().join(' ');
+  }
+
+  /**
+   * Adds the class [value] to the element if it is not on it, removes it if it
+   * is.
+   *
+   * 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.
+   */
+  bool toggle(String value, [bool shouldAdd]) {
+    _validateToken(value);
+    Set<String> s = readClasses();
+    bool result = false;
+    if (shouldAdd == null) shouldAdd = !s.contains(value);
+    if (shouldAdd) {
+      s.add(value);
+      result = true;
+    } else {
+      s.remove(value);
+    }
+    writeClasses(s);
+    return result;
+  }
+
+  /**
+   * Returns [:true:] if classes cannot be added or removed from this
+   * [:CssClassSet:].
+   */
+  bool get frozen => false;
+
+  // interface Iterable - BEGIN
+  Iterator<String> get iterator => readClasses().iterator;
+  // interface Iterable - END
+
+  // interface Collection - BEGIN
+  void forEach(void f(String element)) {
+    readClasses().forEach(f);
+  }
+
+  String join([String separator = ""]) => readClasses().join(separator);
+
+  Iterable<T> map<T>(T f(String e)) => readClasses().map<T>(f);
+
+  Iterable<String> where(bool f(String element)) => readClasses().where(f);
+
+  Iterable<T> expand<T>(Iterable<T> f(String element)) =>
+      readClasses().expand<T>(f);
+
+  bool every(bool f(String element)) => readClasses().every(f);
+
+  bool any(bool f(String element)) => readClasses().any(f);
+
+  bool get isEmpty => readClasses().isEmpty;
+
+  bool get isNotEmpty => readClasses().isNotEmpty;
+
+  int get length => readClasses().length;
+
+  String reduce(String combine(String value, String element)) {
+    return readClasses().reduce(combine);
+  }
+
+  T fold<T>(T initialValue, T combine(T previousValue, String element)) {
+    return readClasses().fold<T>(initialValue, combine);
+  }
+
+  // interface Collection - END
+
+  // interface Set - BEGIN
+  /**
+   * Determine if this element contains the class [value].
+   *
+   * This is the Dart equivalent of jQuery's
+   * [hasClass](http://api.jquery.com/hasClass/).
+   */
+  bool contains(Object value) {
+    if (value is! String) return false;
+    _validateToken(value);
+    return readClasses().contains(value);
+  }
+
+  /** Lookup from the Set interface. Not interesting for a String set. */
+  String lookup(Object value) => contains(value) ? value : null;
+
+  /**
+   * Add the class [value] to element.
+   *
+   * This is the Dart equivalent of jQuery's
+   * [addClass](http://api.jquery.com/addClass/).
+   */
+  bool add(String value) {
+    _validateToken(value);
+    // TODO - figure out if we need to do any validation here
+    // or if the browser natively does enough.
+    return modify((s) => s.add(value));
+  }
+
+  /**
+   * Remove the class [value] from element, and return true on successful
+   * removal.
+   *
+   * This is the Dart equivalent of jQuery's
+   * [removeClass](http://api.jquery.com/removeClass/).
+   */
+  bool remove(Object value) {
+    _validateToken(value);
+    if (value is! String) return false;
+    Set<String> s = readClasses();
+    bool result = s.remove(value);
+    writeClasses(s);
+    return result;
+  }
+
+  /**
+   * Add all classes specified in [iterable] to element.
+   *
+   * This is the Dart equivalent of jQuery's
+   * [addClass](http://api.jquery.com/addClass/).
+   */
+  void addAll(Iterable<String> iterable) {
+    // TODO - see comment above about validation.
+    modify((s) => s.addAll(iterable.map(_validateToken)));
+  }
+
+  /**
+   * Remove all classes specified in [iterable] from element.
+   *
+   * This is the Dart equivalent of jQuery's
+   * [removeClass](http://api.jquery.com/removeClass/).
+   */
+  void removeAll(Iterable<Object> iterable) {
+    modify((s) => s.removeAll(iterable));
+  }
+
+  /**
+   * Toggles all classes specified in [iterable] on element.
+   *
+   * Iterate through [iterable]'s items, and add it if it is not on it, or
+   * remove it if it is. This is the Dart equivalent of jQuery's
+   * [toggleClass](http://api.jquery.com/toggleClass/).
+   * 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.
+   */
+  void toggleAll(Iterable<String> iterable, [bool shouldAdd]) {
+    iterable.forEach((e) => toggle(e, shouldAdd));
+  }
+
+  void retainAll(Iterable<Object> iterable) {
+    modify((s) => s.retainAll(iterable));
+  }
+
+  void removeWhere(bool test(String name)) {
+    modify((s) => s.removeWhere(test));
+  }
+
+  void retainWhere(bool test(String name)) {
+    modify((s) => s.retainWhere(test));
+  }
+
+  bool containsAll(Iterable<Object> collection) =>
+      readClasses().containsAll(collection);
+
+  Set<String> intersection(Set<Object> other) =>
+      readClasses().intersection(other);
+
+  Set<String> union(Set<String> other) => readClasses().union(other);
+
+  Set<String> difference(Set<Object> other) => readClasses().difference(other);
+
+  String get first => readClasses().first;
+  String get last => readClasses().last;
+  String get single => readClasses().single;
+  List<String> toList({bool growable: true}) =>
+      readClasses().toList(growable: growable);
+  Set<String> toSet() => readClasses().toSet();
+  Iterable<String> take(int n) => readClasses().take(n);
+  Iterable<String> takeWhile(bool test(String value)) =>
+      readClasses().takeWhile(test);
+  Iterable<String> skip(int n) => readClasses().skip(n);
+  Iterable<String> skipWhile(bool test(String value)) =>
+      readClasses().skipWhile(test);
+  String firstWhere(bool test(String value), {String orElse()}) =>
+      readClasses().firstWhere(test, orElse: orElse);
+  String lastWhere(bool test(String value), {String orElse()}) =>
+      readClasses().lastWhere(test, orElse: orElse);
+  String singleWhere(bool test(String value), {String orElse()}) =>
+      readClasses().singleWhere(test, orElse: orElse);
+  String elementAt(int index) => readClasses().elementAt(index);
+
+  void clear() {
+    // TODO(sra): Do this without reading the classes.
+    modify((s) => s.clear());
+  }
+  // interface Set - END
+
+  /**
+   * Helper method used to modify the set of css classes on this element.
+   *
+   *   f - callback with:
+   *   s - a Set of all the css class name currently on this element.
+   *
+   *   After f returns, the modified set is written to the
+   *       className property of this element.
+   */
+  modify(f(Set<String> s)) {
+    Set<String> s = readClasses();
+    var ret = f(s);
+    writeClasses(s);
+    return ret;
+  }
+
+  /**
+   * Read the class names from the Element class property,
+   * and put them into a set (duplicates are discarded).
+   * This is intended to be overridden by specific implementations.
+   */
+  Set<String> readClasses();
+
+  /**
+   * Join all the elements of a set into one string and write
+   * back to the element.
+   * This is intended to be overridden by specific implementations.
+   */
+  void writeClasses(Set<String> s);
+}
diff --git a/sdk_nnbd/lib/html/html_common/device.dart b/sdk_nnbd/lib/html/html_common/device.dart
new file mode 100644
index 0000000..123a5db
--- /dev/null
+++ b/sdk_nnbd/lib/html/html_common/device.dart
@@ -0,0 +1,112 @@
+// Copyright (c) 2011, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of html_common;
+
+/**
+ * Utils for device detection.
+ */
+class Device {
+  static bool _isOpera;
+  static bool _isIE;
+  static bool _isFirefox;
+  static bool _isWebKit;
+  static String _cachedCssPrefix;
+  static String _cachedPropertyPrefix;
+
+  /**
+   * Gets the browser's user agent. Using this function allows tests to inject
+   * the user agent.
+ * Returns the user agent.
+   */
+  static String get userAgent => window.navigator.userAgent;
+
+  /**
+   * Determines if the current device is running Opera.
+   */
+  static bool get isOpera {
+    if (_isOpera == null) {
+      _isOpera = userAgent.contains("Opera", 0);
+    }
+    return _isOpera;
+  }
+
+  /**
+   * Determines if the current device is running Internet Explorer.
+   */
+  static bool get isIE {
+    if (_isIE == null) {
+      _isIE = !isOpera && userAgent.contains("Trident/", 0);
+    }
+    return _isIE;
+  }
+
+  /**
+   * Determines if the current device is running Firefox.
+   */
+  static bool get isFirefox {
+    if (_isFirefox == null) {
+      _isFirefox = userAgent.contains("Firefox", 0);
+    }
+    return _isFirefox;
+  }
+
+  /**
+   * Determines if the current device is running WebKit.
+   */
+  static bool get isWebKit {
+    if (_isWebKit == null) {
+      _isWebKit = !isOpera && userAgent.contains("WebKit", 0);
+    }
+    return _isWebKit;
+  }
+
+  /**
+   * Gets the CSS property prefix for the current platform.
+   */
+  static String get cssPrefix {
+    String prefix = _cachedCssPrefix;
+    if (prefix != null) return prefix;
+    if (isFirefox) {
+      prefix = '-moz-';
+    } else if (isIE) {
+      prefix = '-ms-';
+    } else if (isOpera) {
+      prefix = '-o-';
+    } else {
+      prefix = '-webkit-';
+    }
+    return _cachedCssPrefix = prefix;
+  }
+
+  /**
+   * Prefix as used for JS property names.
+   */
+  static String get propertyPrefix {
+    String prefix = _cachedPropertyPrefix;
+    if (prefix != null) return prefix;
+    if (isFirefox) {
+      prefix = 'moz';
+    } else if (isIE) {
+      prefix = 'ms';
+    } else if (isOpera) {
+      prefix = 'o';
+    } else {
+      prefix = 'webkit';
+    }
+    return _cachedPropertyPrefix = prefix;
+  }
+
+  /**
+   * Checks to see if the event class is supported by the current platform.
+   */
+  static bool isEventTypeSupported(String eventType) {
+    // Browsers throw for unsupported event names.
+    try {
+      var e = new Event.eventType(eventType, '');
+      return e is Event;
+    } catch (_) {}
+    return false;
+  }
+}
diff --git a/sdk_nnbd/lib/html/html_common/filtered_element_list.dart b/sdk_nnbd/lib/html/html_common/filtered_element_list.dart
new file mode 100644
index 0000000..fba6ad7
--- /dev/null
+++ b/sdk_nnbd/lib/html/html_common/filtered_element_list.dart
@@ -0,0 +1,150 @@
+// Copyright (c) 2011, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of html_common;
+
+/**
+ * An indexable collection of a node's direct descendants in the document tree,
+ * filtered so that only elements are in the collection.
+ */
+class FilteredElementList extends ListBase<Element> implements NodeListWrapper {
+  final Node _node;
+  final List<Node> _childNodes;
+
+  /**
+   * Creates a collection of the elements that descend from a node.
+   *
+   * Example usage:
+   *
+   *     var filteredElements = new FilteredElementList(query("#container"));
+   *     // filteredElements is [a, b, c].
+   */
+  FilteredElementList(Node node)
+      : _childNodes = node.nodes,
+        _node = node;
+
+  // We can't memoize this, since it's possible that children will be messed
+  // with externally to this class.
+  Iterable<Element> get _iterable =>
+      _childNodes.where((n) => n is Element).map<Element>((n) => n as Element);
+  List<Element> get _filtered =>
+      new List<Element>.from(_iterable, growable: false);
+
+  void forEach(void f(Element element)) {
+    // This cannot use the iterator, because operations during iteration might
+    // modify the collection, e.g. addAll might append a node to another parent.
+    _filtered.forEach(f);
+  }
+
+  void operator []=(int index, Element value) {
+    this[index].replaceWith(value);
+  }
+
+  set length(int newLength) {
+    final len = this.length;
+    if (newLength >= len) {
+      return;
+    } else if (newLength < 0) {
+      throw new ArgumentError("Invalid list length");
+    }
+
+    removeRange(newLength, len);
+  }
+
+  void add(Element value) {
+    _childNodes.add(value);
+  }
+
+  void addAll(Iterable<Element> iterable) {
+    for (Element element in iterable) {
+      add(element);
+    }
+  }
+
+  bool contains(Object needle) {
+    if (needle is! Element) return false;
+    Element element = needle;
+    return element.parentNode == _node;
+  }
+
+  Iterable<Element> get reversed => _filtered.reversed;
+
+  void sort([int compare(Element a, Element b)]) {
+    throw new UnsupportedError('Cannot sort filtered list');
+  }
+
+  void setRange(int start, int end, Iterable<Element> iterable,
+      [int skipCount = 0]) {
+    throw new UnsupportedError('Cannot setRange on filtered list');
+  }
+
+  void fillRange(int start, int end, [Element fillValue]) {
+    throw new UnsupportedError('Cannot fillRange on filtered list');
+  }
+
+  void replaceRange(int start, int end, Iterable<Element> iterable) {
+    throw new UnsupportedError('Cannot replaceRange on filtered list');
+  }
+
+  void removeRange(int start, int end) {
+    new List.from(_iterable.skip(start).take(end - start))
+        .forEach((el) => el.remove());
+  }
+
+  void clear() {
+    // Currently, ElementList#clear clears even non-element nodes, so we follow
+    // that behavior.
+    _childNodes.clear();
+  }
+
+  Element removeLast() {
+    final result = _iterable.last;
+    if (result != null) {
+      result.remove();
+    }
+    return result;
+  }
+
+  void insert(int index, Element value) {
+    if (index == length) {
+      add(value);
+    } else {
+      var element = _iterable.elementAt(index);
+      element.parentNode.insertBefore(value, element);
+    }
+  }
+
+  void insertAll(int index, Iterable<Element> iterable) {
+    if (index == length) {
+      addAll(iterable);
+    } else {
+      var element = _iterable.elementAt(index);
+      element.parentNode.insertAllBefore(iterable, element);
+    }
+  }
+
+  Element removeAt(int index) {
+    final result = this[index];
+    result.remove();
+    return result;
+  }
+
+  bool remove(Object element) {
+    if (element is! Element) return false;
+    if (contains(element)) {
+      (element as Element).remove(); // Placate the type checker
+      return true;
+    } else {
+      return false;
+    }
+  }
+
+  int get length => _iterable.length;
+  Element operator [](int index) => _iterable.elementAt(index);
+  // This cannot use the iterator, because operations during iteration might
+  // modify the collection, e.g. addAll might append a node to another parent.
+  Iterator<Element> get iterator => _filtered.iterator;
+
+  List<Node> get rawList => _node.childNodes;
+}
diff --git a/sdk_nnbd/lib/html/html_common/html_common.dart b/sdk_nnbd/lib/html/html_common/html_common.dart
new file mode 100644
index 0000000..e689c9a
--- /dev/null
+++ b/sdk_nnbd/lib/html/html_common/html_common.dart
@@ -0,0 +1,25 @@
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library html_common;
+
+import 'dart:async';
+import 'dart:collection';
+import 'dart:html';
+import 'dart:js' as js;
+import 'dart:_internal' show WhereIterable;
+import 'dart:mirrors';
+import 'dart:nativewrappers';
+import 'dart:typed_data';
+import 'dart:web_gl' as gl;
+
+import 'dart:_js_helper';
+
+import 'dart:_metadata';
+export 'dart:_metadata';
+
+part 'css_class_set.dart';
+part 'device.dart';
+part 'filtered_element_list.dart';
+part 'lists.dart';
+part 'conversions.dart';
diff --git a/sdk_nnbd/lib/html/html_common/html_common_dart2js.dart b/sdk_nnbd/lib/html/html_common/html_common_dart2js.dart
new file mode 100644
index 0000000..f162ad8
--- /dev/null
+++ b/sdk_nnbd/lib/html/html_common/html_common_dart2js.dart
@@ -0,0 +1,26 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library html_common;
+
+import 'dart:async';
+import 'dart:collection';
+import 'dart:html';
+import 'dart:_internal' show WhereIterable;
+import 'dart:web_gl' as gl;
+import 'dart:typed_data';
+import 'dart:_native_typed_data';
+import 'dart:_js_helper' show Creates, Returns, convertDartClosureToJS;
+import 'dart:_foreign_helper' show JS;
+import 'dart:_interceptors' show Interceptor, JSExtendableArray;
+
+import 'dart:_metadata';
+export 'dart:_metadata';
+
+part 'css_class_set.dart';
+part 'conversions.dart';
+part 'conversions_dart2js.dart';
+part 'device.dart';
+part 'filtered_element_list.dart';
+part 'lists.dart';
diff --git a/sdk_nnbd/lib/html/html_common/lists.dart b/sdk_nnbd/lib/html/html_common/lists.dart
new file mode 100644
index 0000000..c7abc41
--- /dev/null
+++ b/sdk_nnbd/lib/html/html_common/lists.dart
@@ -0,0 +1,71 @@
+// Copyright (c) 2011, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of html_common;
+
+class Lists {
+  /**
+   * Returns the index in the array [a] of the given [element], starting
+   * the search at index [startIndex] to [endIndex] (exclusive).
+   * Returns -1 if [element] is not found.
+   */
+  static int indexOf(List a, Object element, int startIndex, int endIndex) {
+    if (startIndex >= a.length) {
+      return -1;
+    }
+    if (startIndex < 0) {
+      startIndex = 0;
+    }
+    for (int i = startIndex; i < endIndex; i++) {
+      if (a[i] == element) {
+        return i;
+      }
+    }
+    return -1;
+  }
+
+  /**
+   * Returns the last index in the array [a] of the given [element], starting
+   * the search at index [startIndex] to 0.
+   * Returns -1 if [element] is not found.
+   */
+  static int lastIndexOf(List a, Object element, int startIndex) {
+    if (startIndex < 0) {
+      return -1;
+    }
+    if (startIndex >= a.length) {
+      startIndex = a.length - 1;
+    }
+    for (int i = startIndex; i >= 0; i--) {
+      if (a[i] == element) {
+        return i;
+      }
+    }
+    return -1;
+  }
+
+  /**
+   * Returns a sub list copy of this list, from [start] to
+   * [end] ([end] not inclusive).
+   * Returns an empty list if [length] is 0.
+   * It is an error if indices are not valid for the list, or
+   * if [end] is before [start].
+   */
+  static List getRange(List a, int start, int end, List accumulator) {
+    if (start < 0) throw new RangeError.value(start);
+    if (end < start) throw new RangeError.value(end);
+    if (end > a.length) throw new RangeError.value(end);
+    for (int i = start; i < end; i++) {
+      accumulator.add(a[i]);
+    }
+    return accumulator;
+  }
+}
+
+/**
+ * For accessing underlying node lists, for dart:js interop.
+ */
+abstract class NodeListWrapper {
+  List<Node> get rawList;
+}
diff --git a/sdk_nnbd/lib/html/html_common/metadata.dart b/sdk_nnbd/lib/html/html_common/metadata.dart
new file mode 100644
index 0000000..b5542dc
--- /dev/null
+++ b/sdk_nnbd/lib/html/html_common/metadata.dart
@@ -0,0 +1,71 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library metadata;
+
+/**
+ * An annotation used to mark a feature as only being supported by a subset
+ * of the browsers that Dart supports by default.
+ *
+ * If an API is not annotated with [SupportedBrowser] then it is assumed to
+ * work on all browsers Dart supports.
+ */
+class SupportedBrowser {
+  static const String CHROME = "Chrome";
+  static const String FIREFOX = "Firefox";
+  static const String IE = "Internet Explorer";
+  static const String OPERA = "Opera";
+  static const String SAFARI = "Safari";
+
+  /// The name of the browser.
+  final String browserName;
+
+  /// The minimum version of the browser that supports the feature, or null
+  /// if supported on all versions.
+  final String minimumVersion;
+
+  const SupportedBrowser(this.browserName, [this.minimumVersion]);
+}
+
+/**
+ * An annotation used to mark an API as being experimental.
+ *
+ * An API is considered to be experimental if it is still going through the
+ * process of stabilizing and is subject to change or removal.
+ *
+ * See also:
+ *
+ * * [W3C recommendation](http://en.wikipedia.org/wiki/W3C_recommendation)
+ */
+class Experimental {
+  const Experimental();
+}
+
+/**
+ * Annotation that specifies that a member is editable through generate files.
+ *
+ * This is used for API generation.
+ *
+ * [name] should be formatted as `interface.member`.
+ */
+class DomName {
+  final String name;
+  const DomName(this.name);
+}
+
+/**
+ * Metadata that specifies that that member is editable through generated
+ * files.
+ */
+class DocsEditable {
+  const DocsEditable();
+}
+
+/**
+ * Annotation that indicates that an API is not expected to change but has
+ * not undergone enough testing to be considered stable.
+ */
+class Unstable {
+  const Unstable();
+}
diff --git a/sdk_nnbd/lib/indexed_db/dart2js/indexed_db_dart2js.dart b/sdk_nnbd/lib/indexed_db/dart2js/indexed_db_dart2js.dart
new file mode 100644
index 0000000..b664b7d
--- /dev/null
+++ b/sdk_nnbd/lib/indexed_db/dart2js/indexed_db_dart2js.dart
@@ -0,0 +1,1295 @@
+/**
+ * A client-side key-value store with support for indexes.
+ *
+ * Many browsers support IndexedDB&mdash;a web standard for
+ * an indexed database.
+ * By storing data on the client in an IndexedDB,
+ * a web app gets some advantages, such as faster performance and persistence.
+ * To find out which browsers support IndexedDB,
+ * refer to [Can I Use?](http://caniuse.com/#feat=indexeddb)
+ *
+ * In IndexedDB, each record is identified by a unique index or key,
+ * making data retrieval speedy.
+ * You can store structured data,
+ * such as images, arrays, and maps using IndexedDB.
+ * The standard does not specify size limits for individual data items
+ * or for the database itself, but browsers may impose storage limits.
+ *
+ * ## Using indexed_db
+ *
+ * The classes in this library provide an interface
+ * to the browser's IndexedDB, if it has one.
+ * To use this library in your code:
+ *
+ *     import 'dart:indexed_db';
+ *
+ * A web app can determine if the browser supports
+ * IndexedDB with [IdbFactory.supported]:
+ *
+ *     if (IdbFactory.supported)
+ *       // Use indexeddb.
+ *     else
+ *       // Find an alternative.
+ *
+ * Access to the browser's IndexedDB is provided by the app's top-level
+ * [Window] object, which your code can refer to with `window.indexedDB`.
+ * So, for example,
+ * here's how to use window.indexedDB to open a database:
+ *
+ *     Future open() {
+ *       return window.indexedDB.open('myIndexedDB',
+ *           version: 1,
+ *           onUpgradeNeeded: _initializeDatabase)
+ *         .then(_loadFromDB);
+ *     }
+ *     void _initializeDatabase(VersionChangeEvent e) {
+ *       ...
+ *     }
+ *     Future _loadFromDB(Database db) {
+ *       ...
+ *     }
+ *
+ *
+ * All data in an IndexedDB is stored within an [ObjectStore].
+ * To manipulate the database use [Transaction]s.
+ *
+ * ## Other resources
+ *
+ * Other options for client-side data storage include:
+ *
+ * * [Window.localStorage]&mdash;a
+ * basic mechanism that stores data as a [Map],
+ * and where both the keys and the values are strings.
+ *
+ * * [dart:web_sql]&mdash;a database that can be queried with SQL.
+ * 
+ * For a tutorial about using the indexed_db library with Dart,
+ * check out
+ * [Use IndexedDB](http://www.dartlang.org/docs/tutorials/indexeddb/).
+ *
+ * MDN provides [API
+ * documentation](https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API).
+ *
+ * {@category Web}
+ */
+library dart.dom.indexed_db;
+
+import 'dart:async';
+import 'dart:html';
+import 'dart:html_common';
+import 'dart:_native_typed_data';
+import 'dart:typed_data';
+import 'dart:_js_helper' show Creates, Returns, JSName, Native;
+import 'dart:_foreign_helper' show JS;
+import 'dart:_interceptors' show Interceptor, JSExtendableArray;
+import 'dart:_js_helper' show convertDartClosureToJS;
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// DO NOT EDIT - unless you are editing documentation as per:
+// https://code.google.com/p/dart/wiki/ContributingHTMLDocumentation
+// Auto-generated dart:svg library.
+
+class _KeyRangeFactoryProvider {
+  static KeyRange createKeyRange_only(/*Key*/ value) =>
+      _only(_class(), _translateKey(value));
+
+  static KeyRange createKeyRange_lowerBound(
+          /*Key*/ bound,
+          [bool open = false]) =>
+      _lowerBound(_class(), _translateKey(bound), open);
+
+  static KeyRange createKeyRange_upperBound(
+          /*Key*/ bound,
+          [bool open = false]) =>
+      _upperBound(_class(), _translateKey(bound), open);
+
+  static KeyRange createKeyRange_bound(/*Key*/ lower, /*Key*/ upper,
+          [bool lowerOpen = false, bool upperOpen = false]) =>
+      _bound(_class(), _translateKey(lower), _translateKey(upper), lowerOpen,
+          upperOpen);
+
+  static var _cachedClass;
+
+  static _class() {
+    if (_cachedClass != null) return _cachedClass;
+    return _cachedClass = _uncachedClass();
+  }
+
+  static _uncachedClass() =>
+      JS('var', '''window.webkitIDBKeyRange || window.mozIDBKeyRange ||
+          window.msIDBKeyRange || window.IDBKeyRange''');
+
+  static _translateKey(idbkey) => idbkey; // TODO: fixme.
+
+  static KeyRange _only(cls, value) => JS('KeyRange', '#.only(#)', cls, value);
+
+  static KeyRange _lowerBound(cls, bound, open) =>
+      JS('KeyRange', '#.lowerBound(#, #)', cls, bound, open);
+
+  static KeyRange _upperBound(cls, bound, open) =>
+      JS('KeyRange', '#.upperBound(#, #)', cls, bound, open);
+
+  static KeyRange _bound(cls, lower, upper, lowerOpen, upperOpen) => JS(
+      'KeyRange',
+      '#.bound(#, #, #, #)',
+      cls,
+      lower,
+      upper,
+      lowerOpen,
+      upperOpen);
+}
+
+// Conversions for IDBKey.
+//
+// Per http://www.w3.org/TR/IndexedDB/#key-construct
+//
+// "A value is said to be a valid key if it is one of the following types: Array
+// JavaScript objects [ECMA-262], DOMString [WEBIDL], Date [ECMA-262] or float
+// [WEBIDL]. However Arrays are only valid keys if every item in the array is
+// defined and is a valid key (i.e. sparse arrays can not be valid keys) and if
+// the Array doesn't directly or indirectly contain itself. Any non-numeric
+// properties are ignored, and thus does not affect whether the Array is a valid
+// key. Additionally, if the value is of type float, it is only a valid key if
+// it is not NaN, and if the value is of type Date it is only a valid key if its
+// [[PrimitiveValue]] internal property, as defined by [ECMA-262], is not NaN."
+
+// What is required is to ensure that an Lists in the key are actually
+// JavaScript arrays, and any Dates are JavaScript Dates.
+
+/**
+ * Converts a native IDBKey into a Dart object.
+ *
+ * May return the original input.  May mutate the original input (but will be
+ * idempotent if mutation occurs).  It is assumed that this conversion happens
+ * on native IDBKeys on all paths that return IDBKeys from native DOM calls.
+ *
+ * If necessary, JavaScript Dates are converted into Dart Dates.
+ */
+_convertNativeToDart_IDBKey(nativeKey) {
+  containsDate(object) {
+    if (isJavaScriptDate(object)) return true;
+    if (object is List) {
+      for (int i = 0; i < object.length; i++) {
+        if (containsDate(object[i])) return true;
+      }
+    }
+    return false; // number, string.
+  }
+
+  if (containsDate(nativeKey)) {
+    throw new UnimplementedError('Key containing DateTime');
+  }
+  // TODO: Cache conversion somewhere?
+  return nativeKey;
+}
+
+/**
+ * Converts a Dart object into a valid IDBKey.
+ *
+ * May return the original input.  Does not mutate input.
+ *
+ * If necessary, [dartKey] may be copied to ensure all lists are converted into
+ * JavaScript Arrays and Dart Dates into JavaScript Dates.
+ */
+_convertDartToNative_IDBKey(dartKey) {
+  // TODO: Implement.
+  return dartKey;
+}
+
+/// May modify original.  If so, action is idempotent.
+_convertNativeToDart_IDBAny(object) {
+  return convertNativeToDart_AcceptStructuredClone(object, mustCopy: false);
+}
+
+// TODO(sra): Add DateTime.
+const String _idbKey = 'JSExtendableArray|=Object|num|String';
+const _annotation_Creates_IDBKey = const Creates(_idbKey);
+const _annotation_Returns_IDBKey = const Returns(_idbKey);
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("IDBCursor")
+class Cursor extends Interceptor {
+  Future delete() {
+    try {
+      return _completeRequest(_delete());
+    } catch (e, stacktrace) {
+      return new Future.error(e, stacktrace);
+    }
+  }
+
+  Future update(value) {
+    try {
+      return _completeRequest(_update(value));
+    } catch (e, stacktrace) {
+      return new Future.error(e, stacktrace);
+    }
+  }
+
+  @JSName('continue')
+  void next([Object key]) {
+    if (key == null) {
+      JS('void', '#.continue()', this);
+    } else {
+      JS('void', '#.continue(#)', this, key);
+    }
+  }
+
+  // To suppress missing implicit constructor warnings.
+  factory Cursor._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final String direction;
+
+  @_annotation_Creates_IDBKey
+  @_annotation_Returns_IDBKey
+  final Object key;
+
+  @_annotation_Creates_IDBKey
+  @_annotation_Returns_IDBKey
+  final Object primaryKey;
+
+  @Creates('Null')
+  @Returns('ObjectStore|Index|Null')
+  final Object source;
+
+  void advance(int count) native;
+
+  void continuePrimaryKey(Object key, Object primaryKey) native;
+
+  @JSName('delete')
+  Request _delete() native;
+
+  Request _update(/*any*/ value) {
+    var value_1 = convertDartToNative_SerializedScriptValue(value);
+    return _update_1(value_1);
+  }
+
+  @JSName('update')
+  Request _update_1(value) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("IDBCursorWithValue")
+class CursorWithValue extends Cursor {
+  // To suppress missing implicit constructor warnings.
+  factory CursorWithValue._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  dynamic get value => _convertNativeToDart_IDBAny(this._get_value);
+  @JSName('value')
+  @annotation_Creates_SerializedScriptValue
+  @annotation_Returns_SerializedScriptValue
+  final dynamic _get_value;
+}
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/**
+ * An indexed database object for storing client-side data
+ * in web apps.
+ */
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.FIREFOX, '15')
+@SupportedBrowser(SupportedBrowser.IE, '10')
+@Unstable()
+@Native("IDBDatabase")
+class Database extends EventTarget {
+  ObjectStore createObjectStore(String name, {keyPath, bool autoIncrement}) {
+    var options = {};
+    if (keyPath != null) {
+      options['keyPath'] = keyPath;
+    }
+    if (autoIncrement != null) {
+      options['autoIncrement'] = autoIncrement;
+    }
+
+    return _createObjectStore(name, options);
+  }
+
+  Transaction transaction(storeName_OR_storeNames, String mode) {
+    if (mode != 'readonly' && mode != 'readwrite') {
+      throw new ArgumentError(mode);
+    }
+
+    // TODO(sra): Ensure storeName_OR_storeNames is a string or List<String>,
+    // and copy to JavaScript array if necessary.
+
+    // Try and create a transaction with a string mode.  Browsers that expect a
+    // numeric mode tend to convert the string into a number.  This fails
+    // silently, resulting in zero ('readonly').
+    return _transaction(storeName_OR_storeNames, mode);
+  }
+
+  Transaction transactionStore(String storeName, String mode) {
+    if (mode != 'readonly' && mode != 'readwrite') {
+      throw new ArgumentError(mode);
+    }
+    // Try and create a transaction with a string mode.  Browsers that expect a
+    // numeric mode tend to convert the string into a number.  This fails
+    // silently, resulting in zero ('readonly').
+    return _transaction(storeName, mode);
+  }
+
+  Transaction transactionList(List<String> storeNames, String mode) {
+    if (mode != 'readonly' && mode != 'readwrite') {
+      throw new ArgumentError(mode);
+    }
+    List storeNames_1 = convertDartToNative_StringArray(storeNames);
+    return _transaction(storeNames_1, mode);
+  }
+
+  Transaction transactionStores(DomStringList storeNames, String mode) {
+    if (mode != 'readonly' && mode != 'readwrite') {
+      throw new ArgumentError(mode);
+    }
+    return _transaction(storeNames, mode);
+  }
+
+  @JSName('transaction')
+  Transaction _transaction(stores, mode) native;
+
+  // To suppress missing implicit constructor warnings.
+  factory Database._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  /**
+   * Static factory designed to expose `abort` events to event
+   * handlers that are not necessarily instances of [Database].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<Event> abortEvent =
+      const EventStreamProvider<Event>('abort');
+
+  /**
+   * Static factory designed to expose `close` events to event
+   * handlers that are not necessarily instances of [Database].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<Event> closeEvent =
+      const EventStreamProvider<Event>('close');
+
+  /**
+   * Static factory designed to expose `error` events to event
+   * handlers that are not necessarily instances of [Database].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<Event> errorEvent =
+      const EventStreamProvider<Event>('error');
+
+  /**
+   * Static factory designed to expose `versionchange` events to event
+   * handlers that are not necessarily instances of [Database].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<VersionChangeEvent> versionChangeEvent =
+      const EventStreamProvider<VersionChangeEvent>('versionchange');
+
+  final String name;
+
+  @Returns('DomStringList|Null')
+  @Creates('DomStringList')
+  final List<String> objectStoreNames;
+
+  @Creates('int|String|Null')
+  @Returns('int|String|Null')
+  final int version;
+
+  void close() native;
+
+  ObjectStore _createObjectStore(String name, [Map options]) {
+    if (options != null) {
+      var options_1 = convertDartToNative_Dictionary(options);
+      return _createObjectStore_1(name, options_1);
+    }
+    return _createObjectStore_2(name);
+  }
+
+  @JSName('createObjectStore')
+  ObjectStore _createObjectStore_1(name, options) native;
+  @JSName('createObjectStore')
+  ObjectStore _createObjectStore_2(name) native;
+
+  void deleteObjectStore(String name) native;
+
+  /// Stream of `abort` events handled by this [Database].
+  Stream<Event> get onAbort => abortEvent.forTarget(this);
+
+  /// Stream of `close` events handled by this [Database].
+  Stream<Event> get onClose => closeEvent.forTarget(this);
+
+  /// Stream of `error` events handled by this [Database].
+  Stream<Event> get onError => errorEvent.forTarget(this);
+
+  /// Stream of `versionchange` events handled by this [Database].
+  Stream<VersionChangeEvent> get onVersionChange =>
+      versionChangeEvent.forTarget(this);
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+typedef void ObserverCallback(ObserverChanges changes);
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.FIREFOX, '15')
+@SupportedBrowser(SupportedBrowser.IE, '10')
+@Unstable()
+@Native("IDBFactory")
+class IdbFactory extends Interceptor {
+  /**
+   * Checks to see if Indexed DB is supported on the current platform.
+   */
+  static bool get supported {
+    return JS(
+        'bool',
+        '!!(window.indexedDB || '
+            'window.webkitIndexedDB || '
+            'window.mozIndexedDB)');
+  }
+
+  Future<Database> open(String name,
+      {int version,
+      void onUpgradeNeeded(VersionChangeEvent event),
+      void onBlocked(Event event)}) {
+    if ((version == null) != (onUpgradeNeeded == null)) {
+      return new Future.error(new ArgumentError(
+          'version and onUpgradeNeeded must be specified together'));
+    }
+    try {
+      var request;
+      if (version != null) {
+        request = _open(name, version);
+      } else {
+        request = _open(name);
+      }
+
+      if (onUpgradeNeeded != null) {
+        request.onUpgradeNeeded.listen(onUpgradeNeeded);
+      }
+      if (onBlocked != null) {
+        request.onBlocked.listen(onBlocked);
+      }
+      return _completeRequest(request);
+    } catch (e, stacktrace) {
+      return new Future.error(e, stacktrace);
+    }
+  }
+
+  Future<IdbFactory> deleteDatabase(String name, {void onBlocked(Event e)}) {
+    try {
+      var request = _deleteDatabase(name);
+
+      if (onBlocked != null) {
+        request.onBlocked.listen(onBlocked);
+      }
+      var completer = new Completer<IdbFactory>.sync();
+      request.onSuccess.listen((e) {
+        completer.complete(this);
+      });
+      request.onError.listen(completer.completeError);
+      return completer.future;
+    } catch (e, stacktrace) {
+      return new Future.error(e, stacktrace);
+    }
+  }
+
+  /**
+   * Checks to see if getDatabaseNames is supported by the current platform.
+   * TODO(terry): Should be able to always return false?
+   */
+  bool get supportsDatabaseNames {
+    return supported &&
+        JS('bool', '!!(#.getDatabaseNames || #.webkitGetDatabaseNames)', this,
+            this);
+  }
+
+  // To suppress missing implicit constructor warnings.
+  factory IdbFactory._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  int cmp(Object first, Object second) native;
+
+  @JSName('deleteDatabase')
+  OpenDBRequest _deleteDatabase(String name) native;
+
+  @JSName('open')
+  @Returns('Request')
+  @Creates('Request')
+  @Creates('Database')
+  OpenDBRequest _open(String name, [int version]) native;
+}
+
+/**
+ * Ties a request to a completer, so the completer is completed when it succeeds
+ * and errors out when the request errors.
+ */
+Future<T> _completeRequest<T>(Request request) {
+  var completer = new Completer<T>.sync();
+  // TODO: make sure that completer.complete is synchronous as transactions
+  // may be committed if the result is not processed immediately.
+  request.onSuccess.listen((e) {
+    T result = request.result;
+    completer.complete(result);
+  });
+  request.onError.listen(completer.completeError);
+  return completer.future;
+}
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("IDBIndex")
+class Index extends Interceptor {
+  Future<int> count([key_OR_range]) {
+    try {
+      var request = _count(key_OR_range);
+      return _completeRequest(request);
+    } catch (e, stacktrace) {
+      return new Future.error(e, stacktrace);
+    }
+  }
+
+  Future get(key) {
+    try {
+      var request = _get(key);
+
+      return _completeRequest(request);
+    } catch (e, stacktrace) {
+      return new Future.error(e, stacktrace);
+    }
+  }
+
+  Future getKey(key) {
+    try {
+      var request = _getKey(key);
+
+      return _completeRequest(request);
+    } catch (e, stacktrace) {
+      return new Future.error(e, stacktrace);
+    }
+  }
+
+  /**
+   * Creates a stream of cursors over the records in this object store.
+   *
+   * See also:
+   *
+   * * [ObjectStore.openCursor]
+   */
+  Stream<CursorWithValue> openCursor(
+      {key, KeyRange range, String direction, bool autoAdvance}) {
+    var key_OR_range = null;
+    if (key != null) {
+      if (range != null) {
+        throw new ArgumentError('Cannot specify both key and range.');
+      }
+      key_OR_range = key;
+    } else {
+      key_OR_range = range;
+    }
+    var request;
+    if (direction == null) {
+      // FIXME: Passing in "next" should be unnecessary.
+      request = _openCursor(key_OR_range, "next");
+    } else {
+      request = _openCursor(key_OR_range, direction);
+    }
+    return ObjectStore._cursorStreamFromResult(request, autoAdvance);
+  }
+
+  /**
+   * Creates a stream of cursors over the records in this object store.
+   *
+   * See also:
+   *
+   * * [ObjectStore.openCursor]
+   */
+  Stream<Cursor> openKeyCursor(
+      {key, KeyRange range, String direction, bool autoAdvance}) {
+    var key_OR_range = null;
+    if (key != null) {
+      if (range != null) {
+        throw new ArgumentError('Cannot specify both key and range.');
+      }
+      key_OR_range = key;
+    } else {
+      key_OR_range = range;
+    }
+    var request;
+    if (direction == null) {
+      // FIXME: Passing in "next" should be unnecessary.
+      request = _openKeyCursor(key_OR_range, "next");
+    } else {
+      request = _openKeyCursor(key_OR_range, direction);
+    }
+    return ObjectStore._cursorStreamFromResult(request, autoAdvance);
+  }
+
+  // To suppress missing implicit constructor warnings.
+  factory Index._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  @annotation_Creates_SerializedScriptValue
+  final Object keyPath;
+
+  final bool multiEntry;
+
+  String name;
+
+  final ObjectStore objectStore;
+
+  final bool unique;
+
+  @JSName('count')
+  Request _count(Object key) native;
+
+  @JSName('get')
+  @Returns('Request')
+  @Creates('Request')
+  @annotation_Creates_SerializedScriptValue
+  Request _get(Object key) native;
+
+  Request getAll(Object query, [int count]) native;
+
+  Request getAllKeys(Object query, [int count]) native;
+
+  @JSName('getKey')
+  @Returns('Request')
+  @Creates('Request')
+  @annotation_Creates_SerializedScriptValue
+  @Creates('ObjectStore')
+  Request _getKey(Object key) native;
+
+  @JSName('openCursor')
+  @Returns('Request')
+  @Creates('Request')
+  @Creates('Cursor')
+  Request _openCursor(Object range, [String direction]) native;
+
+  @JSName('openKeyCursor')
+  @Returns('Request')
+  @Creates('Request')
+  @Creates('Cursor')
+  Request _openKeyCursor(Object range, [String direction]) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("IDBKeyRange")
+class KeyRange extends Interceptor {
+  factory KeyRange.only(/*Key*/ value) =>
+      _KeyRangeFactoryProvider.createKeyRange_only(value);
+
+  factory KeyRange.lowerBound(/*Key*/ bound, [bool open = false]) =>
+      _KeyRangeFactoryProvider.createKeyRange_lowerBound(bound, open);
+
+  factory KeyRange.upperBound(/*Key*/ bound, [bool open = false]) =>
+      _KeyRangeFactoryProvider.createKeyRange_upperBound(bound, open);
+
+  factory KeyRange.bound(/*Key*/ lower, /*Key*/ upper,
+          [bool lowerOpen = false, bool upperOpen = false]) =>
+      _KeyRangeFactoryProvider.createKeyRange_bound(
+          lower, upper, lowerOpen, upperOpen);
+
+  // To suppress missing implicit constructor warnings.
+  factory KeyRange._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  @annotation_Creates_SerializedScriptValue
+  final Object lower;
+
+  final bool lowerOpen;
+
+  @annotation_Creates_SerializedScriptValue
+  final Object upper;
+
+  final bool upperOpen;
+
+  @JSName('bound')
+  static KeyRange bound_(Object lower, Object upper,
+      [bool lowerOpen, bool upperOpen]) native;
+
+  bool includes(Object key) native;
+
+  @JSName('lowerBound')
+  static KeyRange lowerBound_(Object bound, [bool open]) native;
+
+  @JSName('only')
+  static KeyRange only_(Object value) native;
+
+  @JSName('upperBound')
+  static KeyRange upperBound_(Object bound, [bool open]) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("IDBObjectStore")
+class ObjectStore extends Interceptor {
+  Future add(value, [key]) {
+    try {
+      var request;
+      if (key != null) {
+        request = _add(value, key);
+      } else {
+        request = _add(value);
+      }
+      return _completeRequest(request);
+    } catch (e, stacktrace) {
+      return new Future.error(e, stacktrace);
+    }
+  }
+
+  Future clear() {
+    try {
+      return _completeRequest(_clear());
+    } catch (e, stacktrace) {
+      return new Future.error(e, stacktrace);
+    }
+  }
+
+  Future delete(key_OR_keyRange) {
+    try {
+      return _completeRequest(_delete(key_OR_keyRange));
+    } catch (e, stacktrace) {
+      return new Future.error(e, stacktrace);
+    }
+  }
+
+  Future<int> count([key_OR_range]) {
+    try {
+      var request = _count(key_OR_range);
+      return _completeRequest(request);
+    } catch (e, stacktrace) {
+      return new Future.error(e, stacktrace);
+    }
+  }
+
+  Future put(value, [key]) {
+    try {
+      var request;
+      if (key != null) {
+        request = _put(value, key);
+      } else {
+        request = _put(value);
+      }
+      return _completeRequest(request);
+    } catch (e, stacktrace) {
+      return new Future.error(e, stacktrace);
+    }
+  }
+
+  Future getObject(key) {
+    try {
+      var request = _get(key);
+
+      return _completeRequest(request);
+    } catch (e, stacktrace) {
+      return new Future.error(e, stacktrace);
+    }
+  }
+
+  /**
+   * Creates a stream of cursors over the records in this object store.
+   *
+   * **The stream must be manually advanced by calling [Cursor.next] after
+   * each item or by specifying autoAdvance to be true.**
+   *
+   *     var cursors = objectStore.openCursor().listen(
+   *       (cursor) {
+   *         // ...some processing with the cursor
+   *         cursor.next(); // advance onto the next cursor.
+   *       },
+   *       onDone: () {
+   *         // called when there are no more cursors.
+   *         print('all done!');
+   *       });
+   *
+   * Asynchronous operations which are not related to the current transaction
+   * will cause the transaction to automatically be committed-- all processing
+   * must be done synchronously unless they are additional async requests to
+   * the current transaction.
+   */
+  Stream<CursorWithValue> openCursor(
+      {key, KeyRange range, String direction, bool autoAdvance}) {
+    var key_OR_range = null;
+    if (key != null) {
+      if (range != null) {
+        throw new ArgumentError('Cannot specify both key and range.');
+      }
+      key_OR_range = key;
+    } else {
+      key_OR_range = range;
+    }
+
+    // TODO: try/catch this and return a stream with an immediate error.
+    var request;
+    if (direction == null) {
+      request = _openCursor(key_OR_range);
+    } else {
+      request = _openCursor(key_OR_range, direction);
+    }
+    return _cursorStreamFromResult(request, autoAdvance);
+  }
+
+  Index createIndex(String name, keyPath, {bool unique, bool multiEntry}) {
+    var options = {};
+    if (unique != null) {
+      options['unique'] = unique;
+    }
+    if (multiEntry != null) {
+      options['multiEntry'] = multiEntry;
+    }
+
+    return _createIndex(name, keyPath, options);
+  }
+
+  // To suppress missing implicit constructor warnings.
+  factory ObjectStore._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final bool autoIncrement;
+
+  @Returns('DomStringList|Null')
+  @Creates('DomStringList')
+  final List<String> indexNames;
+
+  @annotation_Creates_SerializedScriptValue
+  final Object keyPath;
+
+  String name;
+
+  final Transaction transaction;
+
+  @Returns('Request')
+  @Creates('Request')
+  @_annotation_Creates_IDBKey
+  Request _add(/*any*/ value, [/*any*/ key]) {
+    if (key != null) {
+      var value_1 = convertDartToNative_SerializedScriptValue(value);
+      var key_2 = convertDartToNative_SerializedScriptValue(key);
+      return _add_1(value_1, key_2);
+    }
+    var value_1 = convertDartToNative_SerializedScriptValue(value);
+    return _add_2(value_1);
+  }
+
+  @JSName('add')
+  @Returns('Request')
+  @Creates('Request')
+  @_annotation_Creates_IDBKey
+  Request _add_1(value, key) native;
+  @JSName('add')
+  @Returns('Request')
+  @Creates('Request')
+  @_annotation_Creates_IDBKey
+  Request _add_2(value) native;
+
+  @JSName('clear')
+  Request _clear() native;
+
+  @JSName('count')
+  Request _count(Object key) native;
+
+  Index _createIndex(String name, Object keyPath, [Map options]) {
+    if (options != null) {
+      var options_1 = convertDartToNative_Dictionary(options);
+      return _createIndex_1(name, keyPath, options_1);
+    }
+    return _createIndex_2(name, keyPath);
+  }
+
+  @JSName('createIndex')
+  Index _createIndex_1(name, keyPath, options) native;
+  @JSName('createIndex')
+  Index _createIndex_2(name, keyPath) native;
+
+  @JSName('delete')
+  Request _delete(Object key) native;
+
+  void deleteIndex(String name) native;
+
+  @JSName('get')
+  @Returns('Request')
+  @Creates('Request')
+  @annotation_Creates_SerializedScriptValue
+  Request _get(Object key) native;
+
+  Request getAll(Object query, [int count]) native;
+
+  Request getAllKeys(Object query, [int count]) native;
+
+  Request getKey(Object key) native;
+
+  Index index(String name) native;
+
+  @JSName('openCursor')
+  @Returns('Request')
+  @Creates('Request')
+  @Creates('Cursor')
+  Request _openCursor(Object range, [String direction]) native;
+
+  Request openKeyCursor(Object range, [String direction]) native;
+
+  @Returns('Request')
+  @Creates('Request')
+  @_annotation_Creates_IDBKey
+  Request _put(/*any*/ value, [/*any*/ key]) {
+    if (key != null) {
+      var value_1 = convertDartToNative_SerializedScriptValue(value);
+      var key_2 = convertDartToNative_SerializedScriptValue(key);
+      return _put_1(value_1, key_2);
+    }
+    var value_1 = convertDartToNative_SerializedScriptValue(value);
+    return _put_2(value_1);
+  }
+
+  @JSName('put')
+  @Returns('Request')
+  @Creates('Request')
+  @_annotation_Creates_IDBKey
+  Request _put_1(value, key) native;
+  @JSName('put')
+  @Returns('Request')
+  @Creates('Request')
+  @_annotation_Creates_IDBKey
+  Request _put_2(value) native;
+
+  /**
+   * Helper for iterating over cursors in a request.
+   */
+  static Stream<T> _cursorStreamFromResult<T extends Cursor>(
+      Request request, bool autoAdvance) {
+    // TODO: need to guarantee that the controller provides the values
+    // immediately as waiting until the next tick will cause the transaction to
+    // close.
+    var controller = new StreamController<T>(sync: true);
+
+    //TODO: Report stacktrace once issue 4061 is resolved.
+    request.onError.listen(controller.addError);
+
+    request.onSuccess.listen((e) {
+      T cursor = request.result as dynamic;
+      if (cursor == null) {
+        controller.close();
+      } else {
+        controller.add(cursor);
+        if (autoAdvance == true && controller.hasListener) {
+          cursor.next();
+        }
+      }
+    });
+    return controller.stream;
+  }
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("IDBObservation")
+class Observation extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory Observation._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final Object key;
+
+  final String type;
+
+  final Object value;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("IDBObserver")
+class Observer extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory Observer._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory Observer(ObserverCallback callback) {
+    var callback_1 = convertDartClosureToJS(callback, 1);
+    return Observer._create_1(callback_1);
+  }
+  static Observer _create_1(callback) =>
+      JS('Observer', 'new IDBObserver(#)', callback);
+
+  void observe(Database db, Transaction tx, Map options) {
+    var options_1 = convertDartToNative_Dictionary(options);
+    _observe_1(db, tx, options_1);
+    return;
+  }
+
+  @JSName('observe')
+  void _observe_1(Database db, Transaction tx, options) native;
+
+  void unobserve(Database db) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("IDBObserverChanges")
+class ObserverChanges extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory ObserverChanges._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final Database database;
+
+  final Object records;
+
+  final Transaction transaction;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("IDBOpenDBRequest,IDBVersionChangeRequest")
+class OpenDBRequest extends Request {
+  // To suppress missing implicit constructor warnings.
+  factory OpenDBRequest._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  /**
+   * Static factory designed to expose `blocked` events to event
+   * handlers that are not necessarily instances of [OpenDBRequest].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<Event> blockedEvent =
+      const EventStreamProvider<Event>('blocked');
+
+  /**
+   * Static factory designed to expose `upgradeneeded` events to event
+   * handlers that are not necessarily instances of [OpenDBRequest].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<VersionChangeEvent> upgradeNeededEvent =
+      const EventStreamProvider<VersionChangeEvent>('upgradeneeded');
+
+  /// Stream of `blocked` events handled by this [OpenDBRequest].
+  Stream<Event> get onBlocked => blockedEvent.forTarget(this);
+
+  /// Stream of `upgradeneeded` events handled by this [OpenDBRequest].
+  Stream<VersionChangeEvent> get onUpgradeNeeded =>
+      upgradeNeededEvent.forTarget(this);
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("IDBRequest")
+class Request extends EventTarget {
+  // To suppress missing implicit constructor warnings.
+  factory Request._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  /**
+   * Static factory designed to expose `error` events to event
+   * handlers that are not necessarily instances of [Request].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<Event> errorEvent =
+      const EventStreamProvider<Event>('error');
+
+  /**
+   * Static factory designed to expose `success` events to event
+   * handlers that are not necessarily instances of [Request].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<Event> successEvent =
+      const EventStreamProvider<Event>('success');
+
+  final DomException error;
+
+  final String readyState;
+
+  dynamic get result => _convertNativeToDart_IDBAny(this._get_result);
+  @JSName('result')
+  @Creates('Null')
+  final dynamic _get_result;
+
+  @Creates('Null')
+  final Object source;
+
+  final Transaction transaction;
+
+  /// Stream of `error` events handled by this [Request].
+  Stream<Event> get onError => errorEvent.forTarget(this);
+
+  /// Stream of `success` events handled by this [Request].
+  Stream<Event> get onSuccess => successEvent.forTarget(this);
+}
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("IDBTransaction")
+class Transaction extends EventTarget {
+  /**
+   * Provides a Future which will be completed once the transaction has
+   * completed.
+   *
+   * The future will error if an error occurrs on the transaction or if the
+   * transaction is aborted.
+   */
+  Future<Database> get completed {
+    var completer = new Completer<Database>();
+
+    this.onComplete.first.then((_) {
+      completer.complete(db);
+    });
+
+    this.onError.first.then((e) {
+      completer.completeError(e);
+    });
+
+    this.onAbort.first.then((e) {
+      // Avoid completing twice if an error occurs.
+      if (!completer.isCompleted) {
+        completer.completeError(e);
+      }
+    });
+
+    return completer.future;
+  }
+
+  // To suppress missing implicit constructor warnings.
+  factory Transaction._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  /**
+   * Static factory designed to expose `abort` events to event
+   * handlers that are not necessarily instances of [Transaction].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<Event> abortEvent =
+      const EventStreamProvider<Event>('abort');
+
+  /**
+   * Static factory designed to expose `complete` events to event
+   * handlers that are not necessarily instances of [Transaction].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<Event> completeEvent =
+      const EventStreamProvider<Event>('complete');
+
+  /**
+   * Static factory designed to expose `error` events to event
+   * handlers that are not necessarily instances of [Transaction].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<Event> errorEvent =
+      const EventStreamProvider<Event>('error');
+
+  final Database db;
+
+  final DomException error;
+
+  final String mode;
+
+  @Returns('DomStringList|Null')
+  @Creates('DomStringList')
+  final List<String> objectStoreNames;
+
+  void abort() native;
+
+  ObjectStore objectStore(String name) native;
+
+  /// Stream of `abort` events handled by this [Transaction].
+  Stream<Event> get onAbort => abortEvent.forTarget(this);
+
+  /// Stream of `complete` events handled by this [Transaction].
+  Stream<Event> get onComplete => completeEvent.forTarget(this);
+
+  /// Stream of `error` events handled by this [Transaction].
+  Stream<Event> get onError => errorEvent.forTarget(this);
+}
+// 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.
+
+@Unstable()
+@Native("IDBVersionChangeEvent")
+class VersionChangeEvent extends Event {
+  // To suppress missing implicit constructor warnings.
+  factory VersionChangeEvent._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory VersionChangeEvent(String type, [Map eventInitDict]) {
+    if (eventInitDict != null) {
+      var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+      return VersionChangeEvent._create_1(type, eventInitDict_1);
+    }
+    return VersionChangeEvent._create_2(type);
+  }
+  static VersionChangeEvent _create_1(type, eventInitDict) => JS(
+      'VersionChangeEvent',
+      'new IDBVersionChangeEvent(#,#)',
+      type,
+      eventInitDict);
+  static VersionChangeEvent _create_2(type) =>
+      JS('VersionChangeEvent', 'new IDBVersionChangeEvent(#)', type);
+
+  final String dataLoss;
+
+  final String dataLossMessage;
+
+  @Creates('int|String|Null')
+  @Returns('int|String|Null')
+  final int newVersion;
+
+  @Creates('int|String|Null')
+  @Returns('int|String|Null')
+  final int oldVersion;
+
+  @JSName('target')
+  final OpenDBRequest target;
+}
diff --git a/sdk_nnbd/lib/internal/async_cast.dart b/sdk_nnbd/lib/internal/async_cast.dart
new file mode 100644
index 0000000..e041ff3
--- /dev/null
+++ b/sdk_nnbd/lib/internal/async_cast.dart
@@ -0,0 +1,121 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart._internal;
+
+// Casting wrappers for asynchronous classes.
+
+class CastStream<S, T> extends Stream<T> {
+  final Stream<S> _source;
+  CastStream(this._source);
+  bool get isBroadcast => _source.isBroadcast;
+
+  StreamSubscription<T> listen(void onData(T data),
+      {Function onError, void onDone(), bool cancelOnError}) {
+    return new CastStreamSubscription<S, T>(
+        _source.listen(null, onDone: onDone, cancelOnError: cancelOnError))
+      ..onData(onData)
+      ..onError(onError);
+  }
+
+  Stream<R> cast<R>() => new CastStream<S, R>(_source);
+}
+
+class CastStreamSubscription<S, T> implements StreamSubscription<T> {
+  final StreamSubscription<S> _source;
+
+  /// Zone where listen was called.
+  final Zone _zone = Zone.current;
+
+  /// User's data handler. May be null.
+  void Function(T) _handleData;
+
+  /// Copy of _source's handleError so we can report errors in onData.
+  /// May be null.
+  Function _handleError;
+
+  CastStreamSubscription(this._source) {
+    _source.onData(_onData);
+  }
+
+  Future cancel() => _source.cancel();
+
+  void onData(void handleData(T data)) {
+    _handleData = handleData == null
+        ? null
+        : _zone.registerUnaryCallback<dynamic, T>(handleData);
+  }
+
+  void onError(Function handleError) {
+    _source.onError(handleError);
+    if (handleError == null) {
+      _handleError = null;
+    } else if (handleError is Function(Null, Null)) {
+      _handleError = _zone
+          .registerBinaryCallback<dynamic, Object, StackTrace>(handleError);
+    } else {
+      _handleError = _zone.registerUnaryCallback<dynamic, Object>(handleError);
+    }
+  }
+
+  void onDone(void handleDone()) {
+    _source.onDone(handleDone);
+  }
+
+  void _onData(S data) {
+    if (_handleData == null) return;
+    T targetData;
+    try {
+      targetData = data as T;
+    } catch (error, stack) {
+      if (_handleError == null) {
+        _zone.handleUncaughtError(error, stack);
+      } else if (_handleError is Function(Null, Null)) {
+        _zone.runBinaryGuarded(_handleError, error, stack);
+      } else {
+        _zone.runUnaryGuarded(_handleError, error);
+      }
+      return;
+    }
+    _zone.runUnaryGuarded(_handleData, targetData);
+  }
+
+  void pause([Future resumeSignal]) {
+    _source.pause(resumeSignal);
+  }
+
+  void resume() {
+    _source.resume();
+  }
+
+  bool get isPaused => _source.isPaused;
+
+  Future<E> asFuture<E>([E futureValue]) => _source.asFuture<E>(futureValue);
+}
+
+class CastStreamTransformer<SS, ST, TS, TT>
+    extends StreamTransformerBase<TS, TT> {
+  final StreamTransformer<SS, ST> _source;
+  CastStreamTransformer(this._source);
+
+  StreamTransformer<RS, RT> cast<RS, RT>() =>
+      new CastStreamTransformer<SS, ST, RS, RT>(_source);
+  Stream<TT> bind(Stream<TS> stream) =>
+      _source.bind(stream.cast<SS>()).cast<TT>();
+}
+
+class CastConverter<SS, ST, TS, TT> extends Converter<TS, TT> {
+  final Converter<SS, ST> _source;
+  CastConverter(this._source);
+
+  TT convert(TS input) => _source.convert(input as SS) as TT;
+
+  // cast is inherited from Converter.
+
+  Stream<TT> bind(Stream<TS> stream) =>
+      _source.bind(stream.cast<SS>()).cast<TT>();
+
+  Converter<RS, RT> cast<RS, RT>() =>
+      new CastConverter<SS, ST, RS, RT>(_source);
+}
diff --git a/sdk_nnbd/lib/internal/cast.dart b/sdk_nnbd/lib/internal/cast.dart
new file mode 100644
index 0000000..b3620f5
--- /dev/null
+++ b/sdk_nnbd/lib/internal/cast.dart
@@ -0,0 +1,361 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart._internal;
+
+// Casting wrappers for collection classes.
+
+abstract class _CastIterableBase<S, T> extends Iterable<T> {
+  Iterable<S> get _source;
+
+  Iterator<T> get iterator => new CastIterator<S, T>(_source.iterator);
+
+  // The following members use the default implementation on the
+  // throwing iterator. These are all operations that have no more efficient
+  // implementation than visiting every element in order,
+  // or that has no more efficient way to get the correct type (toList, toSet).
+  //
+  // * map
+  // * where
+  // * expand
+  // * forEach
+  // * reduce
+  // * fold
+  // * every
+  // * any
+  // * join
+  // * toList
+  // * toSet
+  // * skipWhile
+  // * takeWhile
+  // * firstWhere
+  // * singleWhere
+
+  int get length => _source.length;
+  bool get isEmpty => _source.isEmpty;
+  bool get isNotEmpty => _source.isNotEmpty;
+
+  Iterable<T> skip(int count) => new CastIterable<S, T>(_source.skip(count));
+  Iterable<T> take(int count) => new CastIterable<S, T>(_source.take(count));
+
+  T elementAt(int index) => _source.elementAt(index) as T;
+  T get first => _source.first as T;
+  T get last => _source.last as T;
+  T get single => _source.single as T;
+
+  bool contains(Object other) => _source.contains(other);
+
+  // Might be implemented by testing backwards from the end,
+  // so use the _source's implementation.
+  T lastWhere(bool test(T element), {T orElse()}) =>
+      _source.lastWhere((S element) => test(element as T),
+          orElse: (orElse == null) ? null : () => orElse() as S) as T;
+
+  String toString() => _source.toString();
+}
+
+class CastIterator<S, T> implements Iterator<T> {
+  Iterator<S> _source;
+  CastIterator(this._source);
+  bool moveNext() => _source.moveNext();
+  T get current => _source.current as T;
+}
+
+class CastIterable<S, T> extends _CastIterableBase<S, T> {
+  final Iterable<S> _source;
+
+  CastIterable._(this._source);
+
+  factory CastIterable(Iterable<S> source) {
+    if (source is EfficientLengthIterable<S>) {
+      return new _EfficientLengthCastIterable<S, T>(source);
+    }
+    return new CastIterable<S, T>._(source);
+  }
+
+  Iterable<R> cast<R>() => new CastIterable<S, R>(_source);
+}
+
+class _EfficientLengthCastIterable<S, T> extends CastIterable<S, T>
+    implements EfficientLengthIterable<T> {
+  _EfficientLengthCastIterable(EfficientLengthIterable<S> source)
+      : super._(source);
+}
+
+abstract class _CastListBase<S, T> extends _CastIterableBase<S, T>
+    with ListMixin<T> {
+  List<S> get _source;
+
+  // Using the default implementation from ListMixin:
+  // * reversed
+  // * shuffle
+  // * indexOf
+  // * lastIndexOf
+  // * clear
+  // * sublist
+  // * asMap
+
+  T operator [](int index) => _source[index] as T;
+
+  void operator []=(int index, T value) {
+    _source[index] = value as S;
+  }
+
+  void set length(int length) {
+    _source.length = length;
+  }
+
+  void add(T value) {
+    _source.add(value as S);
+  }
+
+  void addAll(Iterable<T> values) {
+    _source.addAll(new CastIterable<T, S>(values));
+  }
+
+  void sort([int compare(T v1, T v2)]) {
+    _source.sort(
+        compare == null ? null : (S v1, S v2) => compare(v1 as T, v2 as T));
+  }
+
+  void shuffle([Random random]) {
+    _source.shuffle(random);
+  }
+
+  void insert(int index, T element) {
+    _source.insert(index, element as S);
+  }
+
+  void insertAll(int index, Iterable<T> elements) {
+    _source.insertAll(index, new CastIterable<T, S>(elements));
+  }
+
+  void setAll(int index, Iterable<T> elements) {
+    _source.setAll(index, new CastIterable<T, S>(elements));
+  }
+
+  bool remove(Object value) => _source.remove(value);
+
+  T removeAt(int index) => _source.removeAt(index) as T;
+
+  T removeLast() => _source.removeLast() as T;
+
+  void removeWhere(bool test(T element)) {
+    _source.removeWhere((S element) => test(element as T));
+  }
+
+  void retainWhere(bool test(T element)) {
+    _source.retainWhere((S element) => test(element as T));
+  }
+
+  Iterable<T> getRange(int start, int end) =>
+      new CastIterable<S, T>(_source.getRange(start, end));
+
+  void setRange(int start, int end, Iterable<T> iterable, [int skipCount = 0]) {
+    _source.setRange(start, end, new CastIterable<T, S>(iterable), skipCount);
+  }
+
+  void removeRange(int start, int end) {
+    _source.removeRange(start, end);
+  }
+
+  void fillRange(int start, int end, [T fillValue]) {
+    _source.fillRange(start, end, fillValue as S);
+  }
+
+  void replaceRange(int start, int end, Iterable<T> replacement) {
+    _source.replaceRange(start, end, new CastIterable<T, S>(replacement));
+  }
+}
+
+class CastList<S, T> extends _CastListBase<S, T> {
+  final List<S> _source;
+  CastList(this._source);
+
+  List<R> cast<R>() => new CastList<S, R>(_source);
+}
+
+class CastSet<S, T> extends _CastIterableBase<S, T> implements Set<T> {
+  final Set<S> _source;
+
+  /// Creates a new empty set of the same *kind* as [_source],
+  /// but with `<R>` as type argument.
+  /// Used by [toSet] and [union].
+  final Set<R> Function<R>() _emptySet;
+
+  CastSet(this._source, this._emptySet);
+
+  static Set<R> _defaultEmptySet<R>() => new Set<R>();
+
+  Set<R> cast<R>() => new CastSet<S, R>(_source, _emptySet);
+  bool add(T value) => _source.add(value as S);
+
+  void addAll(Iterable<T> elements) {
+    _source.addAll(new CastIterable<T, S>(elements));
+  }
+
+  bool remove(Object object) => _source.remove(object);
+
+  void removeAll(Iterable<Object> objects) {
+    _source.removeAll(objects);
+  }
+
+  void retainAll(Iterable<Object> objects) {
+    _source.retainAll(objects);
+  }
+
+  void removeWhere(bool test(T element)) {
+    _source.removeWhere((S element) => test(element as T));
+  }
+
+  void retainWhere(bool test(T element)) {
+    _source.retainWhere((S element) => test(element as T));
+  }
+
+  bool containsAll(Iterable<Object> objects) => _source.containsAll(objects);
+
+  Set<T> intersection(Set<Object> other) {
+    if (_emptySet != null) return _conditionalAdd(other, true);
+    return new CastSet<S, T>(_source.intersection(other), null);
+  }
+
+  Set<T> difference(Set<Object> other) {
+    if (_emptySet != null) return _conditionalAdd(other, false);
+    return new CastSet<S, T>(_source.difference(other), null);
+  }
+
+  Set<T> _conditionalAdd(Set<Object> other, bool otherContains) {
+    Set<T> result = (_emptySet == null) ? new Set<T>() : _emptySet<T>();
+    for (var element in _source) {
+      T castElement = element as T;
+      if (otherContains == other.contains(castElement)) result.add(castElement);
+    }
+    return result;
+  }
+
+  Set<T> union(Set<T> other) => _clone()..addAll(other);
+
+  void clear() {
+    _source.clear();
+  }
+
+  Set<T> _clone() {
+    Set<T> result = (_emptySet == null) ? new Set<T>() : _emptySet<T>();
+    result.addAll(this);
+    return result;
+  }
+
+  Set<T> toSet() => _clone();
+
+  T lookup(Object key) => _source.lookup(key) as T;
+}
+
+class CastMap<SK, SV, K, V> extends MapBase<K, V> {
+  final Map<SK, SV> _source;
+
+  CastMap(this._source);
+
+  Map<RK, RV> cast<RK, RV>() => new CastMap<SK, SV, RK, RV>(_source);
+
+  bool containsValue(Object value) => _source.containsValue(value);
+
+  bool containsKey(Object key) => _source.containsKey(key);
+
+  V operator [](Object key) => _source[key] as V;
+
+  void operator []=(K key, V value) {
+    _source[key as SK] = value as SV;
+  }
+
+  V putIfAbsent(K key, V ifAbsent()) => _source.putIfAbsent(
+      key as SK, (ifAbsent == null) ? null : () => ifAbsent() as SV) as V;
+
+  void addAll(Map<K, V> other) {
+    _source.addAll(new CastMap<K, V, SK, SV>(other));
+  }
+
+  V remove(Object key) => _source.remove(key) as V;
+
+  void clear() {
+    _source.clear();
+  }
+
+  void forEach(void f(K key, V value)) {
+    _source.forEach((SK key, SV value) {
+      f(key as K, value as V);
+    });
+  }
+
+  Iterable<K> get keys => new CastIterable<SK, K>(_source.keys);
+
+  Iterable<V> get values => new CastIterable<SV, V>(_source.values);
+
+  int get length => _source.length;
+
+  bool get isEmpty => _source.isEmpty;
+
+  bool get isNotEmpty => _source.isNotEmpty;
+
+  V update(K key, V update(V value), {V ifAbsent()}) {
+    return _source.update(key as SK, (SV value) => update(value as V) as SV,
+        ifAbsent: (ifAbsent == null) ? null : () => ifAbsent() as SV) as V;
+  }
+
+  void updateAll(V update(K key, V value)) {
+    _source.updateAll((SK key, SV value) => update(key as K, value as V) as SV);
+  }
+
+  Iterable<MapEntry<K, V>> get entries {
+    return _source.entries.map<MapEntry<K, V>>(
+        (MapEntry<SK, SV> e) => new MapEntry<K, V>(e.key as K, e.value as V));
+  }
+
+  void addEntries(Iterable<MapEntry<K, V>> entries) {
+    for (var entry in entries) {
+      _source[entry.key as SK] = entry.value as SV;
+    }
+  }
+
+  void removeWhere(bool test(K key, V value)) {
+    _source.removeWhere((SK key, SV value) => test(key as K, value as V));
+  }
+}
+
+class CastQueue<S, T> extends _CastIterableBase<S, T> implements Queue<T> {
+  final Queue<S> _source;
+  CastQueue(this._source);
+  Queue<R> cast<R>() => new CastQueue<S, R>(_source);
+
+  T removeFirst() => _source.removeFirst() as T;
+  T removeLast() => _source.removeLast() as T;
+
+  void add(T value) {
+    _source.add(value as S);
+  }
+
+  void addFirst(T value) {
+    _source.addFirst(value as S);
+  }
+
+  void addLast(T value) {
+    _source.addLast(value as S);
+  }
+
+  bool remove(Object other) => _source.remove(other);
+  void addAll(Iterable<T> elements) {
+    _source.addAll(new CastIterable<T, S>(elements));
+  }
+
+  void removeWhere(bool test(T element)) {
+    _source.removeWhere((S element) => test(element as T));
+  }
+
+  void retainWhere(bool test(T element)) {
+    _source.retainWhere((S element) => test(element as T));
+  }
+
+  void clear() {
+    _source.clear();
+  }
+}
diff --git a/sdk_nnbd/lib/internal/internal.dart b/sdk_nnbd/lib/internal/internal.dart
new file mode 100644
index 0000000..11ee996
--- /dev/null
+++ b/sdk_nnbd/lib/internal/internal.dart
@@ -0,0 +1,382 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library dart._internal;
+
+import 'dart:collection';
+
+import 'dart:async'
+    show
+        Future,
+        Stream,
+        StreamSubscription,
+        StreamTransformer,
+        StreamTransformerBase,
+        Zone;
+import 'dart:convert' show Converter;
+import 'dart:core' hide Symbol;
+import 'dart:core' as core;
+import 'dart:math' show Random;
+
+part 'async_cast.dart';
+part 'cast.dart';
+part 'iterable.dart';
+part 'list.dart';
+part 'print.dart';
+part 'sort.dart';
+part 'symbol.dart';
+part 'linked_list.dart';
+
+// Powers of 10 up to 10^22 are representable as doubles.
+// Powers of 10 above that are only approximate due to lack of precission.
+// Used by double-parsing.
+const POWERS_OF_TEN = const [
+  1.0, // 0
+  10.0,
+  100.0,
+  1000.0,
+  10000.0,
+  100000.0, // 5
+  1000000.0,
+  10000000.0,
+  100000000.0,
+  1000000000.0,
+  10000000000.0, // 10
+  100000000000.0,
+  1000000000000.0,
+  10000000000000.0,
+  100000000000000.0,
+  1000000000000000.0, // 15
+  10000000000000000.0,
+  100000000000000000.0,
+  1000000000000000000.0,
+  10000000000000000000.0,
+  100000000000000000000.0, // 20
+  1000000000000000000000.0,
+  10000000000000000000000.0,
+];
+
+/**
+ * An [Iterable] of the UTF-16 code units of a [String] in index order.
+ */
+class CodeUnits extends UnmodifiableListBase<int> {
+  /** The string that this is the code units of. */
+  final String _string;
+
+  CodeUnits(this._string);
+
+  int get length => _string.length;
+  int operator [](int i) => _string.codeUnitAt(i);
+
+  static String stringOf(CodeUnits u) => u._string;
+}
+
+/// Marks a function or library as having an external implementation ("native"
+/// in the Dart VM).
+///
+/// On a function, this provides a backend-specific String that can be used to
+/// identify the function's implementation.
+///
+/// On a library, it provides a Uri that can be used to locate the native
+/// library's implementation.
+class ExternalName {
+  final String name;
+  const ExternalName(this.name);
+}
+
+// Shared hex-parsing utilities.
+
+/// Parses a single hex-digit as code unit.
+///
+/// Returns a negative value if the character is not a valid hex-digit.
+int hexDigitValue(int char) {
+  assert(char >= 0 && char <= 0xFFFF);
+  const int digit0 = 0x30;
+  const int a = 0x61;
+  const int f = 0x66;
+  int digit = char ^ digit0;
+  if (digit <= 9) return digit;
+  int letter = (char | 0x20);
+  if (a <= letter && letter <= f) return letter - (a - 10);
+  return -1;
+}
+
+/// Parses two hex digits in a string.
+///
+/// Returns a negative value if either digit isn't valid.
+int parseHexByte(String source, int index) {
+  assert(index + 2 <= source.length);
+  int digit1 = hexDigitValue(source.codeUnitAt(index));
+  int digit2 = hexDigitValue(source.codeUnitAt(index + 1));
+  return digit1 * 16 + digit2 - (digit2 & 256);
+}
+
+/// Given an [instance] of some generic type [T], and [extract], a first-class
+/// generic function that takes the same number of type parameters as [T],
+/// invokes the function with the same type arguments that were passed to T
+/// when [instance] was constructed.
+///
+/// Example:
+///
+/// ```dart
+/// class Two<A, B> {}
+///
+/// print(extractTypeArguments<List>(<int>[], <T>() => new Set<T>()));
+/// // Prints: Instance of 'Set<int>'.
+///
+/// print(extractTypeArguments<Map>(<String, bool>{},
+///     <T, S>() => new Two<T, S>));
+/// // Prints: Instance of 'Two<String, bool>'.
+/// ```
+///
+/// The type argument T is important to choose which specific type parameter
+/// list in [instance]'s type hierarchy is being extracted. Consider:
+///
+/// ```dart
+/// class A<T> {}
+/// class B<T> {}
+///
+/// class C implements A<int>, B<String> {}
+///
+/// main() {
+///   var c = new C();
+///   print(extractTypeArguments<A>(c, <T>() => <T>[]));
+///   // Prints: Instance of 'List<int>'.
+///
+///   print(extractTypeArguments<B>(c, <T>() => <T>[]));
+///   // Prints: Instance of 'List<String>'.
+/// }
+/// ```
+///
+/// A caller must not:
+///
+/// *   Pass `null` for [instance].
+/// *   Use a non-class type (i.e. a function type) for [T].
+/// *   Use a non-generic type for [T].
+/// *   Pass an instance of a generic type and a function that don't both take
+///     the same number of type arguments:
+///
+///     ```dart
+///     extractTypeArguments<List>(<int>[], <T, S>() => null);
+///     ```
+///
+/// See this issue for more context:
+/// https://github.com/dart-lang/sdk/issues/31371
+external Object extractTypeArguments<T>(T instance, Function extract);
+
+/// Annotation class marking the version where SDK API was added.
+///
+/// A `Since` annotation can be applied to a library declaration,
+/// any public declaration in a library, or in a class, or to
+/// an optional parameter.
+///
+/// It signifies that the export, member or parameter was *added* in
+/// that version.
+///
+/// When applied to a library declaration, it also a applies to
+/// all members declared or exported by that library.
+/// If applied to a class, it also applies to all members and constructors
+/// of that class.
+/// If applied to a class method, or parameter of such,
+/// any method implementing that interface method is also annotated.
+/// I multiple `Since` annotations apply to the same declaration or
+/// parameter, the latest version takes precendence.
+///
+/// Any use of a marked API may trigger a warning if the using code
+/// does not require an SDK version guaranteeing that the API is available,
+/// unless the API feature is also provided by something else.
+/// It is only a problem if an annotated feature is used, and the annotated
+/// API is the *only* thing providing the functionality.
+/// For example, using `Future` exported by `dart:core` is not a problem
+/// if the same library also imports `dart:async`, and using an optional
+/// parameter on an interface is not a problem if the same type also
+/// implements another interface providing the same parameter.
+///
+/// The version must be a semantic version (like `1.4.2` or `0.9.4-rec.4`),
+/// or the first two numbers of a semantic version (like `1.0` or `2.2`),
+/// representing a stable release, and equivalent to the semantic version
+/// you get by appending a `.0`.
+@Since("2.2")
+class Since {
+  final String version;
+  const Since(this.version);
+}
+
+/**
+ * HTTP status codes.  Exported in dart:io and dart:html.
+ */
+abstract class HttpStatus {
+  static const int continue_ = 100;
+  static const int switchingProtocols = 101;
+  @Since("2.1")
+  static const int processing = 102;
+  static const int ok = 200;
+  static const int created = 201;
+  static const int accepted = 202;
+  static const int nonAuthoritativeInformation = 203;
+  static const int noContent = 204;
+  static const int resetContent = 205;
+  static const int partialContent = 206;
+  @Since("2.1")
+  static const int multiStatus = 207;
+  @Since("2.1")
+  static const int alreadyReported = 208;
+  @Since("2.1")
+  static const int imUsed = 226;
+  static const int multipleChoices = 300;
+  static const int movedPermanently = 301;
+  static const int found = 302;
+  static const int movedTemporarily = 302; // Common alias for found.
+  static const int seeOther = 303;
+  static const int notModified = 304;
+  static const int useProxy = 305;
+  static const int temporaryRedirect = 307;
+  @Since("2.1")
+  static const int permanentRedirect = 308;
+  static const int badRequest = 400;
+  static const int unauthorized = 401;
+  static const int paymentRequired = 402;
+  static const int forbidden = 403;
+  static const int notFound = 404;
+  static const int methodNotAllowed = 405;
+  static const int notAcceptable = 406;
+  static const int proxyAuthenticationRequired = 407;
+  static const int requestTimeout = 408;
+  static const int conflict = 409;
+  static const int gone = 410;
+  static const int lengthRequired = 411;
+  static const int preconditionFailed = 412;
+  static const int requestEntityTooLarge = 413;
+  static const int requestUriTooLong = 414;
+  static const int unsupportedMediaType = 415;
+  static const int requestedRangeNotSatisfiable = 416;
+  static const int expectationFailed = 417;
+  @Since("2.1")
+  static const int misdirectedRequest = 421;
+  @Since("2.1")
+  static const int unprocessableEntity = 422;
+  @Since("2.1")
+  static const int locked = 423;
+  @Since("2.1")
+  static const int failedDependency = 424;
+  static const int upgradeRequired = 426;
+  @Since("2.1")
+  static const int preconditionRequired = 428;
+  @Since("2.1")
+  static const int tooManyRequests = 429;
+  @Since("2.1")
+  static const int requestHeaderFieldsTooLarge = 431;
+  @Since("2.1")
+  static const int connectionClosedWithoutResponse = 444;
+  @Since("2.1")
+  static const int unavailableForLegalReasons = 451;
+  @Since("2.1")
+  static const int clientClosedRequest = 499;
+  static const int internalServerError = 500;
+  static const int notImplemented = 501;
+  static const int badGateway = 502;
+  static const int serviceUnavailable = 503;
+  static const int gatewayTimeout = 504;
+  static const int httpVersionNotSupported = 505;
+  @Since("2.1")
+  static const int variantAlsoNegotiates = 506;
+  @Since("2.1")
+  static const int insufficientStorage = 507;
+  @Since("2.1")
+  static const int loopDetected = 508;
+  @Since("2.1")
+  static const int notExtended = 510;
+  @Since("2.1")
+  static const int networkAuthenticationRequired = 511;
+  // Client generated status code.
+  static const int networkConnectTimeoutError = 599;
+
+  @Deprecated("Use continue_ instead")
+  static const int CONTINUE = continue_;
+  @Deprecated("Use switchingProtocols instead")
+  static const int SWITCHING_PROTOCOLS = switchingProtocols;
+  @Deprecated("Use ok instead")
+  static const int OK = ok;
+  @Deprecated("Use created instead")
+  static const int CREATED = created;
+  @Deprecated("Use accepted instead")
+  static const int ACCEPTED = accepted;
+  @Deprecated("Use nonAuthoritativeInformation instead")
+  static const int NON_AUTHORITATIVE_INFORMATION = nonAuthoritativeInformation;
+  @Deprecated("Use noContent instead")
+  static const int NO_CONTENT = noContent;
+  @Deprecated("Use resetContent instead")
+  static const int RESET_CONTENT = resetContent;
+  @Deprecated("Use partialContent instead")
+  static const int PARTIAL_CONTENT = partialContent;
+  @Deprecated("Use multipleChoices instead")
+  static const int MULTIPLE_CHOICES = multipleChoices;
+  @Deprecated("Use movedPermanently instead")
+  static const int MOVED_PERMANENTLY = movedPermanently;
+  @Deprecated("Use found instead")
+  static const int FOUND = found;
+  @Deprecated("Use movedTemporarily instead")
+  static const int MOVED_TEMPORARILY = movedTemporarily;
+  @Deprecated("Use seeOther instead")
+  static const int SEE_OTHER = seeOther;
+  @Deprecated("Use notModified instead")
+  static const int NOT_MODIFIED = notModified;
+  @Deprecated("Use useProxy instead")
+  static const int USE_PROXY = useProxy;
+  @Deprecated("Use temporaryRedirect instead")
+  static const int TEMPORARY_REDIRECT = temporaryRedirect;
+  @Deprecated("Use badRequest instead")
+  static const int BAD_REQUEST = badRequest;
+  @Deprecated("Use unauthorized instead")
+  static const int UNAUTHORIZED = unauthorized;
+  @Deprecated("Use paymentRequired instead")
+  static const int PAYMENT_REQUIRED = paymentRequired;
+  @Deprecated("Use forbidden instead")
+  static const int FORBIDDEN = forbidden;
+  @Deprecated("Use notFound instead")
+  static const int NOT_FOUND = notFound;
+  @Deprecated("Use methodNotAllowed instead")
+  static const int METHOD_NOT_ALLOWED = methodNotAllowed;
+  @Deprecated("Use notAcceptable instead")
+  static const int NOT_ACCEPTABLE = notAcceptable;
+  @Deprecated("Use proxyAuthenticationRequired instead")
+  static const int PROXY_AUTHENTICATION_REQUIRED = proxyAuthenticationRequired;
+  @Deprecated("Use requestTimeout instead")
+  static const int REQUEST_TIMEOUT = requestTimeout;
+  @Deprecated("Use conflict instead")
+  static const int CONFLICT = conflict;
+  @Deprecated("Use gone instead")
+  static const int GONE = gone;
+  @Deprecated("Use lengthRequired instead")
+  static const int LENGTH_REQUIRED = lengthRequired;
+  @Deprecated("Use preconditionFailed instead")
+  static const int PRECONDITION_FAILED = preconditionFailed;
+  @Deprecated("Use requestEntityTooLarge instead")
+  static const int REQUEST_ENTITY_TOO_LARGE = requestEntityTooLarge;
+  @Deprecated("Use requestUriTooLong instead")
+  static const int REQUEST_URI_TOO_LONG = requestUriTooLong;
+  @Deprecated("Use unsupportedMediaType instead")
+  static const int UNSUPPORTED_MEDIA_TYPE = unsupportedMediaType;
+  @Deprecated("Use requestedRangeNotSatisfiable instead")
+  static const int REQUESTED_RANGE_NOT_SATISFIABLE =
+      requestedRangeNotSatisfiable;
+  @Deprecated("Use expectationFailed instead")
+  static const int EXPECTATION_FAILED = expectationFailed;
+  @Deprecated("Use upgradeRequired instead")
+  static const int UPGRADE_REQUIRED = upgradeRequired;
+  @Deprecated("Use internalServerError instead")
+  static const int INTERNAL_SERVER_ERROR = internalServerError;
+  @Deprecated("Use notImplemented instead")
+  static const int NOT_IMPLEMENTED = notImplemented;
+  @Deprecated("Use badGateway instead")
+  static const int BAD_GATEWAY = badGateway;
+  @Deprecated("Use serviceUnavailable instead")
+  static const int SERVICE_UNAVAILABLE = serviceUnavailable;
+  @Deprecated("Use gatewayTimeout instead")
+  static const int GATEWAY_TIMEOUT = gatewayTimeout;
+  @Deprecated("Use httpVersionNotSupported instead")
+  static const int HTTP_VERSION_NOT_SUPPORTED = httpVersionNotSupported;
+  @Deprecated("Use networkConnectTimeoutError instead")
+  static const int NETWORK_CONNECT_TIMEOUT_ERROR = networkConnectTimeoutError;
+}
diff --git a/sdk_nnbd/lib/internal/internal_sources.gni b/sdk_nnbd/lib/internal/internal_sources.gni
new file mode 100644
index 0000000..7c8af46
--- /dev/null
+++ b/sdk_nnbd/lib/internal/internal_sources.gni
@@ -0,0 +1,18 @@
+# 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.
+
+# This file contains all sources for the dart:_internal library.
+internal_sdk_sources = [
+  "internal.dart",
+
+  # The above file needs to be first as it lists the parts below.
+  "async_cast.dart",
+  "cast.dart",
+  "iterable.dart",
+  "list.dart",
+  "linked_list.dart",
+  "print.dart",
+  "sort.dart",
+  "symbol.dart",
+]
diff --git a/sdk_nnbd/lib/internal/iterable.dart b/sdk_nnbd/lib/internal/iterable.dart
new file mode 100644
index 0000000..b3e8e4e
--- /dev/null
+++ b/sdk_nnbd/lib/internal/iterable.dart
@@ -0,0 +1,897 @@
+// Copyright (c) 2011, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart._internal;
+
+/**
+ * Marker interface for [Iterable] subclasses that have an efficient
+ * [length] implementation.
+ */
+abstract class EfficientLengthIterable<T> extends Iterable<T> {
+  const EfficientLengthIterable();
+  /**
+   * Returns the number of elements in the iterable.
+   *
+   * This is an efficient operation that doesn't require iterating through
+   * the elements.
+   */
+  int get length;
+}
+
+/**
+ * An [Iterable] for classes that have efficient [length] and [elementAt].
+ *
+ * All other methods are implemented in terms of [length] and [elementAt],
+ * including [iterator].
+ */
+abstract class ListIterable<E> extends EfficientLengthIterable<E> {
+  int get length;
+  E elementAt(int i);
+
+  const ListIterable();
+
+  Iterator<E> get iterator => new ListIterator<E>(this);
+
+  void forEach(void action(E element)) {
+    int length = this.length;
+    for (int i = 0; i < length; i++) {
+      action(elementAt(i));
+      if (length != this.length) {
+        throw new ConcurrentModificationError(this);
+      }
+    }
+  }
+
+  bool get isEmpty => length == 0;
+
+  E get first {
+    if (length == 0) throw IterableElementError.noElement();
+    return elementAt(0);
+  }
+
+  E get last {
+    if (length == 0) throw IterableElementError.noElement();
+    return elementAt(length - 1);
+  }
+
+  E get single {
+    if (length == 0) throw IterableElementError.noElement();
+    if (length > 1) throw IterableElementError.tooMany();
+    return elementAt(0);
+  }
+
+  bool contains(Object element) {
+    int length = this.length;
+    for (int i = 0; i < length; i++) {
+      if (elementAt(i) == element) return true;
+      if (length != this.length) {
+        throw new ConcurrentModificationError(this);
+      }
+    }
+    return false;
+  }
+
+  bool every(bool test(E element)) {
+    int length = this.length;
+    for (int i = 0; i < length; i++) {
+      if (!test(elementAt(i))) return false;
+      if (length != this.length) {
+        throw new ConcurrentModificationError(this);
+      }
+    }
+    return true;
+  }
+
+  bool any(bool test(E element)) {
+    int length = this.length;
+    for (int i = 0; i < length; i++) {
+      if (test(elementAt(i))) return true;
+      if (length != this.length) {
+        throw new ConcurrentModificationError(this);
+      }
+    }
+    return false;
+  }
+
+  E firstWhere(bool test(E element), {E orElse()}) {
+    int length = this.length;
+    for (int i = 0; i < length; i++) {
+      E element = elementAt(i);
+      if (test(element)) return element;
+      if (length != this.length) {
+        throw new ConcurrentModificationError(this);
+      }
+    }
+    if (orElse != null) return orElse();
+    throw IterableElementError.noElement();
+  }
+
+  E lastWhere(bool test(E element), {E orElse()}) {
+    int length = this.length;
+    for (int i = length - 1; i >= 0; i--) {
+      E element = elementAt(i);
+      if (test(element)) return element;
+      if (length != this.length) {
+        throw new ConcurrentModificationError(this);
+      }
+    }
+    if (orElse != null) return orElse();
+    throw IterableElementError.noElement();
+  }
+
+  E singleWhere(bool test(E element), {E orElse()}) {
+    int length = this.length;
+    E match = null;
+    bool matchFound = false;
+    for (int i = 0; i < length; i++) {
+      E element = elementAt(i);
+      if (test(element)) {
+        if (matchFound) {
+          throw IterableElementError.tooMany();
+        }
+        matchFound = true;
+        match = element;
+      }
+      if (length != this.length) {
+        throw new ConcurrentModificationError(this);
+      }
+    }
+    if (matchFound) return match;
+    if (orElse != null) return orElse();
+    throw IterableElementError.noElement();
+  }
+
+  String join([String separator = ""]) {
+    int length = this.length;
+    if (!separator.isEmpty) {
+      if (length == 0) return "";
+      String first = "${elementAt(0)}";
+      if (length != this.length) {
+        throw new ConcurrentModificationError(this);
+      }
+      StringBuffer buffer = new StringBuffer(first);
+      for (int i = 1; i < length; i++) {
+        buffer.write(separator);
+        buffer.write(elementAt(i));
+        if (length != this.length) {
+          throw new ConcurrentModificationError(this);
+        }
+      }
+      return buffer.toString();
+    } else {
+      StringBuffer buffer = new StringBuffer();
+      for (int i = 0; i < length; i++) {
+        buffer.write(elementAt(i));
+        if (length != this.length) {
+          throw new ConcurrentModificationError(this);
+        }
+      }
+      return buffer.toString();
+    }
+  }
+
+  Iterable<E> where(bool test(E element)) => super.where(test);
+
+  Iterable<T> map<T>(T f(E element)) => new MappedListIterable<E, T>(this, f);
+
+  E reduce(E combine(E value, E element)) {
+    int length = this.length;
+    if (length == 0) throw IterableElementError.noElement();
+    E value = elementAt(0);
+    for (int i = 1; i < length; i++) {
+      value = combine(value, elementAt(i));
+      if (length != this.length) {
+        throw new ConcurrentModificationError(this);
+      }
+    }
+    return value;
+  }
+
+  T fold<T>(T initialValue, T combine(T previousValue, E element)) {
+    var value = initialValue;
+    int length = this.length;
+    for (int i = 0; i < length; i++) {
+      value = combine(value, elementAt(i));
+      if (length != this.length) {
+        throw new ConcurrentModificationError(this);
+      }
+    }
+    return value;
+  }
+
+  Iterable<E> skip(int count) => new SubListIterable<E>(this, count, null);
+
+  Iterable<E> skipWhile(bool test(E element)) => super.skipWhile(test);
+
+  Iterable<E> take(int count) => new SubListIterable<E>(this, 0, count);
+
+  Iterable<E> takeWhile(bool test(E element)) => super.takeWhile(test);
+
+  List<E> toList({bool growable: true}) {
+    List<E> result;
+    if (growable) {
+      result = <E>[]..length = length;
+    } else {
+      result = new List<E>(length);
+    }
+    for (int i = 0; i < length; i++) {
+      result[i] = elementAt(i);
+    }
+    return result;
+  }
+
+  Set<E> toSet() {
+    Set<E> result = new Set<E>();
+    for (int i = 0; i < length; i++) {
+      result.add(elementAt(i));
+    }
+    return result;
+  }
+}
+
+class SubListIterable<E> extends ListIterable<E> {
+  final Iterable<E> _iterable; // Has efficient length and elementAt.
+  final int _start;
+  /** If null, represents the length of the iterable. */
+  final int _endOrLength;
+
+  SubListIterable(this._iterable, this._start, this._endOrLength) {
+    RangeError.checkNotNegative(_start, "start");
+    if (_endOrLength != null) {
+      RangeError.checkNotNegative(_endOrLength, "end");
+      if (_start > _endOrLength) {
+        throw new RangeError.range(_start, 0, _endOrLength, "start");
+      }
+    }
+  }
+
+  int get _endIndex {
+    int length = _iterable.length;
+    if (_endOrLength == null || _endOrLength > length) return length;
+    return _endOrLength;
+  }
+
+  int get _startIndex {
+    int length = _iterable.length;
+    if (_start > length) return length;
+    return _start;
+  }
+
+  int get length {
+    int length = _iterable.length;
+    if (_start >= length) return 0;
+    if (_endOrLength == null || _endOrLength >= length) {
+      return length - _start;
+    }
+    return _endOrLength - _start;
+  }
+
+  E elementAt(int index) {
+    int realIndex = _startIndex + index;
+    if (index < 0 || realIndex >= _endIndex) {
+      throw new RangeError.index(index, this, "index");
+    }
+    return _iterable.elementAt(realIndex);
+  }
+
+  Iterable<E> skip(int count) {
+    RangeError.checkNotNegative(count, "count");
+    int newStart = _start + count;
+    if (_endOrLength != null && newStart >= _endOrLength) {
+      return new EmptyIterable<E>();
+    }
+    return new SubListIterable<E>(_iterable, newStart, _endOrLength);
+  }
+
+  Iterable<E> take(int count) {
+    RangeError.checkNotNegative(count, "count");
+    if (_endOrLength == null) {
+      return new SubListIterable<E>(_iterable, _start, _start + count);
+    } else {
+      int newEnd = _start + count;
+      if (_endOrLength < newEnd) return this;
+      return new SubListIterable<E>(_iterable, _start, newEnd);
+    }
+  }
+
+  List<E> toList({bool growable: true}) {
+    int start = _start;
+    int end = _iterable.length;
+    if (_endOrLength != null && _endOrLength < end) end = _endOrLength;
+    int length = end - start;
+    if (length < 0) length = 0;
+    List<E> result =
+        growable ? (new List<E>()..length = length) : new List<E>(length);
+    for (int i = 0; i < length; i++) {
+      result[i] = _iterable.elementAt(start + i);
+      if (_iterable.length < end) throw new ConcurrentModificationError(this);
+    }
+    return result;
+  }
+}
+
+/**
+ * An [Iterator] that iterates a list-like [Iterable].
+ *
+ * All iterations is done in terms of [Iterable.length] and
+ * [Iterable.elementAt]. These operations are fast for list-like
+ * iterables.
+ */
+class ListIterator<E> implements Iterator<E> {
+  final Iterable<E> _iterable;
+  final int _length;
+  int _index;
+  E _current;
+
+  ListIterator(Iterable<E> iterable)
+      : _iterable = iterable,
+        _length = iterable.length,
+        _index = 0;
+
+  E get current => _current;
+
+  @pragma("vm:prefer-inline")
+  bool moveNext() {
+    int length = _iterable.length;
+    if (_length != length) {
+      throw new ConcurrentModificationError(_iterable);
+    }
+    if (_index >= length) {
+      _current = null;
+      return false;
+    }
+    _current = _iterable.elementAt(_index);
+    _index++;
+    return true;
+  }
+}
+
+typedef T _Transformation<S, T>(S value);
+
+class MappedIterable<S, T> extends Iterable<T> {
+  final Iterable<S> _iterable;
+  final _Transformation<S, T> _f;
+
+  factory MappedIterable(Iterable<S> iterable, T function(S value)) {
+    if (iterable is EfficientLengthIterable) {
+      return new EfficientLengthMappedIterable<S, T>(iterable, function);
+    }
+    return new MappedIterable<S, T>._(iterable, function);
+  }
+
+  MappedIterable._(this._iterable, this._f);
+
+  Iterator<T> get iterator => new MappedIterator<S, T>(_iterable.iterator, _f);
+
+  // Length related functions are independent of the mapping.
+  int get length => _iterable.length;
+  bool get isEmpty => _iterable.isEmpty;
+
+  // Index based lookup can be done before transforming.
+  T get first => _f(_iterable.first);
+  T get last => _f(_iterable.last);
+  T get single => _f(_iterable.single);
+  T elementAt(int index) => _f(_iterable.elementAt(index));
+}
+
+class EfficientLengthMappedIterable<S, T> extends MappedIterable<S, T>
+    implements EfficientLengthIterable<T> {
+  EfficientLengthMappedIterable(Iterable<S> iterable, T function(S value))
+      : super._(iterable, function);
+}
+
+class MappedIterator<S, T> extends Iterator<T> {
+  T _current;
+  final Iterator<S> _iterator;
+  final _Transformation<S, T> _f;
+
+  MappedIterator(this._iterator, this._f);
+
+  bool moveNext() {
+    if (_iterator.moveNext()) {
+      _current = _f(_iterator.current);
+      return true;
+    }
+    _current = null;
+    return false;
+  }
+
+  T get current => _current;
+}
+
+/**
+ * Specialized alternative to [MappedIterable] for mapped [List]s.
+ *
+ * Expects efficient `length` and `elementAt` on the source iterable.
+ */
+class MappedListIterable<S, T> extends ListIterable<T> {
+  final Iterable<S> _source;
+  final _Transformation<S, T> _f;
+
+  MappedListIterable(this._source, this._f);
+
+  int get length => _source.length;
+  T elementAt(int index) => _f(_source.elementAt(index));
+}
+
+typedef bool _ElementPredicate<E>(E element);
+
+class WhereIterable<E> extends Iterable<E> {
+  final Iterable<E> _iterable;
+  final _ElementPredicate<E> _f;
+
+  WhereIterable(this._iterable, this._f);
+
+  Iterator<E> get iterator => new WhereIterator<E>(_iterable.iterator, _f);
+
+  // Specialization of [Iterable.map] to non-EfficientLengthIterable.
+  Iterable<T> map<T>(T f(E element)) => new MappedIterable<E, T>._(this, f);
+}
+
+class WhereIterator<E> extends Iterator<E> {
+  final Iterator<E> _iterator;
+  final _ElementPredicate<E> _f;
+
+  WhereIterator(this._iterator, this._f);
+
+  bool moveNext() {
+    while (_iterator.moveNext()) {
+      if (_f(_iterator.current)) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  E get current => _iterator.current;
+}
+
+typedef Iterable<T> _ExpandFunction<S, T>(S sourceElement);
+
+class ExpandIterable<S, T> extends Iterable<T> {
+  final Iterable<S> _iterable;
+  final _ExpandFunction<S, T> _f;
+
+  ExpandIterable(this._iterable, this._f);
+
+  Iterator<T> get iterator => new ExpandIterator<S, T>(_iterable.iterator, _f);
+}
+
+class ExpandIterator<S, T> implements Iterator<T> {
+  final Iterator<S> _iterator;
+  final _ExpandFunction<S, T> _f;
+  // Initialize _currentExpansion to an empty iterable. A null value
+  // marks the end of iteration, and we don't want to call _f before
+  // the first moveNext call.
+  Iterator<T> _currentExpansion = const EmptyIterator();
+  T _current;
+
+  ExpandIterator(this._iterator, this._f);
+
+  T get current => _current;
+
+  bool moveNext() {
+    if (_currentExpansion == null) return false;
+    while (!_currentExpansion.moveNext()) {
+      _current = null;
+      if (_iterator.moveNext()) {
+        // If _f throws, this ends iteration. Otherwise _currentExpansion and
+        // _current will be set again below.
+        _currentExpansion = null;
+        _currentExpansion = _f(_iterator.current).iterator;
+      } else {
+        return false;
+      }
+    }
+    _current = _currentExpansion.current;
+    return true;
+  }
+}
+
+class TakeIterable<E> extends Iterable<E> {
+  final Iterable<E> _iterable;
+  final int _takeCount;
+
+  factory TakeIterable(Iterable<E> iterable, int takeCount) {
+    ArgumentError.checkNotNull(takeCount, "takeCount");
+    RangeError.checkNotNegative(takeCount, "takeCount");
+    if (iterable is EfficientLengthIterable) {
+      return new EfficientLengthTakeIterable<E>(iterable, takeCount);
+    }
+    return new TakeIterable<E>._(iterable, takeCount);
+  }
+
+  TakeIterable._(this._iterable, this._takeCount);
+
+  Iterator<E> get iterator {
+    return new TakeIterator<E>(_iterable.iterator, _takeCount);
+  }
+}
+
+class EfficientLengthTakeIterable<E> extends TakeIterable<E>
+    implements EfficientLengthIterable<E> {
+  EfficientLengthTakeIterable(Iterable<E> iterable, int takeCount)
+      : super._(iterable, takeCount);
+
+  int get length {
+    int iterableLength = _iterable.length;
+    if (iterableLength > _takeCount) return _takeCount;
+    return iterableLength;
+  }
+}
+
+class TakeIterator<E> extends Iterator<E> {
+  final Iterator<E> _iterator;
+  int _remaining;
+
+  TakeIterator(this._iterator, this._remaining) {
+    assert(_remaining >= 0);
+  }
+
+  bool moveNext() {
+    _remaining--;
+    if (_remaining >= 0) {
+      return _iterator.moveNext();
+    }
+    _remaining = -1;
+    return false;
+  }
+
+  E get current {
+    if (_remaining < 0) return null;
+    return _iterator.current;
+  }
+}
+
+class TakeWhileIterable<E> extends Iterable<E> {
+  final Iterable<E> _iterable;
+  final _ElementPredicate<E> _f;
+
+  TakeWhileIterable(this._iterable, this._f);
+
+  Iterator<E> get iterator {
+    return new TakeWhileIterator<E>(_iterable.iterator, _f);
+  }
+}
+
+class TakeWhileIterator<E> extends Iterator<E> {
+  final Iterator<E> _iterator;
+  final _ElementPredicate<E> _f;
+  bool _isFinished = false;
+
+  TakeWhileIterator(this._iterator, this._f);
+
+  bool moveNext() {
+    if (_isFinished) return false;
+    if (!_iterator.moveNext() || !_f(_iterator.current)) {
+      _isFinished = true;
+      return false;
+    }
+    return true;
+  }
+
+  E get current {
+    if (_isFinished) return null;
+    return _iterator.current;
+  }
+}
+
+class SkipIterable<E> extends Iterable<E> {
+  final Iterable<E> _iterable;
+  final int _skipCount;
+
+  factory SkipIterable(Iterable<E> iterable, int count) {
+    if (iterable is EfficientLengthIterable) {
+      return new EfficientLengthSkipIterable<E>(iterable, count);
+    }
+    return new SkipIterable<E>._(iterable, _checkCount(count));
+  }
+
+  SkipIterable._(this._iterable, this._skipCount);
+
+  Iterable<E> skip(int count) {
+    return new SkipIterable<E>._(_iterable, _skipCount + _checkCount(count));
+  }
+
+  Iterator<E> get iterator {
+    return new SkipIterator<E>(_iterable.iterator, _skipCount);
+  }
+}
+
+class EfficientLengthSkipIterable<E> extends SkipIterable<E>
+    implements EfficientLengthIterable<E> {
+  factory EfficientLengthSkipIterable(Iterable<E> iterable, int count) {
+    return new EfficientLengthSkipIterable<E>._(iterable, _checkCount(count));
+  }
+
+  EfficientLengthSkipIterable._(Iterable<E> iterable, int count)
+      : super._(iterable, count);
+
+  int get length {
+    int length = _iterable.length - _skipCount;
+    if (length >= 0) return length;
+    return 0;
+  }
+
+  Iterable<E> skip(int count) {
+    return new EfficientLengthSkipIterable<E>._(
+        _iterable, _skipCount + _checkCount(count));
+  }
+}
+
+int _checkCount(int count) {
+  ArgumentError.checkNotNull(count, "count");
+  RangeError.checkNotNegative(count, "count");
+  return count;
+}
+
+class SkipIterator<E> extends Iterator<E> {
+  final Iterator<E> _iterator;
+  int _skipCount;
+
+  SkipIterator(this._iterator, this._skipCount) {
+    assert(_skipCount >= 0);
+  }
+
+  bool moveNext() {
+    for (int i = 0; i < _skipCount; i++) _iterator.moveNext();
+    _skipCount = 0;
+    return _iterator.moveNext();
+  }
+
+  E get current => _iterator.current;
+}
+
+class SkipWhileIterable<E> extends Iterable<E> {
+  final Iterable<E> _iterable;
+  final _ElementPredicate<E> _f;
+
+  SkipWhileIterable(this._iterable, this._f);
+
+  Iterator<E> get iterator {
+    return new SkipWhileIterator<E>(_iterable.iterator, _f);
+  }
+}
+
+class SkipWhileIterator<E> extends Iterator<E> {
+  final Iterator<E> _iterator;
+  final _ElementPredicate<E> _f;
+  bool _hasSkipped = false;
+
+  SkipWhileIterator(this._iterator, this._f);
+
+  bool moveNext() {
+    if (!_hasSkipped) {
+      _hasSkipped = true;
+      while (_iterator.moveNext()) {
+        if (!_f(_iterator.current)) return true;
+      }
+    }
+    return _iterator.moveNext();
+  }
+
+  E get current => _iterator.current;
+}
+
+/**
+ * The always empty [Iterable].
+ */
+class EmptyIterable<E> extends EfficientLengthIterable<E> {
+  const EmptyIterable();
+
+  Iterator<E> get iterator => const EmptyIterator();
+
+  void forEach(void action(E element)) {}
+
+  bool get isEmpty => true;
+
+  int get length => 0;
+
+  E get first {
+    throw IterableElementError.noElement();
+  }
+
+  E get last {
+    throw IterableElementError.noElement();
+  }
+
+  E get single {
+    throw IterableElementError.noElement();
+  }
+
+  E elementAt(int index) {
+    throw new RangeError.range(index, 0, 0, "index");
+  }
+
+  bool contains(Object element) => false;
+
+  bool every(bool test(E element)) => true;
+
+  bool any(bool test(E element)) => false;
+
+  E firstWhere(bool test(E element), {E orElse()}) {
+    if (orElse != null) return orElse();
+    throw IterableElementError.noElement();
+  }
+
+  E lastWhere(bool test(E element), {E orElse()}) {
+    if (orElse != null) return orElse();
+    throw IterableElementError.noElement();
+  }
+
+  E singleWhere(bool test(E element), {E orElse()}) {
+    if (orElse != null) return orElse();
+    throw IterableElementError.noElement();
+  }
+
+  String join([String separator = ""]) => "";
+
+  Iterable<E> where(bool test(E element)) => this;
+
+  Iterable<T> map<T>(T f(E element)) => new EmptyIterable<T>();
+
+  E reduce(E combine(E value, E element)) {
+    throw IterableElementError.noElement();
+  }
+
+  T fold<T>(T initialValue, T combine(T previousValue, E element)) {
+    return initialValue;
+  }
+
+  Iterable<E> skip(int count) {
+    RangeError.checkNotNegative(count, "count");
+    return this;
+  }
+
+  Iterable<E> skipWhile(bool test(E element)) => this;
+
+  Iterable<E> take(int count) {
+    RangeError.checkNotNegative(count, "count");
+    return this;
+  }
+
+  Iterable<E> takeWhile(bool test(E element)) => this;
+
+  List<E> toList({bool growable: true}) => growable ? <E>[] : new List<E>(0);
+
+  Set<E> toSet() => new Set<E>();
+}
+
+/** The always empty iterator. */
+class EmptyIterator<E> implements Iterator<E> {
+  const EmptyIterator();
+  bool moveNext() => false;
+  E get current => null;
+}
+
+class FollowedByIterable<E> extends Iterable<E> {
+  final Iterable<E> _first;
+  final Iterable<E> _second;
+  FollowedByIterable(this._first, this._second);
+
+  factory FollowedByIterable.firstEfficient(
+      EfficientLengthIterable<E> first, Iterable<E> second) {
+    if (second is EfficientLengthIterable<E>) {
+      return new EfficientLengthFollowedByIterable<E>(first, second);
+    }
+    return new FollowedByIterable<E>(first, second);
+  }
+
+  Iterator<E> get iterator => new FollowedByIterator(_first, _second);
+
+  int get length => _first.length + _second.length;
+  bool get isEmpty => _first.isEmpty && _second.isEmpty;
+  bool get isNotEmpty => _first.isNotEmpty || _second.isNotEmpty;
+
+  // May be more efficient if either iterable is a Set.
+  bool contains(Object value) =>
+      _first.contains(value) || _second.contains(value);
+
+  E get first {
+    var iterator = _first.iterator;
+    if (iterator.moveNext()) return iterator.current;
+    return _second.first;
+  }
+
+  E get last {
+    var iterator = _second.iterator;
+    if (iterator.moveNext()) {
+      E last = iterator.current;
+      while (iterator.moveNext()) last = iterator.current;
+      return last;
+    }
+    return _first.last;
+  }
+
+  // If linear sequences of `followedBy` becomes an issue, we can flatten
+  // into a list of iterables instead of a tree or spine.
+}
+
+class EfficientLengthFollowedByIterable<E> extends FollowedByIterable<E>
+    implements EfficientLengthIterable<E> {
+  EfficientLengthFollowedByIterable(
+      EfficientLengthIterable<E> first, EfficientLengthIterable<E> second)
+      : super(first, second);
+
+  Iterable<E> skip(int count) {
+    int firstLength = _first.length;
+    if (count >= firstLength) return _second.skip(count - firstLength);
+    return new EfficientLengthFollowedByIterable<E>(
+        _first.skip(count), _second);
+  }
+
+  Iterable<E> take(int count) {
+    int firstLength = _first.length;
+    if (count <= firstLength) return _first.take(count);
+    return new EfficientLengthFollowedByIterable<E>(
+        _first, _second.take(count - firstLength));
+  }
+
+  E elementAt(int index) {
+    int firstLength = _first.length;
+    if (index < firstLength) return _first.elementAt(index);
+    return _second.elementAt(index - firstLength);
+  }
+
+  E get first {
+    if (_first.isNotEmpty) return _first.first;
+    return _second.first;
+  }
+
+  E get last {
+    if (_second.isNotEmpty) return _second.last;
+    return _first.last;
+  }
+}
+
+class FollowedByIterator<E> implements Iterator<E> {
+  Iterator<E> _currentIterator;
+  Iterable<E> _nextIterable;
+
+  FollowedByIterator(Iterable<E> first, this._nextIterable)
+      : _currentIterator = first.iterator;
+
+  bool moveNext() {
+    if (_currentIterator.moveNext()) return true;
+    if (_nextIterable != null) {
+      _currentIterator = _nextIterable.iterator;
+      _nextIterable = null;
+      return _currentIterator.moveNext();
+    }
+    return false;
+  }
+
+  E get current => _currentIterator.current;
+}
+
+class WhereTypeIterable<T> extends Iterable<T> {
+  final Iterable<Object> _source;
+  WhereTypeIterable(this._source);
+  Iterator<T> get iterator => new WhereTypeIterator<T>(_source.iterator);
+}
+
+class WhereTypeIterator<T> implements Iterator<T> {
+  final Iterator<Object> _source;
+  WhereTypeIterator(this._source);
+  bool moveNext() {
+    while (_source.moveNext()) {
+      if (_source.current is T) return true;
+    }
+    return false;
+  }
+
+  T get current => _source.current;
+}
+
+/**
+ * Creates errors throw by [Iterable] when the element count is wrong.
+ */
+abstract class IterableElementError {
+  /** Error thrown thrown by, e.g., [Iterable.first] when there is no result. */
+  static StateError noElement() => new StateError("No element");
+  /** Error thrown by, e.g., [Iterable.single] if there are too many results. */
+  static StateError tooMany() => new StateError("Too many elements");
+  /** Error thrown by, e.g., [List.setRange] if there are too few elements. */
+  static StateError tooFew() => new StateError("Too few elements");
+}
diff --git a/sdk_nnbd/lib/internal/linked_list.dart b/sdk_nnbd/lib/internal/linked_list.dart
new file mode 100644
index 0000000..31a6c01
--- /dev/null
+++ b/sdk_nnbd/lib/internal/linked_list.dart
@@ -0,0 +1,126 @@
+// 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.
+
+part of dart._internal;
+
+/// A rudimentary linked list.
+class LinkedList<T extends LinkedListEntry<T>> extends IterableBase<T> {
+  T first;
+  T last;
+  int length = 0;
+
+  bool get isEmpty => length == 0;
+
+  /**
+   * Adds [newLast] to the end of this linked list.
+   */
+  void add(T newLast) {
+    assert(newLast._next == null && newLast._previous == null);
+    if (last != null) {
+      assert(last._next == null);
+      last._next = newLast;
+    } else {
+      first = newLast;
+    }
+    newLast._previous = last;
+    last = newLast;
+    last._list = this;
+    length++;
+  }
+
+  /**
+   * Adds [newFirst] to the beginning of this linked list.
+   */
+  void addFirst(T newFirst) {
+    if (first != null) {
+      assert(first._previous == null);
+      first._previous = newFirst;
+    } else {
+      last = newFirst;
+    }
+    newFirst._next = first;
+    first = newFirst;
+    first._list = this;
+    length++;
+  }
+
+  /**
+   * Removes the given [node] from this list.
+   *
+   * If the entry is not in this linked list nothing happens.
+   *
+   * Also see [LinkedListEntry.unlink].
+   */
+  void remove(T node) {
+    if (node._list != this) return;
+    length--;
+    if (node._previous == null) {
+      assert(identical(node, first));
+      first = node._next;
+    } else {
+      node._previous._next = node._next;
+    }
+    if (node._next == null) {
+      assert(identical(node, last));
+      last = node._previous;
+    } else {
+      node._next._previous = node._previous;
+    }
+    node._next = node._previous = null;
+    node._list = null;
+  }
+
+  Iterator<T> get iterator => new _LinkedListIterator<T>(this);
+}
+
+class LinkedListEntry<T extends LinkedListEntry<T>> {
+  T _next;
+  T _previous;
+  LinkedList<T> _list;
+
+  /**
+   * Unlinks the element from its linked list.
+   *
+   * If the entry is not in a linked list, does nothing. Otherwise, this
+   * is equivalent to calling [LinkedList.remove] on the list this entry
+   * is currently in.
+   */
+  void unlink() {
+    if (_list == null) return;
+    _list.remove(this);
+  }
+}
+
+class _LinkedListIterator<T extends LinkedListEntry<T>> implements Iterator<T> {
+  /// The current element of the iterator.
+  // This field is writeable, but should only read by users of this class.
+  T current;
+
+  /// The list the iterator iterates over.
+  ///
+  /// Set to [null] if the provided list was empty (indicating that there were
+  /// no entries to iterate over).
+  ///
+  /// Set to [null] as soon as [moveNext] was invoked (indicating that the
+  /// iterator has to work with [current] from now on.
+  LinkedList<T> _list;
+
+  _LinkedListIterator(this._list) {
+    if (_list.length == 0) _list = null;
+  }
+
+  bool moveNext() {
+    // current is null if the iterator hasn't started iterating, or if the
+    // iteration is finished. In the first case, the [_list] field is not null.
+    if (current == null) {
+      if (_list == null) return false;
+      assert(_list.length > 0);
+      current = _list.first;
+      _list = null;
+      return true;
+    }
+    current = current._next;
+    return current != null;
+  }
+}
diff --git a/sdk_nnbd/lib/internal/list.dart b/sdk_nnbd/lib/internal/list.dart
new file mode 100644
index 0000000..e0ddd70
--- /dev/null
+++ b/sdk_nnbd/lib/internal/list.dart
@@ -0,0 +1,341 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart._internal;
+
+/**
+ * Mixin that throws on the length changing operations of [List].
+ *
+ * Intended to mix-in on top of [ListMixin] for fixed-length lists.
+ */
+abstract class FixedLengthListMixin<E> {
+  /** This operation is not supported by a fixed length list. */
+  set length(int newLength) {
+    throw new UnsupportedError(
+        "Cannot change the length of a fixed-length list");
+  }
+
+  /** This operation is not supported by a fixed length list. */
+  void add(E value) {
+    throw new UnsupportedError("Cannot add to a fixed-length list");
+  }
+
+  /** This operation is not supported by a fixed length list. */
+  void insert(int index, E value) {
+    throw new UnsupportedError("Cannot add to a fixed-length list");
+  }
+
+  /** This operation is not supported by a fixed length list. */
+  void insertAll(int at, Iterable<E> iterable) {
+    throw new UnsupportedError("Cannot add to a fixed-length list");
+  }
+
+  /** This operation is not supported by a fixed length list. */
+  void addAll(Iterable<E> iterable) {
+    throw new UnsupportedError("Cannot add to a fixed-length list");
+  }
+
+  /** This operation is not supported by a fixed length list. */
+  bool remove(Object element) {
+    throw new UnsupportedError("Cannot remove from a fixed-length list");
+  }
+
+  /** This operation is not supported by a fixed length list. */
+  void removeWhere(bool test(E element)) {
+    throw new UnsupportedError("Cannot remove from a fixed-length list");
+  }
+
+  /** This operation is not supported by a fixed length list. */
+  void retainWhere(bool test(E element)) {
+    throw new UnsupportedError("Cannot remove from a fixed-length list");
+  }
+
+  /** This operation is not supported by a fixed length list. */
+  void clear() {
+    throw new UnsupportedError("Cannot clear a fixed-length list");
+  }
+
+  /** This operation is not supported by a fixed length list. */
+  E removeAt(int index) {
+    throw new UnsupportedError("Cannot remove from a fixed-length list");
+  }
+
+  /** This operation is not supported by a fixed length list. */
+  E removeLast() {
+    throw new UnsupportedError("Cannot remove from a fixed-length list");
+  }
+
+  /** This operation is not supported by a fixed length list. */
+  void removeRange(int start, int end) {
+    throw new UnsupportedError("Cannot remove from a fixed-length list");
+  }
+
+  /** This operation is not supported by a fixed length list. */
+  void replaceRange(int start, int end, Iterable<E> iterable) {
+    throw new UnsupportedError("Cannot remove from a fixed-length list");
+  }
+}
+
+/**
+ * Mixin for an unmodifiable [List] class.
+ *
+ * This overrides all mutating methods with methods that throw.
+ * This mixin is intended to be mixed in on top of [ListMixin] on
+ * unmodifiable lists.
+ */
+abstract class UnmodifiableListMixin<E> implements List<E> {
+  /** This operation is not supported by an unmodifiable list. */
+  void operator []=(int index, E value) {
+    throw new UnsupportedError("Cannot modify an unmodifiable list");
+  }
+
+  /** This operation is not supported by an unmodifiable list. */
+  set length(int newLength) {
+    throw new UnsupportedError(
+        "Cannot change the length of an unmodifiable list");
+  }
+
+  set first(E element) {
+    throw new UnsupportedError("Cannot modify an unmodifiable list");
+  }
+
+  set last(E element) {
+    throw new UnsupportedError("Cannot modify an unmodifiable list");
+  }
+
+  /** This operation is not supported by an unmodifiable list. */
+  void setAll(int at, Iterable<E> iterable) {
+    throw new UnsupportedError("Cannot modify an unmodifiable list");
+  }
+
+  /** This operation is not supported by an unmodifiable list. */
+  void add(E value) {
+    throw new UnsupportedError("Cannot add to an unmodifiable list");
+  }
+
+  /** This operation is not supported by an unmodifiable list. */
+  void insert(int index, E element) {
+    throw new UnsupportedError("Cannot add to an unmodifiable list");
+  }
+
+  /** This operation is not supported by an unmodifiable list. */
+  void insertAll(int at, Iterable<E> iterable) {
+    throw new UnsupportedError("Cannot add to an unmodifiable list");
+  }
+
+  /** This operation is not supported by an unmodifiable list. */
+  void addAll(Iterable<E> iterable) {
+    throw new UnsupportedError("Cannot add to an unmodifiable list");
+  }
+
+  /** This operation is not supported by an unmodifiable list. */
+  bool remove(Object element) {
+    throw new UnsupportedError("Cannot remove from an unmodifiable list");
+  }
+
+  /** This operation is not supported by an unmodifiable list. */
+  void removeWhere(bool test(E element)) {
+    throw new UnsupportedError("Cannot remove from an unmodifiable list");
+  }
+
+  /** This operation is not supported by an unmodifiable list. */
+  void retainWhere(bool test(E element)) {
+    throw new UnsupportedError("Cannot remove from an unmodifiable list");
+  }
+
+  /** This operation is not supported by an unmodifiable list. */
+  void sort([Comparator<E> compare]) {
+    throw new UnsupportedError("Cannot modify an unmodifiable list");
+  }
+
+  /** This operation is not supported by an unmodifiable list. */
+  void shuffle([Random random]) {
+    throw new UnsupportedError("Cannot modify an unmodifiable list");
+  }
+
+  /** This operation is not supported by an unmodifiable list. */
+  void clear() {
+    throw new UnsupportedError("Cannot clear an unmodifiable list");
+  }
+
+  /** This operation is not supported by an unmodifiable list. */
+  E removeAt(int index) {
+    throw new UnsupportedError("Cannot remove from an unmodifiable list");
+  }
+
+  /** This operation is not supported by an unmodifiable list. */
+  E removeLast() {
+    throw new UnsupportedError("Cannot remove from an unmodifiable list");
+  }
+
+  /** This operation is not supported by an unmodifiable list. */
+  void setRange(int start, int end, Iterable<E> iterable, [int skipCount = 0]) {
+    throw new UnsupportedError("Cannot modify an unmodifiable list");
+  }
+
+  /** This operation is not supported by an unmodifiable list. */
+  void removeRange(int start, int end) {
+    throw new UnsupportedError("Cannot remove from an unmodifiable list");
+  }
+
+  /** This operation is not supported by an unmodifiable list. */
+  void replaceRange(int start, int end, Iterable<E> iterable) {
+    throw new UnsupportedError("Cannot remove from an unmodifiable list");
+  }
+
+  /** This operation is not supported by an unmodifiable list. */
+  void fillRange(int start, int end, [E fillValue]) {
+    throw new UnsupportedError("Cannot modify an unmodifiable list");
+  }
+}
+
+/**
+ * Abstract implementation of a fixed-length list.
+ *
+ * All operations are defined in terms of `length`, `operator[]` and
+ * `operator[]=`, which need to be implemented.
+ */
+abstract class FixedLengthListBase<E> = ListBase<E>
+    with FixedLengthListMixin<E>;
+
+/**
+ * Abstract implementation of an unmodifiable list.
+ *
+ * All operations are defined in terms of `length` and `operator[]`,
+ * which need to be implemented.
+ */
+abstract class UnmodifiableListBase<E> = ListBase<E>
+    with UnmodifiableListMixin<E>;
+
+class _ListIndicesIterable extends ListIterable<int> {
+  List _backedList;
+
+  _ListIndicesIterable(this._backedList);
+
+  int get length => _backedList.length;
+  int elementAt(int index) {
+    RangeError.checkValidIndex(index, this);
+    return index;
+  }
+}
+
+class ListMapView<E> extends UnmodifiableMapBase<int, E> {
+  List<E> _values;
+
+  ListMapView(this._values);
+
+  E operator [](Object key) => containsKey(key) ? _values[key] : null;
+  int get length => _values.length;
+
+  Iterable<E> get values => new SubListIterable<E>(_values, 0, null);
+  Iterable<int> get keys => new _ListIndicesIterable(_values);
+
+  bool get isEmpty => _values.isEmpty;
+  bool get isNotEmpty => _values.isNotEmpty;
+  bool containsValue(Object value) => _values.contains(value);
+  bool containsKey(Object key) => key is int && key >= 0 && key < length;
+
+  void forEach(void f(int key, E value)) {
+    int length = _values.length;
+    for (int i = 0; i < length; i++) {
+      f(i, _values[i]);
+      if (length != _values.length) {
+        throw new ConcurrentModificationError(_values);
+      }
+    }
+  }
+}
+
+class ReversedListIterable<E> extends ListIterable<E> {
+  Iterable<E> _source;
+  ReversedListIterable(this._source);
+
+  int get length => _source.length;
+
+  E elementAt(int index) => _source.elementAt(_source.length - 1 - index);
+}
+
+/**
+ * Creates errors thrown by unmodifiable lists when they are attempted modified.
+ *
+ * This class creates [UnsupportedError]s with specialized messages.
+ */
+abstract class UnmodifiableListError {
+  /** Error thrown when trying to add elements to an unmodifiable list. */
+  static UnsupportedError add() =>
+      new UnsupportedError("Cannot add to unmodifiable List");
+
+  /** Error thrown when trying to add elements to an unmodifiable list. */
+  static UnsupportedError change() =>
+      new UnsupportedError("Cannot change the content of an unmodifiable List");
+
+  /** Error thrown when trying to change the length of an unmodifiable list. */
+  static UnsupportedError length() =>
+      new UnsupportedError("Cannot change length of unmodifiable List");
+
+  /** Error thrown when trying to remove elements from an unmodifiable list. */
+  static UnsupportedError remove() =>
+      new UnsupportedError("Cannot remove from unmodifiable List");
+}
+
+/**
+ * Creates errors thrown by non-growable lists when they are attempted modified.
+ *
+ * This class creates [UnsupportedError]s with specialized messages.
+ */
+abstract class NonGrowableListError {
+  /** Error thrown when trying to add elements to an non-growable list. */
+  static UnsupportedError add() =>
+      new UnsupportedError("Cannot add to non-growable List");
+
+  /** Error thrown when trying to change the length of an non-growable list. */
+  static UnsupportedError length() =>
+      new UnsupportedError("Cannot change length of non-growable List");
+
+  /** Error thrown when trying to remove elements from an non-growable list. */
+  static UnsupportedError remove() =>
+      new UnsupportedError("Cannot remove from non-growable List");
+}
+
+/**
+ * Converts a growable list to a fixed length list with the same elements.
+ *
+ * For internal use only.
+ * Only works on growable lists as created by `[]` or `new List()`.
+ * May throw on any other list.
+ *
+ * The operation is efficient. It doesn't copy the elements, but converts
+ * the existing list directly to a fixed length list.
+ * That means that it is a destructive conversion.
+ * The original list should not be used afterwards.
+ *
+ * The returned list may be the same list as the original,
+ * or it may be a different list (according to [identical]).
+ * The original list may have changed type to be a fixed list,
+ * or become empty or been otherwise modified.
+ * It will still be a valid object, so references to it will not, e.g., crash
+ * the runtime if accessed, but no promises are made wrt. its contents.
+ *
+ * This unspecified behavior is the reason the function is not exposed to
+ * users. We allow the underlying implementation to make the most efficient
+ * conversion, at the cost of leaving the original list in an unspecified
+ * state.
+ */
+external List<T> makeListFixedLength<T>(List<T> growableList);
+
+/**
+ * Converts a fixed-length list to an unmodifiable list.
+ *
+ * For internal use only.
+ * Only works for core fixed-length lists as created by `new List(length)`,
+ * or as returned by [makeListFixedLength].
+ *
+ * The operation is efficient. It doesn't copy the elements, but converts
+ * the existing list directly to a fixed length list.
+ * That means that it is a destructive conversion.
+ * The original list should not be used afterwards.
+ *
+ * The unmodifiable list type is similar to the one used by const lists.
+ */
+external List<T> makeFixedListUnmodifiable<T>(List<T> fixedLengthList);
diff --git a/sdk_nnbd/lib/internal/patch.dart b/sdk_nnbd/lib/internal/patch.dart
new file mode 100644
index 0000000..3fc9733
--- /dev/null
+++ b/sdk_nnbd/lib/internal/patch.dart
@@ -0,0 +1,11 @@
+// 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.
+
+part of "dart:_internal";
+
+class _Patch {
+  const _Patch();
+}
+
+const _Patch patch = const _Patch();
diff --git a/sdk_nnbd/lib/internal/print.dart b/sdk_nnbd/lib/internal/print.dart
new file mode 100644
index 0000000..417003b
--- /dev/null
+++ b/sdk_nnbd/lib/internal/print.dart
@@ -0,0 +1,17 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart._internal;
+
+/**
+ * This function is set by the first allocation of a Zone.
+ *
+ * Once the function is set the core `print` function calls this closure instead
+ * of [printToConsole].
+ *
+ * This decouples the core library from the async library.
+ */
+void Function(String) printToZone = null;
+
+external void printToConsole(String line);
diff --git a/sdk_nnbd/lib/internal/sort.dart b/sdk_nnbd/lib/internal/sort.dart
new file mode 100644
index 0000000..d6cca2e
--- /dev/null
+++ b/sdk_nnbd/lib/internal/sort.dart
@@ -0,0 +1,385 @@
+// Copyright (c) 2011, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart._internal;
+
+/**
+ * Dual-Pivot Quicksort algorithm.
+ *
+ * This class implements the dual-pivot quicksort algorithm as presented in
+ * Vladimir Yaroslavskiy's paper.
+ *
+ * Some improvements have been copied from Android's implementation.
+ */
+class Sort {
+  // When a list has less then [:_INSERTION_SORT_THRESHOLD:] elements it will
+  // be sorted by an insertion sort.
+  static const int _INSERTION_SORT_THRESHOLD = 32;
+
+  /**
+   * Sorts all elements of the given list [:a:] according to the given
+   * [:compare:] function.
+   *
+   * The [:compare:] function takes two arguments [:x:] and [:y:] and returns
+   *  -1 if [:x < y:],
+   *   0 if [:x == y:], and
+   *   1 if [:x > y:].
+   *
+   * The function's behavior must be consistent. It must not return different
+   * results for the same values.
+   */
+  static void sort<E>(List<E> a, int compare(E a, E b)) {
+    _doSort(a, 0, a.length - 1, compare);
+  }
+
+  /**
+   * Sorts all elements in the range [:from:] (inclusive) to [:to:] (exclusive)
+   * of the given list [:a:].
+   *
+   * If the given range is invalid an "OutOfRange" error is raised.
+   * TODO(floitsch): do we want an error?
+   *
+   * See [:sort:] for requirements of the [:compare:] function.
+   */
+  static void sortRange<E>(List<E> a, int from, int to, int compare(E a, E b)) {
+    if ((from < 0) || (to > a.length) || (to < from)) {
+      throw "OutOfRange";
+    }
+    _doSort(a, from, to - 1, compare);
+  }
+
+  /**
+   * Sorts the list in the interval [:left:] to [:right:] (both inclusive).
+   */
+  static void _doSort<E>(
+      List<E> a, int left, int right, int compare(E a, E b)) {
+    if ((right - left) <= _INSERTION_SORT_THRESHOLD) {
+      _insertionSort(a, left, right, compare);
+    } else {
+      _dualPivotQuicksort(a, left, right, compare);
+    }
+  }
+
+  static void _insertionSort<E>(
+      List<E> a, int left, int right, int compare(E a, E b)) {
+    for (int i = left + 1; i <= right; i++) {
+      var el = a[i];
+      int j = i;
+      while ((j > left) && (compare(a[j - 1], el) > 0)) {
+        a[j] = a[j - 1];
+        j--;
+      }
+      a[j] = el;
+    }
+  }
+
+  static void _dualPivotQuicksort<E>(
+      List<E> a, int left, int right, int compare(E a, E b)) {
+    assert(right - left > _INSERTION_SORT_THRESHOLD);
+
+    // Compute the two pivots by looking at 5 elements.
+    int sixth = (right - left + 1) ~/ 6;
+    int index1 = left + sixth;
+    int index5 = right - sixth;
+    int index3 = (left + right) ~/ 2; // The midpoint.
+    int index2 = index3 - sixth;
+    int index4 = index3 + sixth;
+
+    var el1 = a[index1];
+    var el2 = a[index2];
+    var el3 = a[index3];
+    var el4 = a[index4];
+    var el5 = a[index5];
+
+    // Sort the selected 5 elements using a sorting network.
+    if (compare(el1, el2) > 0) {
+      var t = el1;
+      el1 = el2;
+      el2 = t;
+    }
+    if (compare(el4, el5) > 0) {
+      var t = el4;
+      el4 = el5;
+      el5 = t;
+    }
+    if (compare(el1, el3) > 0) {
+      var t = el1;
+      el1 = el3;
+      el3 = t;
+    }
+    if (compare(el2, el3) > 0) {
+      var t = el2;
+      el2 = el3;
+      el3 = t;
+    }
+    if (compare(el1, el4) > 0) {
+      var t = el1;
+      el1 = el4;
+      el4 = t;
+    }
+    if (compare(el3, el4) > 0) {
+      var t = el3;
+      el3 = el4;
+      el4 = t;
+    }
+    if (compare(el2, el5) > 0) {
+      var t = el2;
+      el2 = el5;
+      el5 = t;
+    }
+    if (compare(el2, el3) > 0) {
+      var t = el2;
+      el2 = el3;
+      el3 = t;
+    }
+    if (compare(el4, el5) > 0) {
+      var t = el4;
+      el4 = el5;
+      el5 = t;
+    }
+
+    var pivot1 = el2;
+    var pivot2 = el4;
+
+    // el2 and el4 have been saved in the pivot variables. They will be written
+    // back, once the partitioning is finished.
+    a[index1] = el1;
+    a[index3] = el3;
+    a[index5] = el5;
+
+    a[index2] = a[left];
+    a[index4] = a[right];
+
+    int less = left + 1; // First element in the middle partition.
+    int great = right - 1; // Last element in the middle partition.
+
+    bool pivots_are_equal = (compare(pivot1, pivot2) == 0);
+    if (pivots_are_equal) {
+      var pivot = pivot1;
+      // Degenerated case where the partitioning becomes a Dutch national flag
+      // problem.
+      //
+      // [ |  < pivot  | == pivot | unpartitioned | > pivot  | ]
+      //  ^             ^          ^             ^            ^
+      // left         less         k           great         right
+      //
+      // a[left] and a[right] are undefined and are filled after the
+      // partitioning.
+      //
+      // Invariants:
+      //   1) for x in ]left, less[ : x < pivot.
+      //   2) for x in [less, k[ : x == pivot.
+      //   3) for x in ]great, right[ : x > pivot.
+      for (int k = less; k <= great; k++) {
+        var ak = a[k];
+        int comp = compare(ak, pivot);
+        if (comp == 0) continue;
+        if (comp < 0) {
+          if (k != less) {
+            a[k] = a[less];
+            a[less] = ak;
+          }
+          less++;
+        } else {
+          // comp > 0.
+          //
+          // Find the first element <= pivot in the range [k - 1, great] and
+          // put [:ak:] there. We know that such an element must exist:
+          // When k == less, then el3 (which is equal to pivot) lies in the
+          // interval. Otherwise a[k - 1] == pivot and the search stops at k-1.
+          // Note that in the latter case invariant 2 will be violated for a
+          // short amount of time. The invariant will be restored when the
+          // pivots are put into their final positions.
+          while (true) {
+            comp = compare(a[great], pivot);
+            if (comp > 0) {
+              great--;
+              // This is the only location in the while-loop where a new
+              // iteration is started.
+              continue;
+            } else if (comp < 0) {
+              // Triple exchange.
+              a[k] = a[less];
+              a[less++] = a[great];
+              a[great--] = ak;
+              break;
+            } else {
+              // comp == 0;
+              a[k] = a[great];
+              a[great--] = ak;
+              // Note: if great < k then we will exit the outer loop and fix
+              // invariant 2 (which we just violated).
+              break;
+            }
+          }
+        }
+      }
+    } else {
+      // We partition the list into three parts:
+      //  1. < pivot1
+      //  2. >= pivot1 && <= pivot2
+      //  3. > pivot2
+      //
+      // During the loop we have:
+      // [ | < pivot1 | >= pivot1 && <= pivot2 | unpartitioned  | > pivot2  | ]
+      //  ^            ^                        ^              ^             ^
+      // left         less                     k              great        right
+      //
+      // a[left] and a[right] are undefined and are filled after the
+      // partitioning.
+      //
+      // Invariants:
+      //   1. for x in ]left, less[ : x < pivot1
+      //   2. for x in [less, k[ : pivot1 <= x && x <= pivot2
+      //   3. for x in ]great, right[ : x > pivot2
+      for (int k = less; k <= great; k++) {
+        var ak = a[k];
+        int comp_pivot1 = compare(ak, pivot1);
+        if (comp_pivot1 < 0) {
+          if (k != less) {
+            a[k] = a[less];
+            a[less] = ak;
+          }
+          less++;
+        } else {
+          int comp_pivot2 = compare(ak, pivot2);
+          if (comp_pivot2 > 0) {
+            while (true) {
+              int comp = compare(a[great], pivot2);
+              if (comp > 0) {
+                great--;
+                if (great < k) break;
+                // This is the only location inside the loop where a new
+                // iteration is started.
+                continue;
+              } else {
+                // a[great] <= pivot2.
+                comp = compare(a[great], pivot1);
+                if (comp < 0) {
+                  // Triple exchange.
+                  a[k] = a[less];
+                  a[less++] = a[great];
+                  a[great--] = ak;
+                } else {
+                  // a[great] >= pivot1.
+                  a[k] = a[great];
+                  a[great--] = ak;
+                }
+                break;
+              }
+            }
+          }
+        }
+      }
+    }
+
+    // Move pivots into their final positions.
+    // We shrunk the list from both sides (a[left] and a[right] have
+    // meaningless values in them) and now we move elements from the first
+    // and third partition into these locations so that we can store the
+    // pivots.
+    a[left] = a[less - 1];
+    a[less - 1] = pivot1;
+    a[right] = a[great + 1];
+    a[great + 1] = pivot2;
+
+    // The list is now partitioned into three partitions:
+    // [ < pivot1   | >= pivot1 && <= pivot2   |  > pivot2   ]
+    //  ^            ^                        ^             ^
+    // left         less                     great        right
+
+    // Recursive descent. (Don't include the pivot values.)
+    _doSort(a, left, less - 2, compare);
+    _doSort(a, great + 2, right, compare);
+
+    if (pivots_are_equal) {
+      // All elements in the second partition are equal to the pivot. No
+      // need to sort them.
+      return;
+    }
+
+    // In theory it should be enough to call _doSort recursively on the second
+    // partition.
+    // The Android source however removes the pivot elements from the recursive
+    // call if the second partition is too large (more than 2/3 of the list).
+    if (less < index1 && great > index5) {
+      while (compare(a[less], pivot1) == 0) {
+        less++;
+      }
+      while (compare(a[great], pivot2) == 0) {
+        great--;
+      }
+
+      // Copy paste of the previous 3-way partitioning with adaptions.
+      //
+      // We partition the list into three parts:
+      //  1. == pivot1
+      //  2. > pivot1 && < pivot2
+      //  3. == pivot2
+      //
+      // During the loop we have:
+      // [ == pivot1 | > pivot1 && < pivot2 | unpartitioned  | == pivot2 ]
+      //              ^                      ^              ^
+      //            less                     k              great
+      //
+      // Invariants:
+      //   1. for x in [ *, less[ : x == pivot1
+      //   2. for x in [less, k[ : pivot1 < x && x < pivot2
+      //   3. for x in ]great, * ] : x == pivot2
+      for (int k = less; k <= great; k++) {
+        var ak = a[k];
+        int comp_pivot1 = compare(ak, pivot1);
+        if (comp_pivot1 == 0) {
+          if (k != less) {
+            a[k] = a[less];
+            a[less] = ak;
+          }
+          less++;
+        } else {
+          int comp_pivot2 = compare(ak, pivot2);
+          if (comp_pivot2 == 0) {
+            while (true) {
+              int comp = compare(a[great], pivot2);
+              if (comp == 0) {
+                great--;
+                if (great < k) break;
+                // This is the only location inside the loop where a new
+                // iteration is started.
+                continue;
+              } else {
+                // a[great] < pivot2.
+                comp = compare(a[great], pivot1);
+                if (comp < 0) {
+                  // Triple exchange.
+                  a[k] = a[less];
+                  a[less++] = a[great];
+                  a[great--] = ak;
+                } else {
+                  // a[great] == pivot1.
+                  a[k] = a[great];
+                  a[great--] = ak;
+                }
+                break;
+              }
+            }
+          }
+        }
+      }
+      // The second partition has now been cleared of pivot elements and looks
+      // as follows:
+      // [  *  |  > pivot1 && < pivot2  | * ]
+      //        ^                      ^
+      //       less                  great
+      // Sort the second partition using recursive descent.
+      _doSort(a, less, great, compare);
+    } else {
+      // The second partition looks as follows:
+      // [  *  |  >= pivot1 && <= pivot2  | * ]
+      //        ^                        ^
+      //       less                    great
+      // Simply sort it by recursive descent.
+      _doSort(a, less, great, compare);
+    }
+  }
+}
diff --git a/sdk_nnbd/lib/internal/symbol.dart b/sdk_nnbd/lib/internal/symbol.dart
new file mode 100644
index 0000000..54d235c
--- /dev/null
+++ b/sdk_nnbd/lib/internal/symbol.dart
@@ -0,0 +1,142 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart._internal;
+
+/**
+ * Implementation of [core.Symbol].  This class uses the same name as
+ * a core class so a user can't tell the difference.
+ *
+ * The purpose of this class is to hide [_name] from user code, but
+ * make it accessible to Dart platform code via the static method
+ * [getName].
+ */
+class Symbol implements core.Symbol {
+  final String _name;
+
+  /**
+   * Source of RegExp matching Dart reserved words.
+   *
+   * Reserved words are not allowed as identifiers.
+   */
+  static const String reservedWordRE =
+      r'(?:assert|break|c(?:a(?:se|tch)|lass|on(?:st|tinue))|d(?:efault|o)|'
+      r'e(?:lse|num|xtends)|f(?:alse|inal(?:ly)?|or)|i[fns]|n(?:ew|ull)|'
+      r'ret(?:hrow|urn)|s(?:uper|witch)|t(?:h(?:is|row)|r(?:ue|y))|'
+      r'v(?:ar|oid)|w(?:hile|ith))';
+  /**
+   * Source of RegExp matching any public identifier.
+   *
+   * A public identifier is a valid identifier (not a reserved word)
+   * that doesn't start with '_'.
+   */
+  static const String publicIdentifierRE =
+      r'(?!' '$reservedWordRE' r'\b(?!\$))[a-zA-Z$][\w$]*';
+  /**
+   * Source of RegExp matching any identifier.
+   *
+   * It matches identifiers but not reserved words. The identifiers
+   * may start with '_'.
+   */
+  static const String identifierRE =
+      r'(?!' '$reservedWordRE' r'\b(?!\$))[a-zA-Z$_][\w$]*';
+  /**
+   * Source of RegExp matching a declarable operator names.
+   *
+   * The operators that can be declared using `operator` declarations are
+   * also the only ones allowed as symbols. The name of the operators is
+   * the same as the operator itself except for unary minus, where the name
+   * is "unary-".
+   */
+  static const String operatorRE =
+      r'(?:[\-+*/%&|^]|\[\]=?|==|~/?|<[<=]?|>[>=]?|unary-)';
+
+  // Grammar if symbols:
+  //    symbol ::= qualifiedName | <empty>
+  //    qualifiedName ::= publicIdentifier '.' qualifiedName | name
+  //    name ::= publicIdentifier
+  //           | publicIdentifier '='
+  //           | operator
+  // where publicIdentifier is any valid identifier (not a reserved word)
+  // that isn't private (doesn't start with '_').
+  //
+  // Railroad diagram of the accepted grammar:
+  //
+  //    /----------------\
+  //    |                |
+  //    |          /-[.]-/     /-[=]-\
+  //    \         /           /       \
+  //  -------[id]------------------------->
+  //       \                     /
+  //        \------[operator]---/
+  //            \              /
+  //             \------------/
+  //
+
+  /**
+   * RegExp that validates a non-empty non-private symbol.
+   *
+   * The empty symbol is handled before this regexp is used, and is not
+   * accepted.
+   */
+  static final RegExp publicSymbolPattern = new RegExp(
+      '^(?:$operatorRE\$|$publicIdentifierRE(?:=?\$|[.](?!\$)))+?\$');
+
+  // The grammar of symbols that may be private is the same as for public
+  // symbols, except that "publicIdentifier" is replaced by "identifier",
+  // which matches any identifier.
+
+  /**
+   * RegExp that validates a non-empty symbol.
+   *
+   * Private symbols are accepted.
+   *
+   * The empty symbol is handled before this regexp is used, and is not
+   * accepted.
+   */
+  static final RegExp symbolPattern =
+      new RegExp('^(?:$operatorRE\$|$identifierRE(?:=?\$|[.](?!\$)))+?\$');
+
+  external const Symbol(String name);
+
+  /**
+   * Platform-private method used by the mirror system to create
+   * otherwise invalid names.
+   */
+  const Symbol.unvalidated(this._name);
+
+  // This is called by dart2js.
+  Symbol.validated(String name) : this._name = validatePublicSymbol(name);
+
+  bool operator ==(other) => other is Symbol && _name == other._name;
+
+  external int get hashCode;
+
+  external toString();
+
+  /// Platform-private accessor which cannot be called from user libraries.
+  static String getName(Symbol symbol) => symbol._name;
+
+  static String validatePublicSymbol(String name) {
+    if (name.isEmpty || publicSymbolPattern.hasMatch(name)) return name;
+    if (name.startsWith('_')) {
+      // There may be other private parts in a qualified name than the first
+      // one, but this is a common case that deserves a specific error
+      // message.
+      throw new ArgumentError('"$name" is a private identifier');
+    }
+    throw new ArgumentError('"$name" is not a valid (qualified) symbol name');
+  }
+
+  /**
+   * Checks whether name is a valid symbol name.
+   *
+   * This test allows both private and non-private symbols.
+   */
+  static bool isValidSymbol(String name) {
+    return (name.isEmpty || symbolPattern.hasMatch(name));
+  }
+
+  external static String computeUnmangledName(Symbol symbol);
+}
diff --git a/sdk_nnbd/lib/io/bytes_builder.dart b/sdk_nnbd/lib/io/bytes_builder.dart
new file mode 100644
index 0000000..9113d44
--- /dev/null
+++ b/sdk_nnbd/lib/io/bytes_builder.dart
@@ -0,0 +1,233 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.io;
+
+/**
+ * Builds a list of bytes, allowing bytes and lists of bytes to be added at the
+ * end.
+ *
+ * Used to efficiently collect bytes and lists of bytes.
+ */
+abstract class BytesBuilder {
+  /**
+   * Construct a new empty [BytesBuilder].
+   *
+   * If [copy] is true, the data is always copied when added to the list. If
+   * it [copy] is false, the data is only copied if needed. That means that if
+   * the lists are changed after added to the [BytesBuilder], it may effect the
+   * output. Default is `true`.
+   */
+  factory BytesBuilder({bool copy: true}) {
+    if (copy) {
+      return new _CopyingBytesBuilder();
+    } else {
+      return new _BytesBuilder();
+    }
+  }
+
+  /**
+   * Appends [bytes] to the current contents of the builder.
+   *
+   * Each value of [bytes] will be bit-representation truncated to the range
+   * 0 .. 255.
+   */
+  void add(List<int> bytes);
+
+  /**
+   * Append [byte] to the current contents of the builder.
+   *
+   * The [byte] will be bit-representation truncated to the range 0 .. 255.
+   */
+  void addByte(int byte);
+
+  /**
+   * Returns the contents of `this` and clears `this`.
+   *
+   * The list returned is a view of the internal buffer, limited to the
+   * [length].
+   */
+  Uint8List takeBytes();
+
+  /**
+   * Returns a copy of the current contents of the builder.
+   *
+   * Leaves the contents of the builder intact.
+   */
+  Uint8List toBytes();
+
+  /**
+   * The number of bytes in the builder.
+   */
+  int get length;
+
+  /**
+   * Returns `true` if the buffer is empty.
+   */
+  bool get isEmpty;
+
+  /**
+   * Returns `true` if the buffer is not empty.
+   */
+  bool get isNotEmpty;
+
+  /**
+   * Clear the contents of the builder.
+   */
+  void clear();
+}
+
+class _CopyingBytesBuilder implements BytesBuilder {
+  // Start with 1024 bytes.
+  static const int _initSize = 1024;
+
+  // Safe for reuse because a fixed-length empty list is immutable.
+  static final _emptyList = new Uint8List(0);
+
+  int _length = 0;
+  Uint8List _buffer;
+
+  _CopyingBytesBuilder([int initialCapacity = 0])
+      : _buffer = (initialCapacity <= 0)
+            ? _emptyList
+            : new Uint8List(_pow2roundup(initialCapacity));
+
+  void add(List<int> bytes) {
+    int bytesLength = bytes.length;
+    if (bytesLength == 0) return;
+    int required = _length + bytesLength;
+    if (_buffer.length < required) {
+      _grow(required);
+    }
+    assert(_buffer.length >= required);
+    if (bytes is Uint8List) {
+      _buffer.setRange(_length, required, bytes);
+    } else {
+      for (int i = 0; i < bytesLength; i++) {
+        _buffer[_length + i] = bytes[i];
+      }
+    }
+    _length = required;
+  }
+
+  void addByte(int byte) {
+    if (_buffer.length == _length) {
+      // The grow algorithm always at least doubles.
+      // If we added one to _length it would quadruple unnecessarily.
+      _grow(_length);
+    }
+    assert(_buffer.length > _length);
+    _buffer[_length] = byte;
+    _length++;
+  }
+
+  void _grow(int required) {
+    // We will create a list in the range of 2-4 times larger than
+    // required.
+    int newSize = required * 2;
+    if (newSize < _initSize) {
+      newSize = _initSize;
+    } else {
+      newSize = _pow2roundup(newSize);
+    }
+    var newBuffer = new Uint8List(newSize);
+    newBuffer.setRange(0, _buffer.length, _buffer);
+    _buffer = newBuffer;
+  }
+
+  Uint8List takeBytes() {
+    if (_length == 0) return _emptyList;
+    var buffer = new Uint8List.view(_buffer.buffer, 0, _length);
+    clear();
+    return buffer;
+  }
+
+  Uint8List toBytes() {
+    if (_length == 0) return _emptyList;
+    return new Uint8List.fromList(
+        new Uint8List.view(_buffer.buffer, 0, _length));
+  }
+
+  int get length => _length;
+
+  bool get isEmpty => _length == 0;
+
+  bool get isNotEmpty => _length != 0;
+
+  void clear() {
+    _length = 0;
+    _buffer = _emptyList;
+  }
+
+  static int _pow2roundup(int x) {
+    assert(x > 0);
+    --x;
+    x |= x >> 1;
+    x |= x >> 2;
+    x |= x >> 4;
+    x |= x >> 8;
+    x |= x >> 16;
+    return x + 1;
+  }
+}
+
+class _BytesBuilder implements BytesBuilder {
+  int _length = 0;
+  final List<Uint8List> _chunks = [];
+
+  void add(List<int> bytes) {
+    Uint8List typedBytes;
+    if (bytes is Uint8List) {
+      typedBytes = bytes;
+    } else {
+      typedBytes = new Uint8List.fromList(bytes);
+    }
+    _chunks.add(typedBytes);
+    _length += typedBytes.length;
+  }
+
+  void addByte(int byte) {
+    _chunks.add(new Uint8List(1)..[0] = byte);
+    _length++;
+  }
+
+  Uint8List takeBytes() {
+    if (_length == 0) return _CopyingBytesBuilder._emptyList;
+    if (_chunks.length == 1) {
+      var buffer = _chunks[0];
+      clear();
+      return buffer;
+    }
+    var buffer = new Uint8List(_length);
+    int offset = 0;
+    for (var chunk in _chunks) {
+      buffer.setRange(offset, offset + chunk.length, chunk);
+      offset += chunk.length;
+    }
+    clear();
+    return buffer;
+  }
+
+  Uint8List toBytes() {
+    if (_length == 0) return _CopyingBytesBuilder._emptyList;
+    var buffer = new Uint8List(_length);
+    int offset = 0;
+    for (var chunk in _chunks) {
+      buffer.setRange(offset, offset + chunk.length, chunk);
+      offset += chunk.length;
+    }
+    return buffer;
+  }
+
+  int get length => _length;
+
+  bool get isEmpty => _length == 0;
+
+  bool get isNotEmpty => _length != 0;
+
+  void clear() {
+    _length = 0;
+    _chunks.clear();
+  }
+}
diff --git a/sdk_nnbd/lib/io/common.dart b/sdk_nnbd/lib/io/common.dart
new file mode 100644
index 0000000..77b7587
--- /dev/null
+++ b/sdk_nnbd/lib/io/common.dart
@@ -0,0 +1,117 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.io;
+
+// Constants used when working with native ports.
+// These must match the constants in runtime/bin/dartutils.h class CObject.
+const int _successResponse = 0;
+const int _illegalArgumentResponse = 1;
+const int _osErrorResponse = 2;
+const int _fileClosedResponse = 3;
+
+const int _errorResponseErrorType = 0;
+const int _osErrorResponseErrorCode = 1;
+const int _osErrorResponseMessage = 2;
+
+// Functions used to receive exceptions from native ports.
+bool _isErrorResponse(response) =>
+    response is List && response[0] != _successResponse;
+
+/**
+ * Returns an Exception or an Error
+ */
+_exceptionFromResponse(response, String message, String path) {
+  assert(_isErrorResponse(response));
+  switch (response[_errorResponseErrorType]) {
+    case _illegalArgumentResponse:
+      return new ArgumentError("$message: $path");
+    case _osErrorResponse:
+      var err = new OSError(response[_osErrorResponseMessage],
+          response[_osErrorResponseErrorCode]);
+      return new FileSystemException(message, path, err);
+    case _fileClosedResponse:
+      return new FileSystemException("File closed", path);
+    default:
+      return new Exception("Unknown error");
+  }
+}
+
+/**
+ * Base class for all IO related exceptions.
+ */
+abstract class IOException implements Exception {
+  String toString() => "IOException";
+}
+
+/**
+  * An [OSError] object holds information about an error from the
+  * operating system.
+  */
+@pragma("vm:entry-point")
+class OSError {
+  /** Constant used to indicate that no OS error code is available. */
+  static const int noErrorCode = -1;
+
+  /// Error message supplied by the operating system. This may be `null` or
+  /// empty if no message is associated with the error.
+  final String message;
+
+  /// Error code supplied by the operating system.
+  ///
+  /// Will have the value [OSError.noErrorCode] if there is no error code
+  /// associated with the error.
+  final int errorCode;
+
+  /** Creates an OSError object from a message and an errorCode. */
+  @pragma("vm:entry-point")
+  const OSError([this.message = "", this.errorCode = noErrorCode]);
+
+  /** Converts an OSError object to a string representation. */
+  String toString() {
+    StringBuffer sb = new StringBuffer();
+    sb.write("OS Error");
+    if (message.isNotEmpty) {
+      sb..write(": ")..write(message);
+      if (errorCode != noErrorCode) {
+        sb..write(", errno = ")..write(errorCode.toString());
+      }
+    } else if (errorCode != noErrorCode) {
+      sb..write(": errno = ")..write(errorCode.toString());
+    }
+    return sb.toString();
+  }
+}
+
+// Object for holding a buffer and an offset.
+class _BufferAndStart {
+  List<int> buffer;
+  int start;
+  _BufferAndStart(this.buffer, this.start);
+}
+
+// Ensure that the input List can be serialized through a native port.
+// Only Int8List and Uint8List Lists are serialized directly.
+// All other lists are first copied into a Uint8List. This has the added
+// benefit that it is faster to access from the C code as well.
+_BufferAndStart _ensureFastAndSerializableByteData(
+    List<int> buffer, int start, int end) {
+  if (buffer is Uint8List || buffer is Int8List) {
+    return new _BufferAndStart(buffer, start);
+  }
+  int length = end - start;
+  var newBuffer = new Uint8List(length);
+  int j = start;
+  for (int i = 0; i < length; i++) {
+    int value = buffer[j];
+    if (value == null) throw ArgumentError("List element is null at index $j");
+    newBuffer[i] = value;
+    j++;
+  }
+  return new _BufferAndStart(newBuffer, 0);
+}
+
+class _IOCrypto {
+  external static Uint8List getRandomBytes(int count);
+}
diff --git a/sdk_nnbd/lib/io/data_transformer.dart b/sdk_nnbd/lib/io/data_transformer.dart
new file mode 100644
index 0000000..33c615d
--- /dev/null
+++ b/sdk_nnbd/lib/io/data_transformer.dart
@@ -0,0 +1,673 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.io;
+
+/**
+ * Exposes ZLib options for input parameters.
+ *
+ * See http://www.zlib.net/manual.html for more documentation.
+ */
+abstract class ZLibOption {
+  /// Minimal value for [ZLibCodec.windowBits], [ZLibEncoder.windowBits]
+  /// and [ZLibDecoder.windowBits].
+  static const int minWindowBits = 8;
+  @Deprecated("Use minWindowBits instead")
+  static const int MIN_WINDOW_BITS = 8;
+
+  /// Maximal value for [ZLibCodec.windowBits], [ZLibEncoder.windowBits]
+  /// and [ZLibDecoder.windowBits].
+  static const int maxWindowBits = 15;
+  @Deprecated("Use maxWindowBits instead")
+  static const int MAX_WINDOW_BITS = 15;
+
+  /// Default value for [ZLibCodec.windowBits], [ZLibEncoder.windowBits]
+  /// and [ZLibDecoder.windowBits].
+  static const int defaultWindowBits = 15;
+  @Deprecated("Use defaultWindowBits instead")
+  static const int DEFAULT_WINDOW_BITS = 15;
+
+  /// Minimal value for [ZLibCodec.level] and [ZLibEncoder.level].
+  static const int minLevel = -1;
+  @Deprecated("Use minLevel instead")
+  static const int MIN_LEVEL = -1;
+
+  /// Maximal value for [ZLibCodec.level] and [ZLibEncoder.level]
+  static const int maxLevel = 9;
+  @Deprecated("Use maxLevel instead")
+  static const int MAX_LEVEL = 9;
+
+  /// Default value for [ZLibCodec.level] and [ZLibEncoder.level].
+  static const int defaultLevel = 6;
+  @Deprecated("Use defaultLevel instead")
+  static const int DEFAULT_LEVEL = 6;
+
+  /// Minimal value for [ZLibCodec.memLevel] and [ZLibEncoder.memLevel].
+  static const int minMemLevel = 1;
+  @Deprecated("Use minMemLevel instead")
+  static const int MIN_MEM_LEVEL = 1;
+
+  /// Maximal value for [ZLibCodec.memLevel] and [ZLibEncoder.memLevel].
+  static const int maxMemLevel = 9;
+  @Deprecated("Use maxMemLevel instead")
+  static const int MAX_MEM_LEVEL = 9;
+
+  /// Default value for [ZLibCodec.memLevel] and [ZLibEncoder.memLevel].
+  static const int defaultMemLevel = 8;
+  @Deprecated("Use defaultMemLevel instead")
+  static const int DEFAULT_MEM_LEVEL = 8;
+
+  /// Recommended strategy for data produced by a filter (or predictor)
+  static const int strategyFiltered = 1;
+  @Deprecated("Use strategyFiltered instead")
+  static const int STRATEGY_FILTERED = 1;
+
+  /// Use this strategy to force Huffman encoding only (no string match)
+  static const int strategyHuffmanOnly = 2;
+  @Deprecated("Use strategyHuffmanOnly instead")
+  static const int STRATEGY_HUFFMAN_ONLY = 2;
+
+  /// Use this strategy to limit match distances to one (run-length encoding)
+  static const int strategyRle = 3;
+  @Deprecated("Use strategyRle instead")
+  static const int STRATEGY_RLE = 3;
+
+  /// This strategy prevents the use of dynamic Huffman codes, allowing for a
+  /// simpler decoder
+  static const int strategyFixed = 4;
+  @Deprecated("Use strategyFixed instead")
+  static const int STRATEGY_FIXED = 4;
+
+  /// Recommended strategy for normal data
+  static const int strategyDefault = 0;
+  @Deprecated("Use strategyDefault instead")
+  static const int STRATEGY_DEFAULT = 0;
+}
+
+/**
+ * An instance of the default implementation of the [ZLibCodec].
+ */
+const ZLibCodec zlib = const ZLibCodec._default();
+@Deprecated("Use zlib instead")
+const ZLibCodec ZLIB = zlib;
+
+/**
+ * The [ZLibCodec] encodes raw bytes to ZLib compressed bytes and decodes ZLib
+ * compressed bytes to raw bytes.
+ */
+class ZLibCodec extends Codec<List<int>, List<int>> {
+  /**
+   * When true, `GZip` frames will be added to the compressed data.
+   */
+  final bool gzip;
+
+  /**
+   * The compression-[level] can be set in the range of `-1..9`, with `6` being
+   * the default compression level. Levels above `6` will have higher
+   * compression rates at the cost of more CPU and memory usage. Levels below
+   * `6` will use less CPU and memory at the cost of lower compression rates.
+   */
+  final int level;
+
+  /**
+   * Specifies how much memory should be allocated for the internal compression
+   * state. `1` uses minimum memory but is slow and reduces compression ratio;
+   * `9` uses maximum memory for optimal speed. The default value is `8`.
+   *
+   * The memory requirements for deflate are (in bytes):
+   *
+   *     (1 << (windowBits + 2)) +  (1 << (memLevel + 9))
+   * that is: 128K for windowBits = 15 + 128K for memLevel = 8 (default values)
+   */
+  final int memLevel;
+
+  /**
+   * Tunes the compression algorithm. Use the value strategyDefault for normal
+   * data, strategyFiltered for data produced by a filter (or predictor),
+   * strategyHuffmanOnly to force Huffman encoding only (no string match), or
+   * strategyRle to limit match distances to one (run-length encoding).
+   */
+  final int strategy;
+
+  /**
+   * Base two logarithm of the window size (the size of the history buffer). It
+   * should be in the range 8..15. Larger values result in better compression at
+   * the expense of memory usage. The default value is 15
+   */
+  final int windowBits;
+
+  /**
+   * When true, deflate generates raw data with no zlib header or trailer, and
+   * will not compute an adler32 check value
+   */
+  final bool raw;
+
+  /**
+   * Initial compression dictionary.
+   *
+   * It should consist of strings (byte sequences) that are likely to be
+   * encountered later in the data to be compressed, with the most commonly used
+   * strings preferably put towards the end of the dictionary. Using a
+   * dictionary is most useful when the data to be compressed is short and can
+   * be predicted with good accuracy; the data can then be compressed better
+   * than with the default empty dictionary.
+   */
+  final List<int> dictionary;
+
+  ZLibCodec(
+      {this.level: ZLibOption.defaultLevel,
+      this.windowBits: ZLibOption.defaultWindowBits,
+      this.memLevel: ZLibOption.defaultMemLevel,
+      this.strategy: ZLibOption.strategyDefault,
+      this.dictionary,
+      this.raw: false,
+      this.gzip: false}) {
+    _validateZLibeLevel(level);
+    _validateZLibMemLevel(memLevel);
+    _validateZLibStrategy(strategy);
+    _validateZLibWindowBits(windowBits);
+  }
+
+  const ZLibCodec._default()
+      : level = ZLibOption.defaultLevel,
+        windowBits = ZLibOption.defaultWindowBits,
+        memLevel = ZLibOption.defaultMemLevel,
+        strategy = ZLibOption.strategyDefault,
+        raw = false,
+        gzip = false,
+        dictionary = null;
+
+  /**
+   * Get a [ZLibEncoder] for encoding to `ZLib` compressed data.
+   */
+  ZLibEncoder get encoder => new ZLibEncoder(
+      gzip: false,
+      level: level,
+      windowBits: windowBits,
+      memLevel: memLevel,
+      strategy: strategy,
+      dictionary: dictionary,
+      raw: raw);
+
+  /**
+   * Get a [ZLibDecoder] for decoding `ZLib` compressed data.
+   */
+  ZLibDecoder get decoder =>
+      new ZLibDecoder(windowBits: windowBits, dictionary: dictionary, raw: raw);
+}
+
+/**
+ * An instance of the default implementation of the [GZipCodec].
+ */
+const GZipCodec gzip = const GZipCodec._default();
+@Deprecated("Use gzip instead")
+const GZipCodec GZIP = gzip;
+
+/**
+ * The [GZipCodec] encodes raw bytes to GZip compressed bytes and decodes GZip
+ * compressed bytes to raw bytes.
+ *
+ * The difference between [ZLibCodec] and [GZipCodec] is that the [GZipCodec]
+ * wraps the `ZLib` compressed bytes in `GZip` frames.
+ */
+class GZipCodec extends Codec<List<int>, List<int>> {
+  /**
+   * When true, `GZip` frames will be added to the compressed data.
+   */
+  final bool gzip;
+
+  /**
+   * The compression-[level] can be set in the range of `-1..9`, with `6` being
+   * the default compression level. Levels above `6` will have higher
+   * compression rates at the cost of more CPU and memory usage. Levels below
+   * `6` will use less CPU and memory at the cost of lower compression rates.
+   */
+  final int level;
+
+  /**
+   * Specifies how much memory should be allocated for the internal compression
+   * state. `1` uses minimum memory but is slow and reduces compression ratio;
+   * `9` uses maximum memory for optimal speed. The default value is `8`.
+   *
+   * The memory requirements for deflate are (in bytes):
+   *
+   *     (1 << (windowBits + 2)) +  (1 << (memLevel + 9))
+   * that is: 128K for windowBits = 15 + 128K for memLevel = 8 (default values)
+   */
+  final int memLevel;
+
+  /**
+   * Tunes the compression algorithm. Use the value
+   * [ZLibOption.strategyDefault] for normal data,
+   * [ZLibOption.strategyFiltered] for data produced by a filter
+   * (or predictor), [ZLibOption.strategyHuffmanOnly] to force Huffman
+   * encoding only (no string match), or [ZLibOption.strategyRle] to limit
+   * match distances to one (run-length encoding).
+   */
+  final int strategy;
+
+  /**
+   * Base two logarithm of the window size (the size of the history buffer). It
+   * should be in the range `8..15`. Larger values result in better compression
+   * at the expense of memory usage. The default value is `15`
+   */
+  final int windowBits;
+
+  /**
+   * Initial compression dictionary.
+   *
+   * It should consist of strings (byte sequences) that are likely to be
+   * encountered later in the data to be compressed, with the most commonly used
+   * strings preferably put towards the end of the dictionary. Using a
+   * dictionary is most useful when the data to be compressed is short and can
+   * be predicted with good accuracy; the data can then be compressed better
+   * than with the default empty dictionary.
+   */
+  final List<int> dictionary;
+
+  /**
+   * When true, deflate generates raw data with no zlib header or trailer, and
+   * will not compute an adler32 check value
+   */
+  final bool raw;
+
+  GZipCodec(
+      {this.level: ZLibOption.defaultLevel,
+      this.windowBits: ZLibOption.defaultWindowBits,
+      this.memLevel: ZLibOption.defaultMemLevel,
+      this.strategy: ZLibOption.strategyDefault,
+      this.dictionary,
+      this.raw: false,
+      this.gzip: true}) {
+    _validateZLibeLevel(level);
+    _validateZLibMemLevel(memLevel);
+    _validateZLibStrategy(strategy);
+    _validateZLibWindowBits(windowBits);
+  }
+
+  const GZipCodec._default()
+      : level = ZLibOption.defaultLevel,
+        windowBits = ZLibOption.defaultWindowBits,
+        memLevel = ZLibOption.defaultMemLevel,
+        strategy = ZLibOption.strategyDefault,
+        raw = false,
+        gzip = true,
+        dictionary = null;
+
+  /**
+   * Get a [ZLibEncoder] for encoding to `GZip` compressed data.
+   */
+  ZLibEncoder get encoder => new ZLibEncoder(
+      gzip: true,
+      level: level,
+      windowBits: windowBits,
+      memLevel: memLevel,
+      strategy: strategy,
+      dictionary: dictionary,
+      raw: raw);
+
+  /**
+   * Get a [ZLibDecoder] for decoding `GZip` compressed data.
+   */
+  ZLibDecoder get decoder =>
+      new ZLibDecoder(windowBits: windowBits, dictionary: dictionary, raw: raw);
+}
+
+/**
+ * The [ZLibEncoder] encoder is used by [ZLibCodec] and [GZipCodec] to compress
+ * data.
+ */
+class ZLibEncoder extends Converter<List<int>, List<int>> {
+  /**
+   * When true, `GZip` frames will be added to the compressed data.
+   */
+  final bool gzip;
+
+  /**
+   * The compression-[level] can be set in the range of `-1..9`, with `6` being
+   * the default compression level. Levels above `6` will have higher
+   * compression rates at the cost of more CPU and memory usage. Levels below
+   * `6` will use less CPU and memory at the cost of lower compression rates.
+   */
+  final int level;
+
+  /**
+   * Specifies how much memory should be allocated for the internal compression
+   * state. `1` uses minimum memory but is slow and reduces compression ratio;
+   * `9` uses maximum memory for optimal speed. The default value is `8`.
+   *
+   * The memory requirements for deflate are (in bytes):
+   *
+   *     (1 << (windowBits + 2)) +  (1 << (memLevel + 9))
+   * that is: 128K for windowBits = 15 + 128K for memLevel = 8 (default values)
+   */
+  final int memLevel;
+
+  /**
+   * Tunes the compression algorithm. Use the value
+   * [ZLibOption.strategyDefault] for normal data,
+   * [ZLibOption.strategyFiltered] for data produced by a filter
+   * (or predictor), [ZLibOption.strategyHuffmanOnly] to force Huffman
+   * encoding only (no string match), or [ZLibOption.strategyRle] to limit
+   * match distances to one (run-length encoding).
+   */
+  final int strategy;
+
+  /**
+   * Base two logarithm of the window size (the size of the history buffer). It
+   * should be in the range `8..15`. Larger values result in better compression
+   * at the expense of memory usage. The default value is `15`
+   */
+  final int windowBits;
+
+  /**
+   * Initial compression dictionary.
+   *
+   * It should consist of strings (byte sequences) that are likely to be
+   * encountered later in the data to be compressed, with the most commonly used
+   * strings preferably put towards the end of the dictionary. Using a
+   * dictionary is most useful when the data to be compressed is short and can
+   * be predicted with good accuracy; the data can then be compressed better
+   * than with the default empty dictionary.
+   */
+  final List<int> dictionary;
+
+  /**
+   * When true, deflate generates raw data with no zlib header or trailer, and
+   * will not compute an adler32 check value
+   */
+  final bool raw;
+
+  ZLibEncoder(
+      {this.gzip: false,
+      this.level: ZLibOption.defaultLevel,
+      this.windowBits: ZLibOption.defaultWindowBits,
+      this.memLevel: ZLibOption.defaultMemLevel,
+      this.strategy: ZLibOption.strategyDefault,
+      this.dictionary,
+      this.raw: false}) {
+    _validateZLibeLevel(level);
+    _validateZLibMemLevel(memLevel);
+    _validateZLibStrategy(strategy);
+    _validateZLibWindowBits(windowBits);
+  }
+
+  /**
+   * Convert a list of bytes using the options given to the ZLibEncoder
+   * constructor.
+   */
+  List<int> convert(List<int> bytes) {
+    _BufferSink sink = new _BufferSink();
+    startChunkedConversion(sink)
+      ..add(bytes)
+      ..close();
+    return sink.builder.takeBytes();
+  }
+
+  /**
+   * Start a chunked conversion using the options given to the [ZLibEncoder]
+   * constructor. While it accepts any [Sink] taking [List<int>]'s,
+   * the optimal sink to be passed as [sink] is a [ByteConversionSink].
+   */
+  ByteConversionSink startChunkedConversion(Sink<List<int>> sink) {
+    if (sink is! ByteConversionSink) {
+      sink = new ByteConversionSink.from(sink);
+    }
+    return new _ZLibEncoderSink._(
+        sink, gzip, level, windowBits, memLevel, strategy, dictionary, raw);
+  }
+}
+
+/**
+ * The [ZLibDecoder] is used by [ZLibCodec] and [GZipCodec] to decompress data.
+ */
+class ZLibDecoder extends Converter<List<int>, List<int>> {
+  /**
+   * Base two logarithm of the window size (the size of the history buffer). It
+   * should be in the range `8..15`. Larger values result in better compression
+   * at the expense of memory usage. The default value is `15`.
+   */
+  final int windowBits;
+
+  /**
+   * Initial compression dictionary.
+   *
+   * It should consist of strings (byte sequences) that are likely to be
+   * encountered later in the data to be compressed, with the most commonly used
+   * strings preferably put towards the end of the dictionary. Using a
+   * dictionary is most useful when the data to be compressed is short and can
+   * be predicted with good accuracy; the data can then be compressed better
+   * than with the default empty dictionary.
+   */
+  final List<int> dictionary;
+
+  /**
+   * When true, deflate generates raw data with no zlib header or trailer, and
+   * will not compute an adler32 check value
+   */
+  final bool raw;
+
+  ZLibDecoder(
+      {this.windowBits: ZLibOption.defaultWindowBits,
+      this.dictionary,
+      this.raw: false}) {
+    _validateZLibWindowBits(windowBits);
+  }
+
+  /**
+   * Convert a list of bytes using the options given to the [ZLibDecoder]
+   * constructor.
+   */
+  List<int> convert(List<int> bytes) {
+    _BufferSink sink = new _BufferSink();
+    startChunkedConversion(sink)
+      ..add(bytes)
+      ..close();
+    return sink.builder.takeBytes();
+  }
+
+  /**
+   * Start a chunked conversion. While it accepts any [Sink]
+   * taking [List<int>]'s, the optimal sink to be passed as [sink] is a
+   * [ByteConversionSink].
+   */
+  ByteConversionSink startChunkedConversion(Sink<List<int>> sink) {
+    if (sink is! ByteConversionSink) {
+      sink = new ByteConversionSink.from(sink);
+    }
+    return new _ZLibDecoderSink._(sink, windowBits, dictionary, raw);
+  }
+}
+
+/**
+ * The [RawZLibFilter] class provides a low-level interface to zlib.
+ */
+abstract class RawZLibFilter {
+  /**
+   * Returns a a [RawZLibFilter] whose [process] and [processed] methods
+   * compress data.
+   */
+  factory RawZLibFilter.deflateFilter({
+    bool gzip: false,
+    int level: ZLibOption.defaultLevel,
+    int windowBits: ZLibOption.defaultWindowBits,
+    int memLevel: ZLibOption.defaultMemLevel,
+    int strategy: ZLibOption.strategyDefault,
+    List<int> dictionary,
+    bool raw: false,
+  }) {
+    return _makeZLibDeflateFilter(
+        gzip, level, windowBits, memLevel, strategy, dictionary, raw);
+  }
+
+  /**
+   * Returns a a [RawZLibFilter] whose [process] and [processed] methods
+   * decompress data.
+   */
+  factory RawZLibFilter.inflateFilter({
+    int windowBits: ZLibOption.defaultWindowBits,
+    List<int> dictionary,
+    bool raw: false,
+  }) {
+    return _makeZLibInflateFilter(windowBits, dictionary, raw);
+  }
+
+  /**
+   * Call to process a chunk of data. A call to [process] should only be made
+   * when [processed] returns [:null:].
+   */
+  void process(List<int> data, int start, int end);
+
+  /**
+   * Get a chunk of processed data. When there are no more data available,
+   * [processed] will return [:null:]. Set [flush] to [:false:] for non-final
+   * calls to improve performance of some filters.
+   *
+   * The last call to [processed] should have [end] set to [:true:]. This will
+   * make sure an 'end' packet is written on the stream.
+   */
+  List<int> processed({bool flush: true, bool end: false});
+
+  external static RawZLibFilter _makeZLibDeflateFilter(
+      bool gzip,
+      int level,
+      int windowBits,
+      int memLevel,
+      int strategy,
+      List<int> dictionary,
+      bool raw);
+
+  external static RawZLibFilter _makeZLibInflateFilter(
+      int windowBits, List<int> dictionary, bool raw);
+}
+
+class _BufferSink extends ByteConversionSink {
+  final BytesBuilder builder = new BytesBuilder(copy: false);
+
+  void add(List<int> chunk) {
+    builder.add(chunk);
+  }
+
+  void addSlice(List<int> chunk, int start, int end, bool isLast) {
+    if (chunk is Uint8List) {
+      Uint8List list = chunk;
+      builder.add(new Uint8List.view(list.buffer, start, end - start));
+    } else {
+      builder.add(chunk.sublist(start, end));
+    }
+  }
+
+  void close() {}
+}
+
+class _ZLibEncoderSink extends _FilterSink {
+  _ZLibEncoderSink._(
+      ByteConversionSink sink,
+      bool gzip,
+      int level,
+      int windowBits,
+      int memLevel,
+      int strategy,
+      List<int> dictionary,
+      bool raw)
+      : super(
+            sink,
+            RawZLibFilter._makeZLibDeflateFilter(
+                gzip, level, windowBits, memLevel, strategy, dictionary, raw));
+}
+
+class _ZLibDecoderSink extends _FilterSink {
+  _ZLibDecoderSink._(
+      ByteConversionSink sink, int windowBits, List<int> dictionary, bool raw)
+      : super(sink,
+            RawZLibFilter._makeZLibInflateFilter(windowBits, dictionary, raw));
+}
+
+class _FilterSink extends ByteConversionSink {
+  final RawZLibFilter _filter;
+  final ByteConversionSink _sink;
+  bool _closed = false;
+  bool _empty = true;
+
+  _FilterSink(this._sink, this._filter);
+
+  void add(List<int> data) {
+    addSlice(data, 0, data.length, false);
+  }
+
+  void addSlice(List<int> data, int start, int end, bool isLast) {
+    if (_closed) return;
+    if (end == null) throw new ArgumentError.notNull("end");
+    RangeError.checkValidRange(start, end, data.length);
+    try {
+      _empty = false;
+      _BufferAndStart bufferAndStart =
+          _ensureFastAndSerializableByteData(data, start, end);
+      _filter.process(bufferAndStart.buffer, bufferAndStart.start,
+          end - (start - bufferAndStart.start));
+      List<int> out;
+      while ((out = _filter.processed(flush: false)) != null) {
+        _sink.add(out);
+      }
+    } catch (e) {
+      _closed = true;
+      rethrow;
+    }
+
+    if (isLast) close();
+  }
+
+  void close() {
+    if (_closed) return;
+    // Be sure to send process an empty chunk of data. Without this, the empty
+    // message would not have a GZip frame (if compressed with GZip).
+    if (_empty) _filter.process(const [], 0, 0);
+    try {
+      List<int> out;
+      while ((out = _filter.processed(end: true)) != null) {
+        _sink.add(out);
+      }
+    } catch (e) {
+      // TODO(kevmoo): not sure why this isn't a try/finally
+      _closed = true;
+      throw e;
+    }
+    _closed = true;
+    _sink.close();
+  }
+}
+
+void _validateZLibWindowBits(int windowBits) {
+  if (ZLibOption.minWindowBits > windowBits ||
+      ZLibOption.maxWindowBits < windowBits) {
+    throw new RangeError.range(
+        windowBits, ZLibOption.minWindowBits, ZLibOption.maxWindowBits);
+  }
+}
+
+void _validateZLibeLevel(int level) {
+  if (ZLibOption.minLevel > level || ZLibOption.maxLevel < level) {
+    throw new RangeError.range(level, ZLibOption.minLevel, ZLibOption.maxLevel);
+  }
+}
+
+void _validateZLibMemLevel(int memLevel) {
+  if (ZLibOption.minMemLevel > memLevel || ZLibOption.maxMemLevel < memLevel) {
+    throw new RangeError.range(
+        memLevel, ZLibOption.minMemLevel, ZLibOption.maxMemLevel);
+  }
+}
+
+void _validateZLibStrategy(int strategy) {
+  const strategies = const <int>[
+    ZLibOption.strategyFiltered,
+    ZLibOption.strategyHuffmanOnly,
+    ZLibOption.strategyRle,
+    ZLibOption.strategyFixed,
+    ZLibOption.strategyDefault
+  ];
+  if (strategies.indexOf(strategy) == -1) {
+    throw new ArgumentError("Unsupported 'strategy'");
+  }
+}
diff --git a/sdk_nnbd/lib/io/directory.dart b/sdk_nnbd/lib/io/directory.dart
new file mode 100644
index 0000000..2f141cb
--- /dev/null
+++ b/sdk_nnbd/lib/io/directory.dart
@@ -0,0 +1,344 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.io;
+
+/**
+ * A reference to a directory (or _folder_) on the file system.
+ *
+ * A Directory instance is an object holding a [path] on which operations can
+ * be performed. The path to the directory can be [absolute] or relative.
+ * You can get the parent directory using the getter [parent],
+ * a property inherited from [FileSystemEntity].
+ *
+ * In addition to being used as an instance to access the file system,
+ * Directory has a number of static properties, such as [systemTemp],
+ * which gets the system's temporary directory, and the getter and setter
+ * [current], which you can use to access or change the current directory.
+ *
+ * Create a new Directory object with a pathname to access the specified
+ * directory on the file system from your program.
+ *
+ *     var myDir = new Directory('myDir');
+ *
+ * Most methods in this class occur in synchronous and asynchronous pairs,
+ * for example, [create] and [createSync].
+ * Unless you have a specific reason for using the synchronous version
+ * of a method, prefer the asynchronous version to avoid blocking your program.
+ *
+ * ## Create a directory
+ *
+ * The following code sample creates a directory using the [create] method.
+ * By setting the `recursive` parameter to true, you can create the
+ * named directory and all its necessary parent directories,
+ * if they do not already exist.
+ *
+ *     import 'dart:io';
+ *
+ *     void main() {
+ *       // Creates dir/ and dir/subdir/.
+ *       new Directory('dir/subdir').create(recursive: true)
+ *         // The created directory is returned as a Future.
+ *         .then((Directory directory) {
+ *           print(directory.path);
+ *       });
+ *     }
+ *
+ * ## List a directory
+ *
+ * Use the [list] or [listSync] methods to get the files and directories
+ * contained by a directory.
+ * Set `recursive` to true to recursively list all subdirectories.
+ * Set `followLinks` to true to follow symbolic links.
+ * The list method returns a [Stream] that provides FileSystemEntity
+ * objects. Use the listen callback function to process each object
+ * as it become available.
+ *
+ *     import 'dart:io';
+ *
+ *     void main() {
+ *       // Get the system temp directory.
+ *       var systemTempDir = Directory.systemTemp;
+ *
+ *       // List directory contents, recursing into sub-directories,
+ *       // but not following symbolic links.
+ *       systemTempDir.list(recursive: true, followLinks: false)
+ *         .listen((FileSystemEntity entity) {
+ *           print(entity.path);
+ *         });
+ *     }
+ *
+ * ## The use of Futures
+ *
+ * I/O operations can block a program for some period of time while it waits for
+ * the operation to complete. To avoid this, all
+ * methods involving I/O have an asynchronous variant which returns a [Future].
+ * This future completes when the I/O operation finishes. While the I/O
+ * operation is in progress, the Dart program is not blocked,
+ * and can perform other operations.
+ *
+ * For example,
+ * the [exists] method, which determines whether the directory exists,
+ * returns a boolean value using a Future.
+ * Use `then` to register a callback function, which is called when
+ * the value is ready.
+ *
+ *     import 'dart:io';
+ *
+ *     main() {
+ *       final myDir = new Directory('dir');
+ *       myDir.exists().then((isThere) {
+ *         isThere ? print('exists') : print('non-existent');
+ *       });
+ *     }
+ *
+ *
+ * In addition to exists, the [stat], [rename], and
+ * other methods, return Futures.
+ *
+ * ## Other resources
+ *
+ * * [Dart by Example](https://www.dartlang.org/dart-by-example/#files-directories-and-symlinks)
+ *   provides additional task-oriented code samples that show how to use
+ *   various API from the Directory class and the related [File] class.
+ *
+ * * [I/O for Command-Line
+ *   Apps](https://www.dartlang.org/docs/dart-up-and-running/ch03.html#dartio---io-for-command-line-apps)
+ *   a section from _A Tour of the Dart Libraries_ covers files and directories.
+ *
+ * * [Write Command-Line Apps](https://www.dartlang.org/docs/tutorials/cmdline/),
+ *   a tutorial about writing command-line apps, includes information about
+ *   files and directories.
+ */
+@pragma("vm:entry-point")
+abstract class Directory implements FileSystemEntity {
+  /**
+   * Gets the path of this directory.
+   */
+  String get path;
+
+  /**
+   * Creates a [Directory] object.
+   *
+   * If [path] is a relative path, it will be interpreted relative to the
+   * current working directory (see [Directory.current]), when used.
+   *
+   * If [path] is an absolute path, it will be immune to changes to the
+   * current working directory.
+   */
+  @pragma("vm:entry-point")
+  factory Directory(String path) {
+    final IOOverrides overrides = IOOverrides.current;
+    if (overrides == null) {
+      return new _Directory(path);
+    }
+    return overrides.createDirectory(path);
+  }
+
+  @pragma("vm:entry-point")
+  factory Directory.fromRawPath(Uint8List path) {
+    // TODO(bkonyi): Handle overrides.
+    return new _Directory.fromRawPath(path);
+  }
+
+  /**
+   * Create a Directory object from a URI.
+   *
+   * If [uri] cannot reference a directory this throws [UnsupportedError].
+   */
+  factory Directory.fromUri(Uri uri) => new Directory(uri.toFilePath());
+
+  /**
+   * Creates a directory object pointing to the current working
+   * directory.
+   */
+  static Directory get current {
+    final IOOverrides overrides = IOOverrides.current;
+    if (overrides == null) {
+      return _Directory.current;
+    }
+    return overrides.getCurrentDirectory();
+  }
+
+  /**
+   * Returns a [Uri] representing the directory's location.
+   *
+   * The returned URI's scheme is always "file" if the entity's [path] is
+   * absolute, otherwise the scheme will be empty.
+   * The returned URI's path always ends in a slash ('/').
+   */
+  Uri get uri;
+
+  /**
+   * Sets the current working directory of the Dart process including
+   * all running isolates. The new value set can be either a [Directory]
+   * or a [String].
+   *
+   * The new value is passed to the OS's system call unchanged, so a
+   * relative path passed as the new working directory will be
+   * resolved by the OS.
+   *
+   * Note that setting the current working directory is a synchronous
+   * operation and that it changes the working directory of *all*
+   * isolates.
+   *
+   * Use this with care - especially when working with asynchronous
+   * operations and multiple isolates. Changing the working directory,
+   * while asynchronous operations are pending or when other isolates
+   * are working with the file system, can lead to unexpected results.
+   */
+  static void set current(path) {
+    final IOOverrides overrides = IOOverrides.current;
+    if (overrides == null) {
+      _Directory.current = path;
+      return;
+    }
+    overrides.setCurrentDirectory(path);
+  }
+
+  /**
+   * Creates the directory with this name.
+   *
+   * If [recursive] is false, only the last directory in the path is
+   * created. If [recursive] is true, all non-existing path components
+   * are created. If the directory already exists nothing is done.
+   *
+   * Returns a [:Future<Directory>:] that completes with this
+   * directory once it has been created. If the directory cannot be
+   * created the future completes with an exception.
+   */
+  Future<Directory> create({bool recursive: false});
+
+  /**
+   * Synchronously creates the directory with this name.
+   *
+   * If [recursive] is false, only the last directory in the path is
+   * created. If [recursive] is true, all non-existing path components
+   * are created. If the directory already exists nothing is done.
+   *
+   * If the directory cannot be created an exception is thrown.
+   */
+  void createSync({bool recursive: false});
+
+  /**
+   * Gets the system temp directory.
+   *
+   * Gets the directory provided by the operating system for creating
+   * temporary files and directories in.
+   * The location of the system temp directory is platform-dependent,
+   * and may be set by an environment variable.
+   */
+  static Directory get systemTemp {
+    final IOOverrides overrides = IOOverrides.current;
+    if (overrides == null) {
+      return _Directory.systemTemp;
+    }
+    return overrides.getSystemTempDirectory();
+  }
+
+  /**
+   * Creates a temporary directory in this directory. Additional random
+   * characters are appended to [prefix] to produce a unique directory
+   * name. If [prefix] is missing or null, the empty string is used
+   * for [prefix].
+   *
+   * Returns a [:Future<Directory>:] that completes with the newly
+   * created temporary directory.
+   */
+  Future<Directory> createTemp([String prefix]);
+
+  /**
+   * Synchronously creates a temporary directory in this directory.
+   * Additional random characters are appended to [prefix] to produce
+   * a unique directory name. If [prefix] is missing or null, the empty
+   * string is used for [prefix].
+   *
+   * Returns the newly created temporary directory.
+   */
+  Directory createTempSync([String prefix]);
+
+  Future<String> resolveSymbolicLinks();
+
+  String resolveSymbolicLinksSync();
+
+  /**
+   * Renames this directory. Returns a [:Future<Directory>:] that completes
+   * with a [Directory] instance for the renamed directory.
+   *
+   * If newPath identifies an existing directory, that directory is
+   * replaced. If newPath identifies an existing file, the operation
+   * fails and the future completes with an exception.
+   */
+  Future<Directory> rename(String newPath);
+
+  /**
+   * Synchronously renames this directory. Returns a [Directory]
+   * instance for the renamed directory.
+   *
+   * If newPath identifies an existing directory, that directory is
+   * replaced. If newPath identifies an existing file the operation
+   * fails and an exception is thrown.
+   */
+  Directory renameSync(String newPath);
+
+  /**
+   * Returns a [Directory] instance whose path is the absolute path to [this].
+   *
+   * The absolute path is computed by prefixing
+   * a relative path with the current working directory, and returning
+   * an absolute path unchanged.
+   */
+  Directory get absolute;
+
+  /**
+   * Lists the sub-directories and files of this [Directory].
+   * Optionally recurses into sub-directories.
+   *
+   * If [followLinks] is false, then any symbolic links found
+   * are reported as [Link] objects, rather than as directories or files,
+   * and are not recursed into.
+   *
+   * If [followLinks] is true, then working links are reported as
+   * directories or files, depending on
+   * their type, and links to directories are recursed into.
+   * Broken links are reported as [Link] objects.
+   * If a symbolic link makes a loop in the file system, then a recursive
+   * listing will not follow a link twice in the
+   * same recursive descent, but will report it as a [Link]
+   * the second time it is seen.
+   *
+   * The result is a stream of [FileSystemEntity] objects
+   * for the directories, files, and links.
+   */
+  Stream<FileSystemEntity> list(
+      {bool recursive: false, bool followLinks: true});
+
+  /**
+   * Lists the sub-directories and files of this [Directory].
+   * Optionally recurses into sub-directories.
+   *
+   * If [followLinks] is false, then any symbolic links found
+   * are reported as [Link] objects, rather than as directories or files,
+   * and are not recursed into.
+   *
+   * If [followLinks] is true, then working links are reported as
+   * directories or files, depending on
+   * their type, and links to directories are recursed into.
+   * Broken links are reported as [Link] objects.
+   * If a link makes a loop in the file system, then a recursive
+   * listing will not follow a link twice in the
+   * same recursive descent, but will report it as a [Link]
+   * the second time it is seen.
+   *
+   * Returns a [List] containing [FileSystemEntity] objects for the
+   * directories, files, and links.
+   */
+  List<FileSystemEntity> listSync(
+      {bool recursive: false, bool followLinks: true});
+
+  /**
+   * Returns a human readable string for this Directory instance.
+   */
+  String toString();
+}
diff --git a/sdk_nnbd/lib/io/directory_impl.dart b/sdk_nnbd/lib/io/directory_impl.dart
new file mode 100644
index 0000000..faed892
--- /dev/null
+++ b/sdk_nnbd/lib/io/directory_impl.dart
@@ -0,0 +1,447 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.io;
+
+class _Directory extends FileSystemEntity implements Directory {
+  String _path;
+  Uint8List _rawPath;
+
+  _Directory(String path) {
+    ArgumentError.checkNotNull(path, 'path');
+    _path = path;
+    _rawPath = FileSystemEntity._toUtf8Array(_path);
+  }
+
+  _Directory.fromRawPath(Uint8List rawPath) {
+    if (rawPath == null) {
+      throw new ArgumentError('rawPath cannot be null');
+    }
+    _rawPath = FileSystemEntity._toNullTerminatedUtf8Array(rawPath);
+    _path = FileSystemEntity._toStringFromUtf8Array(rawPath);
+  }
+
+  String get path => _path;
+
+  external static _current(_Namespace namespace);
+  external static _setCurrent(_Namespace namespace, Uint8List rawPath);
+  external static _createTemp(_Namespace namespace, Uint8List rawPath);
+  external static String _systemTemp(_Namespace namespace);
+  external static _exists(_Namespace namespace, Uint8List rawPath);
+  external static _create(_Namespace namespace, Uint8List rawPath);
+  external static _deleteNative(
+      _Namespace namespace, Uint8List rawPath, bool recursive);
+  external static _rename(
+      _Namespace namespace, Uint8List rawPath, String newPath);
+  external static void _fillWithDirectoryListing(
+      _Namespace namespace,
+      List<FileSystemEntity> list,
+      Uint8List rawPath,
+      bool recursive,
+      bool followLinks);
+
+  static Directory get current {
+    var result = _current(_Namespace._namespace);
+    if (result is OSError) {
+      throw new FileSystemException(
+          "Getting current working directory failed", "", result);
+    }
+    return new _Directory(result);
+  }
+
+  static void set current(path) {
+    Uint8List _rawPath;
+    if (path is _Directory) {
+      // For our internal Directory implementation, go ahead and use the raw
+      // path.
+      _rawPath = path._rawPath;
+    } else if (path is Directory) {
+      // FIXME(bkonyi): package:file passes in instances of classes which do
+      // not have _path defined, so we will fallback to using the existing
+      // path String for now.
+      _rawPath = FileSystemEntity._toUtf8Array(path.path);
+    } else if (path is String) {
+      _rawPath = FileSystemEntity._toUtf8Array(path);
+    } else {
+      throw new ArgumentError('${Error.safeToString(path)} is not a String or'
+          ' Directory');
+    }
+    if (!_EmbedderConfig._mayChdir) {
+      throw new UnsupportedError(
+          "This embedder disallows setting Directory.current");
+    }
+    var result = _setCurrent(_Namespace._namespace, _rawPath);
+    if (result is ArgumentError) throw result;
+    if (result is OSError) {
+      throw new FileSystemException(
+          "Setting current working directory failed", path, result);
+    }
+  }
+
+  Uri get uri {
+    return new Uri.directory(path);
+  }
+
+  Future<bool> exists() {
+    return _File._dispatchWithNamespace(
+        _IOService.directoryExists, [null, _rawPath]).then((response) {
+      if (_isErrorResponse(response)) {
+        throw _exceptionOrErrorFromResponse(response, "Exists failed");
+      }
+      return response == 1;
+    });
+  }
+
+  bool existsSync() {
+    var result = _exists(_Namespace._namespace, _rawPath);
+    if (result is OSError) {
+      throw new FileSystemException("Exists failed", path, result);
+    }
+    return (result == 1);
+  }
+
+  Directory get absolute => new Directory(_absolutePath);
+
+  Future<Directory> create({bool recursive: false}) {
+    if (recursive) {
+      return exists().then((exists) {
+        if (exists) return this;
+        if (path != parent.path) {
+          return parent.create(recursive: true).then((_) {
+            return create();
+          });
+        } else {
+          return create();
+        }
+      });
+    } else {
+      return _File._dispatchWithNamespace(
+          _IOService.directoryCreate, [null, _rawPath]).then((response) {
+        if (_isErrorResponse(response)) {
+          throw _exceptionOrErrorFromResponse(response, "Creation failed");
+        }
+        return this;
+      });
+    }
+  }
+
+  void createSync({bool recursive: false}) {
+    if (recursive) {
+      if (existsSync()) return;
+      if (path != parent.path) {
+        parent.createSync(recursive: true);
+      }
+    }
+    var result = _create(_Namespace._namespace, _rawPath);
+    if (result is OSError) {
+      throw new FileSystemException("Creation failed", path, result);
+    }
+  }
+
+  static Directory get systemTemp =>
+      new Directory(_systemTemp(_Namespace._namespace));
+
+  Future<Directory> createTemp([String prefix]) {
+    prefix ??= '';
+    if (path == '') {
+      throw new ArgumentError("Directory.createTemp called with an empty path. "
+          "To use the system temp directory, use Directory.systemTemp");
+    }
+    String fullPrefix;
+    // FIXME(bkonyi): here we're using `path` directly, which might cause
+    // issues if it is not UTF-8 encoded.
+    if (path.endsWith('/') || (Platform.isWindows && path.endsWith('\\'))) {
+      fullPrefix = "$path$prefix";
+    } else {
+      fullPrefix = "$path${Platform.pathSeparator}$prefix";
+    }
+    return _File._dispatchWithNamespace(_IOService.directoryCreateTemp,
+        [null, FileSystemEntity._toUtf8Array(fullPrefix)]).then((response) {
+      if (_isErrorResponse(response)) {
+        throw _exceptionOrErrorFromResponse(
+            response, "Creation of temporary directory failed");
+      }
+      return new Directory(response);
+    });
+  }
+
+  Directory createTempSync([String prefix]) {
+    prefix ??= '';
+    if (path == '') {
+      throw new ArgumentError("Directory.createTemp called with an empty path. "
+          "To use the system temp directory, use Directory.systemTemp");
+    }
+    String fullPrefix;
+    // FIXME(bkonyi): here we're using `path` directly, which might cause
+    // issues if it is not UTF-8 encoded.
+    if (path.endsWith('/') || (Platform.isWindows && path.endsWith('\\'))) {
+      fullPrefix = "$path$prefix";
+    } else {
+      fullPrefix = "$path${Platform.pathSeparator}$prefix";
+    }
+    var result = _createTemp(
+        _Namespace._namespace, FileSystemEntity._toUtf8Array(fullPrefix));
+    if (result is OSError) {
+      throw new FileSystemException(
+          "Creation of temporary directory failed", fullPrefix, result);
+    }
+    return new Directory(result);
+  }
+
+  Future<Directory> _delete({bool recursive: false}) {
+    return _File._dispatchWithNamespace(
+            _IOService.directoryDelete, [null, _rawPath, recursive])
+        .then((response) {
+      if (_isErrorResponse(response)) {
+        throw _exceptionOrErrorFromResponse(response, "Deletion failed");
+      }
+      return this;
+    });
+  }
+
+  void _deleteSync({bool recursive: false}) {
+    var result = _deleteNative(_Namespace._namespace, _rawPath, recursive);
+    if (result is OSError) {
+      throw new FileSystemException("Deletion failed", path, result);
+    }
+  }
+
+  Future<Directory> rename(String newPath) {
+    return _File._dispatchWithNamespace(
+        _IOService.directoryRename, [null, _rawPath, newPath]).then((response) {
+      if (_isErrorResponse(response)) {
+        throw _exceptionOrErrorFromResponse(response, "Rename failed");
+      }
+      return new Directory(newPath);
+    });
+  }
+
+  Directory renameSync(String newPath) {
+    if (newPath is! String) {
+      throw new ArgumentError();
+    }
+    var result = _rename(_Namespace._namespace, _rawPath, newPath);
+    if (result is OSError) {
+      throw new FileSystemException("Rename failed", path, result);
+    }
+    return new Directory(newPath);
+  }
+
+  Stream<FileSystemEntity> list(
+      {bool recursive: false, bool followLinks: true}) {
+    return new _AsyncDirectoryLister(
+            // FIXME(bkonyi): here we're using `path` directly, which might cause issues
+            // if it is not UTF-8 encoded.
+            FileSystemEntity._toUtf8Array(
+                FileSystemEntity._ensureTrailingPathSeparators(path)),
+            recursive,
+            followLinks)
+        .stream;
+  }
+
+  List<FileSystemEntity> listSync(
+      {bool recursive: false, bool followLinks: true}) {
+    if (recursive is! bool || followLinks is! bool) {
+      throw new ArgumentError();
+    }
+    var result = <FileSystemEntity>[];
+    _fillWithDirectoryListing(
+        _Namespace._namespace,
+        result,
+        // FIXME(bkonyi): here we're using `path` directly, which might cause issues
+        // if it is not UTF-8 encoded.
+        FileSystemEntity._toUtf8Array(
+            FileSystemEntity._ensureTrailingPathSeparators(path)),
+        recursive,
+        followLinks);
+    return result;
+  }
+
+  String toString() => "Directory: '$path'";
+
+  bool _isErrorResponse(response) =>
+      response is List && response[0] != _successResponse;
+
+  _exceptionOrErrorFromResponse(response, String message) {
+    assert(_isErrorResponse(response));
+    switch (response[_errorResponseErrorType]) {
+      case _illegalArgumentResponse:
+        return new ArgumentError();
+      case _osErrorResponse:
+        var err = new OSError(response[_osErrorResponseMessage],
+            response[_osErrorResponseErrorCode]);
+        return new FileSystemException(message, path, err);
+      default:
+        return new Exception("Unknown error");
+    }
+  }
+}
+
+abstract class _AsyncDirectoryListerOps {
+  external factory _AsyncDirectoryListerOps(int pointer);
+
+  int getPointer();
+}
+
+class _AsyncDirectoryLister {
+  static const int listFile = 0;
+  static const int listDirectory = 1;
+  static const int listLink = 2;
+  static const int listError = 3;
+  static const int listDone = 4;
+
+  static const int responseType = 0;
+  static const int responsePath = 1;
+  static const int responseComplete = 1;
+  static const int responseError = 2;
+
+  final Uint8List rawPath;
+  final bool recursive;
+  final bool followLinks;
+
+  StreamController<FileSystemEntity> controller;
+  bool canceled = false;
+  bool nextRunning = false;
+  bool closed = false;
+  _AsyncDirectoryListerOps _ops;
+  Completer closeCompleter = new Completer();
+
+  _AsyncDirectoryLister(this.rawPath, this.recursive, this.followLinks) {
+    controller = new StreamController<FileSystemEntity>(
+        onListen: onListen, onResume: onResume, onCancel: onCancel, sync: true);
+  }
+
+  // WARNING:
+  // Calling this function will increase the reference count on the native
+  // object that implements the async directory lister operations. It should
+  // only be called to pass the pointer to the IO Service, which will decrement
+  // the reference count when it is finished with it.
+  int _pointer() {
+    return (_ops == null) ? null : _ops.getPointer();
+  }
+
+  Stream<FileSystemEntity> get stream => controller.stream;
+
+  void onListen() {
+    _File._dispatchWithNamespace(_IOService.directoryListStart,
+        [null, rawPath, recursive, followLinks]).then((response) {
+      if (response is int) {
+        _ops = new _AsyncDirectoryListerOps(response);
+        next();
+      } else if (response is Error) {
+        controller.addError(response, response.stackTrace);
+        close();
+      } else {
+        error(response);
+        close();
+      }
+    });
+  }
+
+  void onResume() {
+    if (!nextRunning) {
+      next();
+    }
+  }
+
+  Future onCancel() {
+    canceled = true;
+    // If we are active, but not requesting, close.
+    if (!nextRunning) {
+      close();
+    }
+
+    return closeCompleter.future;
+  }
+
+  void next() {
+    if (canceled) {
+      close();
+      return;
+    }
+    if (controller.isPaused || nextRunning) {
+      return;
+    }
+    var pointer = _pointer();
+    if (pointer == null) {
+      return;
+    }
+    nextRunning = true;
+    _IOService._dispatch(_IOService.directoryListNext, [pointer])
+        .then((result) {
+      nextRunning = false;
+      if (result is List) {
+        next();
+        assert(result.length % 2 == 0);
+        for (int i = 0; i < result.length; i++) {
+          assert(i % 2 == 0);
+          switch (result[i++]) {
+            case listFile:
+              controller.add(new File.fromRawPath(result[i]));
+              break;
+            case listDirectory:
+              controller.add(new Directory.fromRawPath(result[i]));
+              break;
+            case listLink:
+              controller.add(new Link.fromRawPath(result[i]));
+              break;
+            case listError:
+              error(result[i]);
+              break;
+            case listDone:
+              canceled = true;
+              return;
+          }
+        }
+      } else {
+        controller.addError(new FileSystemException("Internal error"));
+      }
+    });
+  }
+
+  void _cleanup() {
+    controller.close();
+    closeCompleter.complete();
+    _ops = null;
+  }
+
+  void close() {
+    if (closed) {
+      return;
+    }
+    if (nextRunning) {
+      return;
+    }
+    closed = true;
+
+    var pointer = _pointer();
+    if (pointer == null) {
+      _cleanup();
+    } else {
+      _IOService._dispatch(_IOService.directoryListStop, [pointer])
+          .whenComplete(_cleanup);
+    }
+  }
+
+  void error(message) {
+    var errorType = message[responseError][_errorResponseErrorType];
+    if (errorType == _illegalArgumentResponse) {
+      controller.addError(new ArgumentError());
+    } else if (errorType == _osErrorResponse) {
+      var responseErrorInfo = message[responseError];
+      var err = new OSError(responseErrorInfo[_osErrorResponseMessage],
+          responseErrorInfo[_osErrorResponseErrorCode]);
+      var errorPath = message[responsePath];
+      if (errorPath == null) {
+        errorPath = utf8.decode(rawPath, allowMalformed: true);
+      } else if (errorPath is Uint8List) {
+        errorPath = utf8.decode(message[responsePath], allowMalformed: true);
+      }
+      controller.addError(
+          new FileSystemException("Directory listing failed", errorPath, err));
+    } else {
+      controller.addError(new FileSystemException("Internal error"));
+    }
+  }
+}
diff --git a/sdk_nnbd/lib/io/embedder_config.dart b/sdk_nnbd/lib/io/embedder_config.dart
new file mode 100644
index 0000000..cbc94f7
--- /dev/null
+++ b/sdk_nnbd/lib/io/embedder_config.dart
@@ -0,0 +1,38 @@
+// 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.
+
+part of dart.io;
+
+/// Embedder-specific, fine-grained dart:io configuration.
+///
+/// This class contains per-Isolate flags that an embedder can set to put
+/// fine-grained limitations on what process-visible operations Isolates are
+/// permitted to use (e.g. exit()). By default, the whole dart:io API is
+/// enabled. When a disallowed operation is attempted, an `UnsupportedError` is
+/// thrown.
+@pragma('vm:entry-point')
+abstract class _EmbedderConfig {
+  /// The Isolate may set Directory.current.
+  static bool _mayChdir = true;
+
+  /// The Isolate may call exit().
+  @pragma("vm:entry-point")
+  static bool _mayExit = true;
+
+  // The Isolate may set Stdin.echoMode.
+  @pragma('vm:entry-point')
+  static bool _maySetEchoMode = true;
+
+  // The Isolate may set Stdin.lineMode.
+  @pragma('vm:entry-point')
+  static bool _maySetLineMode = true;
+
+  /// The Isolate may call sleep().
+  @pragma('vm:entry-point')
+  static bool _maySleep = true;
+
+  // TODO(zra): Consider adding:
+  // - an option to disallow modifying SecurityContext.defaultContext
+  // - an option to disallow closing stdout and stderr.
+}
diff --git a/sdk_nnbd/lib/io/eventhandler.dart b/sdk_nnbd/lib/io/eventhandler.dart
new file mode 100644
index 0000000..36f54e6
--- /dev/null
+++ b/sdk_nnbd/lib/io/eventhandler.dart
@@ -0,0 +1,9 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.io;
+
+class _EventHandler {
+  external static void _sendData(Object sender, SendPort sendPort, int data);
+}
diff --git a/sdk_nnbd/lib/io/file.dart b/sdk_nnbd/lib/io/file.dart
new file mode 100644
index 0000000..861ce47
--- /dev/null
+++ b/sdk_nnbd/lib/io/file.dart
@@ -0,0 +1,1010 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.io;
+
+/**
+ * The modes in which a File can be opened.
+ */
+class FileMode {
+  /// The mode for opening a file only for reading.
+  static const read = const FileMode._internal(0);
+  @Deprecated("Use read instead")
+  static const READ = read;
+
+  /// Mode for opening a file for reading and writing. The file is
+  /// overwritten if it already exists. The file is created if it does not
+  /// already exist.
+  static const write = const FileMode._internal(1);
+  @Deprecated("Use write instead")
+  static const WRITE = write;
+
+  /// Mode for opening a file for reading and writing to the
+  /// end of it. The file is created if it does not already exist.
+  static const append = const FileMode._internal(2);
+  @Deprecated("Use append instead")
+  static const APPEND = append;
+
+  /// Mode for opening a file for writing *only*. The file is
+  /// overwritten if it already exists. The file is created if it does not
+  /// already exist.
+  static const writeOnly = const FileMode._internal(3);
+  @Deprecated("Use writeOnly instead")
+  static const WRITE_ONLY = writeOnly;
+
+  /// Mode for opening a file for writing *only* to the
+  /// end of it. The file is created if it does not already exist.
+  static const writeOnlyAppend = const FileMode._internal(4);
+  @Deprecated("Use writeOnlyAppend instead")
+  static const WRITE_ONLY_APPEND = writeOnlyAppend;
+
+  final int _mode;
+
+  const FileMode._internal(this._mode);
+}
+
+/// The mode for opening a file only for reading.
+@Deprecated("Use FileMode.read instead")
+const READ = FileMode.read;
+
+/// The mode for opening a file for reading and writing. The file is
+/// overwritten if it already exists. The file is created if it does not
+/// already exist.
+@Deprecated("Use FileMode.write instead")
+const WRITE = FileMode.write;
+
+/// The mode for opening a file for reading and writing to the
+/// end of it. The file is created if it does not already exist.
+@Deprecated("Use FileMode.append instead")
+const APPEND = FileMode.append;
+
+/// Mode for opening a file for writing *only*. The file is
+/// overwritten if it already exists. The file is created if it does not
+/// already exist.
+@Deprecated("Use FileMode.writeOnly instead")
+const WRITE_ONLY = FileMode.writeOnly;
+
+/// Mode for opening a file for writing *only* to the
+/// end of it. The file is created if it does not already exist.
+@Deprecated("Use FileMode.writeOnlyAppend instead")
+const WRITE_ONLY_APPEND = FileMode.writeOnlyAppend;
+
+/// Type of lock when requesting a lock on a file.
+class FileLock {
+  /// Shared file lock.
+  static const shared = const FileLock._internal(1);
+  @Deprecated("Use shared instead")
+  static const SHARED = shared;
+
+  /// Exclusive file lock.
+  static const exclusive = const FileLock._internal(2);
+  @Deprecated("Use exclusive instead")
+  static const EXCLUSIVE = exclusive;
+
+  /// Blocking shared file lock.
+  static const blockingShared = const FileLock._internal(3);
+  @Deprecated("Use blockingShared instead")
+  static const BLOCKING_SHARED = blockingShared;
+
+  /// Blocking exclusive file lock.
+  static const blockingExclusive = const FileLock._internal(4);
+  @Deprecated("Use blockingExclusive instead")
+  static const BLOCKING_EXCLUSIVE = blockingExclusive;
+
+  final int _type;
+
+  const FileLock._internal(this._type);
+}
+
+/**
+ * A reference to a file on the file system.
+ *
+ * A File instance is an object that holds a [path] on which operations can
+ * be performed.
+ * You can get the parent directory of the file using the getter [parent],
+ * a property inherited from [FileSystemEntity].
+ *
+ * Create a new File object with a pathname to access the specified file on the
+ * file system from your program.
+ *
+ *     var myFile = new File('file.txt');
+ *
+ * The File class contains methods for manipulating files and their contents.
+ * Using methods in this class, you can open and close files, read to and write
+ * from them, create and delete them, and check for their existence.
+ *
+ * When reading or writing a file, you can use streams (with [openRead]),
+ * random access operations (with [open]),
+ * or convenience methods such as [readAsString],
+ *
+ * Most methods in this class occur in synchronous and asynchronous pairs,
+ * for example, [readAsString] and [readAsStringSync].
+ * Unless you have a specific reason for using the synchronous version
+ * of a method, prefer the asynchronous version to avoid blocking your program.
+ *
+ * ## If path is a link
+ *
+ * If [path] is a symbolic link, rather than a file,
+ * then the methods of File operate on the ultimate target of the
+ * link, except for [delete] and [deleteSync], which operate on
+ * the link.
+ *
+ * ## Read from a file
+ *
+ * The following code sample reads the entire contents from a file as a string
+ * using the asynchronous [readAsString] method:
+ *
+ *     import 'dart:async';
+ *     import 'dart:io';
+ *
+ *     void main() {
+ *       new File('file.txt').readAsString().then((String contents) {
+ *         print(contents);
+ *       });
+ *     }
+ *
+ * A more flexible and useful way to read a file is with a [Stream].
+ * Open the file with [openRead], which returns a stream that
+ * provides the data in the file as chunks of bytes.
+ * Listen to the stream for data and process as needed.
+ * You can use various transformers in succession to manipulate the
+ * data into the required format or to prepare it for output.
+ *
+ * You might want to use a stream to read large files,
+ * to manipulate the data with transformers,
+ * or for compatibility with another API, such as [WebSocket]s.
+ *
+ *     import 'dart:io';
+ *     import 'dart:convert';
+ *     import 'dart:async';
+ *
+ *     main() {
+ *       final file = new File('file.txt');
+ *       Stream<List<int>> inputStream = file.openRead();
+ *
+ *       inputStream
+ *         .transform(utf8.decoder)       // Decode bytes to UTF-8.
+ *         .transform(new LineSplitter()) // Convert stream to individual lines.
+ *         .listen((String line) {        // Process results.
+ *             print('$line: ${line.length} bytes');
+ *           },
+ *           onDone: () { print('File is now closed.'); },
+ *           onError: (e) { print(e.toString()); });
+ *     }
+ *
+ * ## Write to a file
+ *
+ * To write a string to a file, use the [writeAsString] method:
+ *
+ *     import 'dart:io';
+ *
+ *     void main() {
+ *       final filename = 'file.txt';
+ *       new File(filename).writeAsString('some content')
+ *         .then((File file) {
+ *           // Do something with the file.
+ *         });
+ *     }
+ *
+ * You can also write to a file using a [Stream]. Open the file with
+ * [openWrite], which returns an [IOSink] to which you can write data.
+ * Be sure to close the sink with the [IOSink.close] method.
+ *
+ *     import 'dart:io';
+ *
+ *     void main() {
+ *       var file = new File('file.txt');
+ *       var sink = file.openWrite();
+ *       sink.write('FILE ACCESSED ${new DateTime.now()}\n');
+ *
+ *       // Close the IOSink to free system resources.
+ *       sink.close();
+ *     }
+ *
+ * ## The use of Futures
+ *
+ * To avoid unintentional blocking of the program,
+ * several methods use a [Future] to return a value. For example,
+ * the [length] method, which gets the length of a file, returns a Future.
+ * Use `then` to register a callback function, which is called when
+ * the value is ready.
+ *
+ *     import 'dart:io';
+ *
+ *     main() {
+ *       final file = new File('file.txt');
+ *
+ *       file.length().then((len) {
+ *         print(len);
+ *       });
+ *     }
+ *
+ * In addition to length, the [exists], [lastModified], [stat], and
+ * other methods, return Futures.
+ *
+ * ## Other resources
+ *
+ * * [Dart by Example](https://www.dartlang.org/dart-by-example/#files-directories-and-symlinks)
+ *   provides additional task-oriented code samples that show how to use
+ *   various API from the Directory class and the related [File] class.
+ *
+ * * [I/O for Command-Line
+ *   Apps](https://www.dartlang.org/docs/dart-up-and-running/ch03.html#dartio---io-for-command-line-apps)
+ *   a section from _A Tour of the Dart Libraries_ covers files and directories.
+ *
+ * * [Write Command-Line Apps](https://www.dartlang.org/docs/tutorials/cmdline/),
+ *   a tutorial about writing command-line apps, includes information about
+ *   files and directories.
+ */
+@pragma("vm:entry-point")
+abstract class File implements FileSystemEntity {
+  /**
+   * Creates a [File] object.
+   *
+   * If [path] is a relative path, it will be interpreted relative to the
+   * current working directory (see [Directory.current]), when used.
+   *
+   * If [path] is an absolute path, it will be immune to changes to the
+   * current working directory.
+   */
+  @pragma("vm:entry-point")
+  factory File(String path) {
+    final IOOverrides overrides = IOOverrides.current;
+    if (overrides == null) {
+      return new _File(path);
+    }
+    return overrides.createFile(path);
+  }
+
+  /**
+   * Create a File object from a URI.
+   *
+   * If [uri] cannot reference a file this throws [UnsupportedError].
+   */
+  factory File.fromUri(Uri uri) => new File(uri.toFilePath());
+
+  /**
+   * Creates a File object from a raw path, that is, a sequence of bytes
+   * as represented by the OS.
+   */
+  @pragma("vm:entry-point")
+  factory File.fromRawPath(Uint8List rawPath) {
+    // TODO(bkonyi): Handle overrides.
+    return new _File.fromRawPath(rawPath);
+  }
+
+  /**
+   * Create the file. Returns a `Future<File>` that completes with
+   * the file when it has been created.
+   *
+   * If [recursive] is false, the default, the file is created only if
+   * all directories in the path exist. If [recursive] is true, all
+   * non-existing path components are created.
+   *
+   * Existing files are left untouched by [create]. Calling [create] on an
+   * existing file might fail if there are restrictive permissions on
+   * the file.
+   *
+   * Completes the future with a [FileSystemException] if the operation fails.
+   */
+  Future<File> create({bool recursive: false});
+
+  /**
+   * Synchronously create the file. Existing files are left untouched
+   * by [createSync]. Calling [createSync] on an existing file might fail
+   * if there are restrictive permissions on the file.
+   *
+   * If [recursive] is false, the default, the file is created
+   * only if all directories in the path exist.
+   * If [recursive] is true, all non-existing path components are created.
+   *
+   * Throws a [FileSystemException] if the operation fails.
+   */
+  void createSync({bool recursive: false});
+
+  /**
+   * Renames this file. Returns a `Future<File>` that completes
+   * with a [File] instance for the renamed file.
+   *
+   * If [newPath] identifies an existing file, that file is
+   * replaced. If [newPath] identifies an existing directory, the
+   * operation fails and the future completes with an exception.
+   */
+  Future<File> rename(String newPath);
+
+  /**
+   * Synchronously renames this file. Returns a [File]
+   * instance for the renamed file.
+   *
+   * If [newPath] identifies an existing file, that file is
+   * replaced. If [newPath] identifies an existing directory the
+   * operation fails and an exception is thrown.
+   */
+  File renameSync(String newPath);
+
+  /**
+   * Copy this file. Returns a `Future<File>` that completes
+   * with a [File] instance for the copied file.
+   *
+   * If [newPath] identifies an existing file, that file is
+   * replaced. If [newPath] identifies an existing directory, the
+   * operation fails and the future completes with an exception.
+   */
+  Future<File> copy(String newPath);
+
+  /**
+   * Synchronously copy this file. Returns a [File]
+   * instance for the copied file.
+   *
+   * If [newPath] identifies an existing file, that file is
+   * replaced. If [newPath] identifies an existing directory the
+   * operation fails and an exception is thrown.
+   */
+  File copySync(String newPath);
+
+  /**
+   * Get the length of the file. Returns a `Future<int>` that
+   * completes with the length in bytes.
+   */
+  Future<int> length();
+
+  /**
+   * Synchronously get the length of the file.
+   *
+   * Throws a [FileSystemException] if the operation fails.
+   */
+  int lengthSync();
+
+  /**
+   * Returns a [File] instance whose path is the absolute path to [this].
+   *
+   * The absolute path is computed by prefixing
+   * a relative path with the current working directory, and returning
+   * an absolute path unchanged.
+   */
+  File get absolute;
+
+/**
+ * Get the last-accessed time of the file.
+ *
+ * Returns a `Future<DateTime>` that completes with the date and time when the
+ * file was last accessed, if the information is available.
+ *
+ * Throws a [FileSystemException] if the operation fails.
+ */
+  Future<DateTime> lastAccessed();
+
+/**
+ * Get the last-accessed time of the file.
+ *
+ * Returns the date and time when the file was last accessed,
+ * if the information is available. Blocks until the information can be returned
+ * or it is determined that the information is not available.
+ *
+ * Throws a [FileSystemException] if the operation fails.
+ */
+  DateTime lastAccessedSync();
+
+  /**
+   * Modifies the time the file was last accessed.
+   *
+   * Returns a [Future] that completes once the operation has completed.
+   *
+   * Throws a [FileSystemException] if the time cannot be set.
+   */
+  Future setLastAccessed(DateTime time);
+
+  /**
+   * Synchronously modifies the time the file was last accessed.
+   *
+   * Throws a [FileSystemException] if the time cannot be set.
+   */
+  void setLastAccessedSync(DateTime time);
+
+/**
+ * Get the last-modified time of the file.
+ *
+ * Returns a `Future<DateTime>` that completes with the date and time when the
+ * file was last modified, if the information is available.
+ *
+ * Throws a [FileSystemException] if the operation fails.
+ */
+  Future<DateTime> lastModified();
+
+/**
+ * Get the last-modified time of the file.
+ *
+ * Returns the date and time when the file was last modified,
+ * if the information is available. Blocks until the information can be returned
+ * or it is determined that the information is not available.
+ *
+ * Throws a [FileSystemException] if the operation fails.
+ */
+  DateTime lastModifiedSync();
+
+  /**
+   * Modifies the time the file was last modified.
+   *
+   * Returns a [Future] that completes once the operation has completed.
+   *
+   * Throws a [FileSystemException] if the time cannot be set.
+   */
+  Future setLastModified(DateTime time);
+
+  /**
+   * Synchronously modifies the time the file was last modified.
+   *
+   * If the attributes cannot be set, throws a [FileSystemException].
+   */
+  void setLastModifiedSync(DateTime time);
+
+  /**
+   * Open the file for random access operations. Returns a
+   * `Future<RandomAccessFile>` that completes with the opened
+   * random access file. [RandomAccessFile]s must be closed using the
+   * [RandomAccessFile.close] method.
+   *
+   * Files can be opened in three modes:
+   *
+   * [FileMode.read]: open the file for reading.
+   *
+   * [FileMode.write]: open the file for both reading and writing and
+   * truncate the file to length zero. If the file does not exist the
+   * file is created.
+   *
+   * [FileMode.append]: same as [FileMode.write] except that the file is
+   * not truncated.
+   */
+  Future<RandomAccessFile> open({FileMode mode: FileMode.read});
+
+  /**
+   * Synchronously open the file for random access operations. The
+   * result is a [RandomAccessFile] on which random access operations
+   * can be performed. Opened [RandomAccessFile]s must be closed using
+   * the [RandomAccessFile.close] method.
+   *
+   * See [open] for information on the [mode] argument.
+   *
+   * Throws a [FileSystemException] if the operation fails.
+   */
+  RandomAccessFile openSync({FileMode mode: FileMode.read});
+
+  /**
+   * Create a new independent [Stream] for the contents of this file.
+   *
+   * If [start] is present, the file will be read from byte-offset [start].
+   * Otherwise from the beginning (index 0).
+   *
+   * If [end] is present, only up to byte-index [end] will be read. Otherwise,
+   * until end of file.
+   *
+   * In order to make sure that system resources are freed, the stream
+   * must be read to completion or the subscription on the stream must
+   * be cancelled.
+   */
+  Stream<List<int>> openRead([int start, int end]);
+
+  /**
+   * Creates a new independent [IOSink] for the file. The
+   * [IOSink] must be closed when no longer used, to free
+   * system resources.
+   *
+   * An [IOSink] for a file can be opened in two modes:
+   *
+   * * [FileMode.write]: truncates the file to length zero.
+   * * [FileMode.append]: sets the initial write position to the end
+   *   of the file.
+   *
+   *  When writing strings through the returned [IOSink] the encoding
+   *  specified using [encoding] will be used. The returned [IOSink]
+   *  has an `encoding` property which can be changed after the
+   *  [IOSink] has been created.
+   */
+  IOSink openWrite({FileMode mode: FileMode.write, Encoding encoding: utf8});
+
+  /**
+   * Read the entire file contents as a list of bytes. Returns a
+   * `Future<Uint8List>` that completes with the list of bytes that
+   * is the contents of the file.
+   */
+  Future<Uint8List> readAsBytes();
+
+  /**
+   * Synchronously read the entire file contents as a list of bytes.
+   *
+   * Throws a [FileSystemException] if the operation fails.
+   */
+  Uint8List readAsBytesSync();
+
+  /**
+   * Read the entire file contents as a string using the given
+   * [Encoding].
+   *
+   * Returns a `Future<String>` that completes with the string once
+   * the file contents has been read.
+   */
+  Future<String> readAsString({Encoding encoding: utf8});
+
+  /**
+   * Synchronously read the entire file contents as a string using the
+   * given [Encoding].
+   *
+   * Throws a [FileSystemException] if the operation fails.
+   */
+  String readAsStringSync({Encoding encoding: utf8});
+
+  /**
+   * Read the entire file contents as lines of text using the given
+   * [Encoding].
+   *
+   * Returns a `Future<List<String>>` that completes with the lines
+   * once the file contents has been read.
+   */
+  Future<List<String>> readAsLines({Encoding encoding: utf8});
+
+  /**
+   * Synchronously read the entire file contents as lines of text
+   * using the given [Encoding].
+   *
+   * Throws a [FileSystemException] if the operation fails.
+   */
+  List<String> readAsLinesSync({Encoding encoding: utf8});
+
+  /**
+   * Write a list of bytes to a file.
+   *
+   * Opens the file, writes the list of bytes to it, and closes the file.
+   * Returns a `Future<File>` that completes with this [File] object once
+   * the entire operation has completed.
+   *
+   * By default [writeAsBytes] creates the file for writing and truncates the
+   * file if it already exists. In order to append the bytes to an existing
+   * file, pass [FileMode.append] as the optional mode parameter.
+   *
+   * If the argument [flush] is set to `true`, the data written will be
+   * flushed to the file system before the returned future completes.
+   */
+  Future<File> writeAsBytes(List<int> bytes,
+      {FileMode mode: FileMode.write, bool flush: false});
+
+  /**
+   * Synchronously write a list of bytes to a file.
+   *
+   * Opens the file, writes the list of bytes to it and closes the file.
+   *
+   * By default [writeAsBytesSync] creates the file for writing and truncates
+   * the file if it already exists. In order to append the bytes to an existing
+   * file, pass [FileMode.append] as the optional mode parameter.
+   *
+   * If the [flush] argument is set to `true` data written will be
+   * flushed to the file system before returning.
+   *
+   * Throws a [FileSystemException] if the operation fails.
+   */
+  void writeAsBytesSync(List<int> bytes,
+      {FileMode mode: FileMode.write, bool flush: false});
+
+  /**
+   * Write a string to a file.
+   *
+   * Opens the file, writes the string in the given encoding, and closes the
+   * file. Returns a `Future<File>` that completes with this [File] object
+   * once the entire operation has completed.
+   *
+   * By default [writeAsString] creates the file for writing and truncates the
+   * file if it already exists. In order to append the bytes to an existing
+   * file, pass [FileMode.append] as the optional mode parameter.
+   *
+   * If the argument [flush] is set to `true`, the data written will be
+   * flushed to the file system before the returned future completes.
+   *
+   */
+  Future<File> writeAsString(String contents,
+      {FileMode mode: FileMode.write,
+      Encoding encoding: utf8,
+      bool flush: false});
+
+  /**
+   * Synchronously write a string to a file.
+   *
+   * Opens the file, writes the string in the given encoding, and closes the
+   * file.
+   *
+   * By default [writeAsStringSync] creates the file for writing and
+   * truncates the file if it already exists. In order to append the bytes
+   * to an existing file, pass [FileMode.append] as the optional mode
+   * parameter.
+   *
+   * If the [flush] argument is set to `true` data written will be
+   * flushed to the file system before returning.
+   *
+   * Throws a [FileSystemException] if the operation fails.
+   */
+  void writeAsStringSync(String contents,
+      {FileMode mode: FileMode.write,
+      Encoding encoding: utf8,
+      bool flush: false});
+
+  /**
+   * Get the path of the file.
+   */
+  String get path;
+}
+
+/**
+ * `RandomAccessFile` provides random access to the data in a
+ * file.
+ *
+ * `RandomAccessFile` objects are obtained by calling the
+ * `open` method on a [File] object.
+ *
+ * A `RandomAccessFile` have both asynchronous and synchronous
+ * methods. The asynchronous methods all return a `Future`
+ * whereas the synchronous methods will return the result directly,
+ * and block the current isolate until the result is ready.
+ *
+ * At most one asynchronous method can be pending on a given `RandomAccessFile`
+ * instance at the time. If an asynchronous method is called when one is
+ * already in progress a [FileSystemException] is thrown.
+ *
+ * If an asynchronous method is pending it is also not possible to call any
+ * synchronous methods. This will also throw a [FileSystemException].
+ */
+abstract class RandomAccessFile {
+  /**
+   * Closes the file. Returns a `Future` that
+   * completes when it has been closed.
+   */
+  Future<void> close();
+
+  /**
+   * Synchronously closes the file.
+   *
+   * Throws a [FileSystemException] if the operation fails.
+   */
+  void closeSync();
+
+  /**
+   * Reads a byte from the file. Returns a `Future<int>` that
+   * completes with the byte, or with -1 if end-of-file has been reached.
+   */
+  Future<int> readByte();
+
+  /**
+   * Synchronously reads a single byte from the file. If end-of-file
+   * has been reached -1 is returned.
+   *
+   * Throws a [FileSystemException] if the operation fails.
+   */
+  int readByteSync();
+
+  /**
+   * Reads [bytes] bytes from a file and returns the result as a list of bytes.
+   */
+  Future<Uint8List> read(int bytes);
+
+  /**
+   * Synchronously reads a maximum of [bytes] bytes from a file and
+   * returns the result in a list of bytes.
+   *
+   * Throws a [FileSystemException] if the operation fails.
+   */
+  Uint8List readSync(int bytes);
+
+  /**
+   * Reads into an existing [List<int>] from the file. If [start] is present,
+   * the bytes will be filled into [buffer] from at index [start], otherwise
+   * index 0. If [end] is present, the [end] - [start] bytes will be read into
+   * [buffer], otherwise up to [buffer.length]. If [end] == [start] nothing
+   * happens.
+   *
+   * Returns a `Future<int>` that completes with the number of bytes read.
+   */
+  Future<int> readInto(List<int> buffer, [int start = 0, int end]);
+
+  /**
+   * Synchronously reads into an existing [List<int>] from the file. If [start]
+   * is present, the bytes will be filled into [buffer] from at index [start],
+   * otherwise index 0.  If [end] is present, the [end] - [start] bytes will be
+   * read into [buffer], otherwise up to [buffer.length]. If [end] == [start]
+   * nothing happens.
+   *
+   * Throws a [FileSystemException] if the operation fails.
+   */
+  int readIntoSync(List<int> buffer, [int start = 0, int end]);
+
+  /**
+   * Writes a single byte to the file. Returns a
+   * `Future<RandomAccessFile>` that completes with this
+   * RandomAccessFile when the write completes.
+   */
+  Future<RandomAccessFile> writeByte(int value);
+
+  /**
+   * Synchronously writes a single byte to the file. Returns the
+   * number of bytes successfully written.
+   *
+   * Throws a [FileSystemException] if the operation fails.
+   */
+  int writeByteSync(int value);
+
+  /**
+   * Writes from a [List<int>] to the file. It will read the buffer from index
+   * [start] to index [end]. If [start] is omitted, it'll start from index 0.
+   * If [end] is omitted, it will write to end of [buffer].
+   *
+   * Returns a `Future<RandomAccessFile>` that completes with this
+   * [RandomAccessFile] when the write completes.
+   */
+  Future<RandomAccessFile> writeFrom(List<int> buffer,
+      [int start = 0, int end]);
+
+  /**
+   * Synchronously writes from a [List<int>] to the file. It will read the
+   * buffer from index [start] to index [end]. If [start] is omitted, it'll
+   * start from index 0. If [end] is omitted, it will write to the end of
+   * [buffer].
+   *
+   * Throws a [FileSystemException] if the operation fails.
+   */
+  void writeFromSync(List<int> buffer, [int start = 0, int end]);
+
+  /**
+   * Writes a string to the file using the given [Encoding]. Returns a
+   * `Future<RandomAccessFile>` that completes with this
+   * RandomAccessFile when the write completes.
+   */
+  Future<RandomAccessFile> writeString(String string,
+      {Encoding encoding: utf8});
+
+  /**
+   * Synchronously writes a single string to the file using the given
+   * [Encoding].
+   *
+   * Throws a [FileSystemException] if the operation fails.
+   */
+  void writeStringSync(String string, {Encoding encoding: utf8});
+
+  /**
+   * Gets the current byte position in the file. Returns a
+   * `Future<int>` that completes with the position.
+   */
+  Future<int> position();
+
+  /**
+   * Synchronously gets the current byte position in the file.
+   *
+   * Throws a [FileSystemException] if the operation fails.
+   */
+  int positionSync();
+
+  /**
+   * Sets the byte position in the file. Returns a
+   * `Future<RandomAccessFile>` that completes with this
+   * RandomAccessFile when the position has been set.
+   */
+  Future<RandomAccessFile> setPosition(int position);
+
+  /**
+   * Synchronously sets the byte position in the file.
+   *
+   * Throws a [FileSystemException] if the operation fails.
+   */
+  void setPositionSync(int position);
+
+  /**
+   * Truncates (or extends) the file to [length] bytes. Returns a
+   * `Future<RandomAccessFile>` that completes with this
+   * RandomAccessFile when the truncation has been performed.
+   */
+  Future<RandomAccessFile> truncate(int length);
+
+  /**
+   * Synchronously truncates (or extends) the file to [length] bytes.
+   *
+   * Throws a [FileSystemException] if the operation fails.
+   */
+  void truncateSync(int length);
+
+  /**
+   * Gets the length of the file. Returns a `Future<int>` that
+   * completes with the length in bytes.
+   */
+  Future<int> length();
+
+  /**
+   * Synchronously gets the length of the file.
+   *
+   * Throws a [FileSystemException] if the operation fails.
+   */
+  int lengthSync();
+
+  /**
+   * Flushes the contents of the file to disk. Returns a
+   * `Future<RandomAccessFile>` that completes with this
+   * RandomAccessFile when the flush operation completes.
+   */
+  Future<RandomAccessFile> flush();
+
+  /**
+   * Synchronously flushes the contents of the file to disk.
+   *
+   * Throws a [FileSystemException] if the operation fails.
+   */
+  void flushSync();
+
+  /**
+   * Locks the file or part of the file.
+   *
+   * By default an exclusive lock will be obtained, but that can be overridden
+   * by the [mode] argument.
+   *
+   * Locks the byte range from [start] to [end] of the file, with the
+   * byte at position `end` not included. If no arguments are
+   * specified, the full file is locked, If only `start` is specified
+   * the file is locked from byte position `start` to the end of the
+   * file, no matter how large it grows. It is possible to specify an
+   * explicit value of `end` which is past the current length of the file.
+   *
+   * To obtain an exclusive lock on a file it must be opened for writing.
+   *
+   * If [mode] is [FileLock.exclusive] or [FileLock.shared], an error is
+   * signaled if the lock cannot be obtained. If [mode] is
+   * [FileLock.blockingExclusive] or [FileLock.blockingShared], the
+   * returned [Future] is resolved only when the lock has been obtained.
+   *
+   * *NOTE* file locking does have slight differences in behavior across
+   * platforms:
+   *
+   * On Linux and OS X this uses advisory locks, which have the
+   * surprising semantics that all locks associated with a given file
+   * are removed when *any* file descriptor for that file is closed by
+   * the process. Note that this does not actually lock the file for
+   * access. Also note that advisory locks are on a process
+   * level. This means that several isolates in the same process can
+   * obtain an exclusive lock on the same file.
+   *
+   * On Windows the regions used for lock and unlock needs to match. If that
+   * is not the case unlocking will result in the OS error "The segment is
+   * already unlocked".
+   */
+  Future<RandomAccessFile> lock(
+      [FileLock mode = FileLock.exclusive, int start = 0, int end = -1]);
+
+  /**
+   * Synchronously locks the file or part of the file.
+   *
+   * By default an exclusive lock will be obtained, but that can be overridden
+   * by the [mode] argument.
+   *
+   * Locks the byte range from [start] to [end] of the file ,with the
+   * byte at position `end` not included. If no arguments are
+   * specified, the full file is locked, If only `start` is specified
+   * the file is locked from byte position `start` to the end of the
+   * file, no matter how large it grows. It is possible to specify an
+   * explicit value of `end` which is past the current length of the file.
+   *
+   * To obtain an exclusive lock on a file it must be opened for writing.
+   *
+   * If [mode] is [FileLock.exclusive] or [FileLock.shared], an exception is
+   * thrown if the lock cannot be obtained. If [mode] is
+   * [FileLock.blockingExclusive] or [FileLock.blockingShared], the
+   * call returns only after the lock has been obtained.
+   *
+   * *NOTE* file locking does have slight differences in behavior across
+   * platforms:
+   *
+   * On Linux and OS X this uses advisory locks, which have the
+   * surprising semantics that all locks associated with a given file
+   * are removed when *any* file descriptor for that file is closed by
+   * the process. Note that this does not actually lock the file for
+   * access. Also note that advisory locks are on a process
+   * level. This means that several isolates in the same process can
+   * obtain an exclusive lock on the same file.
+   *
+   * On Windows the regions used for lock and unlock needs to match. If that
+   * is not the case unlocking will result in the OS error "The segment is
+   * already unlocked".
+   *
+   */
+  void lockSync(
+      [FileLock mode = FileLock.exclusive, int start = 0, int end = -1]);
+
+  /**
+   * Unlocks the file or part of the file.
+   *
+   * Unlocks the byte range from [start] to [end] of the file, with
+   * the byte at position `end` not included. If no arguments are
+   * specified, the full file is unlocked, If only `start` is
+   * specified the file is unlocked from byte position `start` to the
+   * end of the file.
+   *
+   * *NOTE* file locking does have slight differences in behavior across
+   * platforms:
+   *
+   * See [lock] for more details.
+   */
+  Future<RandomAccessFile> unlock([int start = 0, int end = -1]);
+
+  /**
+   * Synchronously unlocks the file or part of the file.
+   *
+   * Unlocks the byte range from [start] to [end] of the file, with
+   * the byte at position `end` not included. If no arguments are
+   * specified, the full file is unlocked, If only `start` is
+   * specified the file is unlocked from byte position `start` to the
+   * end of the file.
+   *
+   * *NOTE* file locking does have slight differences in behavior across
+   * platforms:
+   *
+   * See [lockSync] for more details.
+   */
+  void unlockSync([int start = 0, int end = -1]);
+
+  /**
+   * Returns a human-readable string for this RandomAccessFile instance.
+   */
+  String toString();
+
+  /**
+   * Gets the path of the file underlying this RandomAccessFile.
+   */
+  String get path;
+}
+
+/**
+ * Exception thrown when a file operation fails.
+ */
+@pragma("vm:entry-point")
+class FileSystemException implements IOException {
+  /**
+   * Message describing the error. This does not include any detailed
+   * information form the underlying OS error. Check [osError] for
+   * that information.
+   */
+  final String message;
+
+  /**
+   * The file system path on which the error occurred. Can be `null`
+   * if the exception does not relate directly to a file system path.
+   */
+  final String path;
+
+  /**
+   * The underlying OS error. Can be `null` if the exception is not
+   * raised due to an OS error.
+   */
+  final OSError osError;
+
+  /**
+   * Creates a new FileSystemException with an optional error message
+   * [message], optional file system path [path] and optional OS error
+   * [osError].
+   */
+  @pragma("vm:entry-point")
+  const FileSystemException([this.message = "", this.path = "", this.osError]);
+
+  String toString() {
+    StringBuffer sb = new StringBuffer();
+    sb.write("FileSystemException");
+    if (message.isNotEmpty) {
+      sb.write(": $message");
+      if (path != null) {
+        sb.write(", path = '$path'");
+      }
+      if (osError != null) {
+        sb.write(" ($osError)");
+      }
+    } else if (osError != null) {
+      sb.write(": $osError");
+      if (path != null) {
+        sb.write(", path = '$path'");
+      }
+    } else if (path != null) {
+      sb.write(": $path");
+    }
+    return sb.toString();
+  }
+}
diff --git a/sdk_nnbd/lib/io/file_impl.dart b/sdk_nnbd/lib/io/file_impl.dart
new file mode 100644
index 0000000..410182c
--- /dev/null
+++ b/sdk_nnbd/lib/io/file_impl.dart
@@ -0,0 +1,1095 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.io;
+
+// Read the file in blocks of size 64k.
+const int _blockSize = 64 * 1024;
+
+class _FileStream extends Stream<List<int>> {
+  // Stream controller.
+  StreamController<Uint8List> _controller;
+
+  // Information about the underlying file.
+  String _path;
+  RandomAccessFile _openedFile;
+  int _position;
+  int _end;
+  final Completer _closeCompleter = new Completer();
+
+  // Has the stream been paused or unsubscribed?
+  bool _unsubscribed = false;
+
+  // Is there a read currently in progress?
+  bool _readInProgress = true;
+  bool _closed = false;
+
+  bool _atEnd = false;
+
+  _FileStream(this._path, this._position, this._end) {
+    _position ??= 0;
+  }
+
+  _FileStream.forStdin() : _position = 0;
+
+  StreamSubscription<Uint8List> listen(void onData(Uint8List event),
+      {Function onError, void onDone(), bool cancelOnError}) {
+    _setupController();
+    return _controller.stream.listen(onData,
+        onError: onError, onDone: onDone, cancelOnError: cancelOnError);
+  }
+
+  void _setupController() {
+    _controller = new StreamController<Uint8List>(
+        sync: true,
+        onListen: _start,
+        onResume: _readBlock,
+        onCancel: () {
+          _unsubscribed = true;
+          return _closeFile();
+        });
+  }
+
+  Future _closeFile() {
+    if (_readInProgress || _closed) {
+      return _closeCompleter.future;
+    }
+    _closed = true;
+
+    void done() {
+      _closeCompleter.complete();
+      _controller.close();
+    }
+
+    _openedFile.close().catchError(_controller.addError).whenComplete(done);
+    return _closeCompleter.future;
+  }
+
+  void _readBlock() {
+    // Don't start a new read if one is already in progress.
+    if (_readInProgress) return;
+    if (_atEnd) {
+      _closeFile();
+      return;
+    }
+    _readInProgress = true;
+    int readBytes = _blockSize;
+    if (_end != null) {
+      readBytes = min(readBytes, _end - _position);
+      if (readBytes < 0) {
+        _readInProgress = false;
+        if (!_unsubscribed) {
+          _controller.addError(new RangeError("Bad end position: $_end"));
+          _closeFile();
+          _unsubscribed = true;
+        }
+        return;
+      }
+    }
+    _openedFile.read(readBytes).then((block) {
+      _readInProgress = false;
+      if (_unsubscribed) {
+        _closeFile();
+        return;
+      }
+      _position += block.length;
+      if (block.length < readBytes || (_end != null && _position == _end)) {
+        _atEnd = true;
+      }
+      if (!_atEnd && !_controller.isPaused) {
+        _readBlock();
+      }
+      _controller.add(block);
+      if (_atEnd) {
+        _closeFile();
+      }
+    }).catchError((e, s) {
+      if (!_unsubscribed) {
+        _controller.addError(e, s);
+        _closeFile();
+        _unsubscribed = true;
+      }
+    });
+  }
+
+  void _start() {
+    if (_position < 0) {
+      _controller.addError(new RangeError("Bad start position: $_position"));
+      _controller.close();
+      _closeCompleter.complete();
+      return;
+    }
+
+    void onReady(RandomAccessFile file) {
+      _openedFile = file;
+      _readInProgress = false;
+      _readBlock();
+    }
+
+    void onOpenFile(RandomAccessFile file) {
+      if (_position > 0) {
+        file.setPosition(_position).then(onReady, onError: (e, s) {
+          _controller.addError(e, s);
+          _readInProgress = false;
+          _closeFile();
+        });
+      } else {
+        onReady(file);
+      }
+    }
+
+    void openFailed(error, stackTrace) {
+      _controller.addError(error, stackTrace);
+      _controller.close();
+      _closeCompleter.complete();
+    }
+
+    if (_path != null) {
+      new File(_path)
+          .open(mode: FileMode.read)
+          .then(onOpenFile, onError: openFailed);
+    } else {
+      try {
+        onOpenFile(_File._openStdioSync(0));
+      } catch (e, s) {
+        openFailed(e, s);
+      }
+    }
+  }
+}
+
+class _FileStreamConsumer extends StreamConsumer<List<int>> {
+  File _file;
+  Future<RandomAccessFile> _openFuture;
+
+  _FileStreamConsumer(this._file, FileMode mode) {
+    _openFuture = _file.open(mode: mode);
+  }
+
+  _FileStreamConsumer.fromStdio(int fd) {
+    _openFuture = new Future.value(_File._openStdioSync(fd));
+  }
+
+  Future<File> addStream(Stream<List<int>> stream) {
+    Completer<File> completer = new Completer<File>.sync();
+    _openFuture.then((openedFile) {
+      var _subscription;
+      void error(e, [StackTrace stackTrace]) {
+        _subscription.cancel();
+        openedFile.close();
+        completer.completeError(e, stackTrace);
+      }
+
+      _subscription = stream.listen((d) {
+        _subscription.pause();
+        try {
+          openedFile
+              .writeFrom(d, 0, d.length)
+              .then((_) => _subscription.resume(), onError: error);
+        } catch (e, stackTrace) {
+          error(e, stackTrace);
+        }
+      }, onDone: () {
+        completer.complete(_file);
+      }, onError: error, cancelOnError: true);
+    }).catchError(completer.completeError);
+    return completer.future;
+  }
+
+  Future<File> close() =>
+      _openFuture.then((openedFile) => openedFile.close()).then((_) => _file);
+}
+
+// Class for encapsulating the native implementation of files.
+class _File extends FileSystemEntity implements File {
+  String _path;
+  Uint8List _rawPath;
+
+  _File(String path) {
+    ArgumentError.checkNotNull(path, 'path');
+    _path = path;
+    _rawPath = FileSystemEntity._toUtf8Array(path);
+  }
+
+  _File.fromRawPath(Uint8List rawPath) {
+    ArgumentError.checkNotNull(rawPath, 'rawPath');
+    _rawPath = FileSystemEntity._toNullTerminatedUtf8Array(rawPath);
+    _path = FileSystemEntity._toStringFromUtf8Array(rawPath);
+  }
+
+  String get path => _path;
+
+  // WARNING:
+  // Calling this function will increase the reference count on the native
+  // namespace object. It should only be called to pass the pointer to the
+  // IOService, which will decrement the reference count when it is finished
+  // with it.
+  static int _namespacePointer() => _Namespace._namespacePointer;
+
+  static Future _dispatchWithNamespace(int request, List data) {
+    data[0] = _namespacePointer();
+    return _IOService._dispatch(request, data);
+  }
+
+  Future<bool> exists() {
+    return _dispatchWithNamespace(_IOService.fileExists, [null, _rawPath])
+        .then((response) {
+      if (_isErrorResponse(response)) {
+        throw _exceptionFromResponse(response, "Cannot check existence", path);
+      }
+      return response;
+    });
+  }
+
+  external static _exists(_Namespace namespace, Uint8List rawPath);
+
+  bool existsSync() {
+    var result = _exists(_Namespace._namespace, _rawPath);
+    throwIfError(result, "Cannot check existence of file", path);
+    return result;
+  }
+
+  File get absolute => new File(_absolutePath);
+
+  Future<File> create({bool recursive: false}) {
+    var result =
+        recursive ? parent.create(recursive: true) : new Future.value(null);
+    return result
+        .then((_) =>
+            _dispatchWithNamespace(_IOService.fileCreate, [null, _rawPath]))
+        .then((response) {
+      if (_isErrorResponse(response)) {
+        throw _exceptionFromResponse(response, "Cannot create file", path);
+      }
+      return this;
+    });
+  }
+
+  external static _create(_Namespace namespace, Uint8List rawPath);
+
+  external static _createLink(
+      _Namespace namespace, Uint8List rawPath, String target);
+
+  external static _linkTarget(_Namespace namespace, Uint8List rawPath);
+
+  void createSync({bool recursive: false}) {
+    if (recursive) {
+      parent.createSync(recursive: true);
+    }
+    var result = _create(_Namespace._namespace, _rawPath);
+    throwIfError(result, "Cannot create file", path);
+  }
+
+  Future<File> _delete({bool recursive: false}) {
+    if (recursive) {
+      return new Directory(path).delete(recursive: true).then((_) => this);
+    }
+    return _dispatchWithNamespace(_IOService.fileDelete, [null, _rawPath])
+        .then((response) {
+      if (_isErrorResponse(response)) {
+        throw _exceptionFromResponse(response, "Cannot delete file", path);
+      }
+      return this;
+    });
+  }
+
+  external static _deleteNative(_Namespace namespace, Uint8List rawPath);
+
+  external static _deleteLinkNative(_Namespace namespace, Uint8List rawPath);
+
+  void _deleteSync({bool recursive: false}) {
+    if (recursive) {
+      return new Directory.fromRawPath(_rawPath).deleteSync(recursive: true);
+    }
+    var result = _deleteNative(_Namespace._namespace, _rawPath);
+    throwIfError(result, "Cannot delete file", path);
+  }
+
+  Future<File> rename(String newPath) {
+    return _dispatchWithNamespace(
+        _IOService.fileRename, [null, _rawPath, newPath]).then((response) {
+      if (_isErrorResponse(response)) {
+        throw _exceptionFromResponse(
+            response, "Cannot rename file to '$newPath'", path);
+      }
+      return new File(newPath);
+    });
+  }
+
+  external static _rename(
+      _Namespace namespace, Uint8List oldPath, String newPath);
+
+  external static _renameLink(
+      _Namespace namespace, Uint8List oldPath, String newPath);
+
+  File renameSync(String newPath) {
+    var result = _rename(_Namespace._namespace, _rawPath, newPath);
+    throwIfError(result, "Cannot rename file to '$newPath'", path);
+    return new File(newPath);
+  }
+
+  Future<File> copy(String newPath) {
+    return _dispatchWithNamespace(
+        _IOService.fileCopy, [null, _rawPath, newPath]).then((response) {
+      if (_isErrorResponse(response)) {
+        throw _exceptionFromResponse(
+            response, "Cannot copy file to '$newPath'", path);
+      }
+      return new File(newPath);
+    });
+  }
+
+  external static _copy(
+      _Namespace namespace, Uint8List oldPath, String newPath);
+
+  File copySync(String newPath) {
+    var result = _copy(_Namespace._namespace, _rawPath, newPath);
+    throwIfError(result, "Cannot copy file to '$newPath'", path);
+    return new File(newPath);
+  }
+
+  Future<RandomAccessFile> open({FileMode mode: FileMode.read}) {
+    if (mode != FileMode.read &&
+        mode != FileMode.write &&
+        mode != FileMode.append &&
+        mode != FileMode.writeOnly &&
+        mode != FileMode.writeOnlyAppend) {
+      return new Future.error(
+          new ArgumentError('Invalid file mode for this operation'));
+    }
+    return _dispatchWithNamespace(
+        _IOService.fileOpen, [null, _rawPath, mode._mode]).then((response) {
+      if (_isErrorResponse(response)) {
+        throw _exceptionFromResponse(response, "Cannot open file", path);
+      }
+      return new _RandomAccessFile(response, path);
+    });
+  }
+
+  Future<int> length() {
+    return _dispatchWithNamespace(
+        _IOService.fileLengthFromPath, [null, _rawPath]).then((response) {
+      if (_isErrorResponse(response)) {
+        throw _exceptionFromResponse(
+            response, "Cannot retrieve length of file", path);
+      }
+      return response;
+    });
+  }
+
+  external static _lengthFromPath(_Namespace namespace, Uint8List rawPath);
+
+  int lengthSync() {
+    var result = _lengthFromPath(_Namespace._namespace, _rawPath);
+    throwIfError(result, "Cannot retrieve length of file", path);
+    return result;
+  }
+
+  Future<DateTime> lastAccessed() {
+    return _dispatchWithNamespace(_IOService.fileLastAccessed, [null, _rawPath])
+        .then((response) {
+      if (_isErrorResponse(response)) {
+        throw _exceptionFromResponse(
+            response, "Cannot retrieve access time", path);
+      }
+      return new DateTime.fromMillisecondsSinceEpoch(response);
+    });
+  }
+
+  external static _lastAccessed(_Namespace namespace, Uint8List rawPath);
+
+  DateTime lastAccessedSync() {
+    var ms = _lastAccessed(_Namespace._namespace, _rawPath);
+    throwIfError(ms, "Cannot retrieve access time", path);
+    return new DateTime.fromMillisecondsSinceEpoch(ms);
+  }
+
+  Future setLastAccessed(DateTime time) {
+    int millis = time.millisecondsSinceEpoch;
+    return _dispatchWithNamespace(
+            _IOService.fileSetLastAccessed, [null, _rawPath, millis])
+        .then((response) {
+      if (_isErrorResponse(response)) {
+        throw _exceptionFromResponse(response, "Cannot set access time", path);
+      }
+      return null;
+    });
+  }
+
+  external static _setLastAccessed(
+      _Namespace namespace, Uint8List rawPath, int millis);
+
+  void setLastAccessedSync(DateTime time) {
+    int millis = time.millisecondsSinceEpoch;
+    var result = _setLastAccessed(_Namespace._namespace, _rawPath, millis);
+    if (result is OSError) {
+      throw new FileSystemException(
+          "Failed to set file access time", path, result);
+    }
+  }
+
+  Future<DateTime> lastModified() {
+    return _dispatchWithNamespace(_IOService.fileLastModified, [null, _rawPath])
+        .then((response) {
+      if (_isErrorResponse(response)) {
+        throw _exceptionFromResponse(
+            response, "Cannot retrieve modification time", path);
+      }
+      return new DateTime.fromMillisecondsSinceEpoch(response);
+    });
+  }
+
+  external static _lastModified(_Namespace namespace, Uint8List rawPath);
+
+  DateTime lastModifiedSync() {
+    var ms = _lastModified(_Namespace._namespace, _rawPath);
+    throwIfError(ms, "Cannot retrieve modification time", path);
+    return new DateTime.fromMillisecondsSinceEpoch(ms);
+  }
+
+  Future setLastModified(DateTime time) {
+    int millis = time.millisecondsSinceEpoch;
+    return _dispatchWithNamespace(
+            _IOService.fileSetLastModified, [null, _rawPath, millis])
+        .then((response) {
+      if (_isErrorResponse(response)) {
+        throw _exceptionFromResponse(
+            response, "Cannot set modification time", path);
+      }
+      return null;
+    });
+  }
+
+  external static _setLastModified(
+      _Namespace namespace, Uint8List rawPath, int millis);
+
+  void setLastModifiedSync(DateTime time) {
+    int millis = time.millisecondsSinceEpoch;
+    var result = _setLastModified(_Namespace._namespace, _rawPath, millis);
+    if (result is OSError) {
+      throw new FileSystemException(
+          "Failed to set file modification time", path, result);
+    }
+  }
+
+  external static _open(_Namespace namespace, Uint8List rawPath, int mode);
+
+  RandomAccessFile openSync({FileMode mode: FileMode.read}) {
+    if (mode != FileMode.read &&
+        mode != FileMode.write &&
+        mode != FileMode.append &&
+        mode != FileMode.writeOnly &&
+        mode != FileMode.writeOnlyAppend) {
+      throw new ArgumentError('Invalid file mode for this operation');
+    }
+    var id = _open(_Namespace._namespace, _rawPath, mode._mode);
+    throwIfError(id, "Cannot open file", path);
+    return new _RandomAccessFile(id, _path);
+  }
+
+  external static int _openStdio(int fd);
+
+  static RandomAccessFile _openStdioSync(int fd) {
+    var id = _openStdio(fd);
+    if (id == 0) {
+      throw new FileSystemException("Cannot open stdio file for: $fd");
+    }
+    return new _RandomAccessFile(id, "");
+  }
+
+  Stream<List<int>> openRead([int start, int end]) {
+    return new _FileStream(path, start, end);
+  }
+
+  IOSink openWrite({FileMode mode: FileMode.write, Encoding encoding: utf8}) {
+    if (mode != FileMode.write &&
+        mode != FileMode.append &&
+        mode != FileMode.writeOnly &&
+        mode != FileMode.writeOnlyAppend) {
+      throw new ArgumentError('Invalid file mode for this operation');
+    }
+    var consumer = new _FileStreamConsumer(this, mode);
+    return new IOSink(consumer, encoding: encoding);
+  }
+
+  Future<Uint8List> readAsBytes() {
+    Future<Uint8List> readDataChunked(RandomAccessFile file) {
+      var builder = new BytesBuilder(copy: false);
+      var completer = new Completer<Uint8List>();
+      void read() {
+        file.read(_blockSize).then((data) {
+          if (data.length > 0) {
+            builder.add(data);
+            read();
+          } else {
+            completer.complete(builder.takeBytes());
+          }
+        }, onError: completer.completeError);
+      }
+
+      read();
+      return completer.future;
+    }
+
+    return open().then((file) {
+      return file.length().then((length) {
+        if (length == 0) {
+          // May be character device, try to read it in chunks.
+          return readDataChunked(file);
+        }
+        return file.read(length);
+      }).whenComplete(file.close);
+    });
+  }
+
+  Uint8List readAsBytesSync() {
+    var opened = openSync();
+    try {
+      Uint8List data;
+      var length = opened.lengthSync();
+      if (length == 0) {
+        // May be character device, try to read it in chunks.
+        var builder = new BytesBuilder(copy: false);
+        do {
+          data = opened.readSync(_blockSize);
+          if (data.length > 0) builder.add(data);
+        } while (data.length > 0);
+        data = builder.takeBytes();
+      } else {
+        data = opened.readSync(length);
+      }
+      return data;
+    } finally {
+      opened.closeSync();
+    }
+  }
+
+  String _tryDecode(List<int> bytes, Encoding encoding) {
+    try {
+      return encoding.decode(bytes);
+    } catch (_) {
+      throw new FileSystemException(
+          "Failed to decode data using encoding '${encoding.name}'", path);
+    }
+  }
+
+  Future<String> readAsString({Encoding encoding: utf8}) {
+    // TODO(dart:io): If the change in async semantics to run synchronously
+    // until await lands, this is as efficient as
+    // return _tryDecode(await readAsBytes(), encoding);
+    var stack = StackTrace.current;
+    return readAsBytes().then((bytes) {
+      try {
+        return _tryDecode(bytes, encoding);
+      } catch (e) {
+        return new Future.error(e, stack);
+      }
+    });
+  }
+
+  String readAsStringSync({Encoding encoding: utf8}) =>
+      _tryDecode(readAsBytesSync(), encoding);
+
+  Future<List<String>> readAsLines({Encoding encoding: utf8}) =>
+      readAsString(encoding: encoding).then(const LineSplitter().convert);
+
+  List<String> readAsLinesSync({Encoding encoding: utf8}) =>
+      const LineSplitter().convert(readAsStringSync(encoding: encoding));
+
+  Future<File> writeAsBytes(List<int> bytes,
+      {FileMode mode: FileMode.write, bool flush: false}) {
+    return open(mode: mode).then((file) {
+      return file.writeFrom(bytes, 0, bytes.length).then<File>((_) {
+        if (flush) return file.flush().then((_) => this);
+        return this;
+      }).whenComplete(file.close);
+    });
+  }
+
+  void writeAsBytesSync(List<int> bytes,
+      {FileMode mode: FileMode.write, bool flush: false}) {
+    RandomAccessFile opened = openSync(mode: mode);
+    try {
+      opened.writeFromSync(bytes, 0, bytes.length);
+      if (flush) opened.flushSync();
+    } finally {
+      opened.closeSync();
+    }
+  }
+
+  Future<File> writeAsString(String contents,
+      {FileMode mode: FileMode.write,
+      Encoding encoding: utf8,
+      bool flush: false}) {
+    try {
+      return writeAsBytes(encoding.encode(contents), mode: mode, flush: flush);
+    } catch (e) {
+      return new Future.error(e);
+    }
+  }
+
+  void writeAsStringSync(String contents,
+      {FileMode mode: FileMode.write,
+      Encoding encoding: utf8,
+      bool flush: false}) {
+    writeAsBytesSync(encoding.encode(contents), mode: mode, flush: flush);
+  }
+
+  String toString() => "File: '$path'";
+
+  static throwIfError(Object result, String msg, String path) {
+    if (result is OSError) {
+      throw new FileSystemException(msg, path, result);
+    }
+  }
+}
+
+abstract class _RandomAccessFileOps {
+  external factory _RandomAccessFileOps(int pointer);
+
+  int getPointer();
+  int close();
+  readByte();
+  read(int bytes);
+  readInto(List<int> buffer, int start, int end);
+  writeByte(int value);
+  writeFrom(List<int> buffer, int start, int end);
+  position();
+  setPosition(int position);
+  truncate(int length);
+  length();
+  flush();
+  lock(int lock, int start, int end);
+}
+
+class _RandomAccessFile implements RandomAccessFile {
+  static bool _connectedResourceHandler = false;
+
+  final String path;
+
+  bool _asyncDispatched = false;
+  SendPort _fileService;
+
+  _FileResourceInfo _resourceInfo;
+  _RandomAccessFileOps _ops;
+
+  _RandomAccessFile(int pointer, this.path) {
+    _ops = new _RandomAccessFileOps(pointer);
+    _resourceInfo = new _FileResourceInfo(this);
+    _maybeConnectHandler();
+  }
+
+  void _maybePerformCleanup() {
+    if (closed) {
+      _FileResourceInfo.FileClosed(_resourceInfo);
+    }
+  }
+
+  _maybeConnectHandler() {
+    if (!_connectedResourceHandler) {
+      // TODO(ricow): We probably need to set these in some initialization code.
+      // We need to make sure that these are always available from the
+      // observatory even if no files (or sockets for the socket ones) are
+      // open.
+      registerExtension(
+          'ext.dart.io.getOpenFiles', _FileResourceInfo.getOpenFiles);
+      registerExtension(
+          'ext.dart.io.getFileByID', _FileResourceInfo.getFileInfoMapByID);
+      _connectedResourceHandler = true;
+    }
+  }
+
+  Future<void> close() {
+    return _dispatch(_IOService.fileClose, [null], markClosed: true)
+        .then((result) {
+      if (result == -1) {
+        throw new FileSystemException("Cannot close file", path);
+      }
+      closed = closed || (result == 0);
+      _maybePerformCleanup();
+    });
+  }
+
+  void closeSync() {
+    _checkAvailable();
+    var id = _ops.close();
+    if (id == -1) {
+      throw new FileSystemException("Cannot close file", path);
+    }
+    closed = closed || (id == 0);
+    _maybePerformCleanup();
+  }
+
+  Future<int> readByte() {
+    return _dispatch(_IOService.fileReadByte, [null]).then((response) {
+      if (_isErrorResponse(response)) {
+        throw _exceptionFromResponse(response, "readByte failed", path);
+      }
+      _resourceInfo.addRead(1);
+      return response;
+    });
+  }
+
+  int readByteSync() {
+    _checkAvailable();
+    var result = _ops.readByte();
+    if (result is OSError) {
+      throw new FileSystemException("readByte failed", path, result);
+    }
+    _resourceInfo.addRead(1);
+    return result;
+  }
+
+  Future<Uint8List> read(int bytes) {
+    ArgumentError.checkNotNull(bytes, 'bytes');
+    return _dispatch(_IOService.fileRead, [null, bytes]).then((response) {
+      if (_isErrorResponse(response)) {
+        throw _exceptionFromResponse(response, "read failed", path);
+      }
+      _resourceInfo.addRead(response[1].length);
+      Uint8List result = response[1];
+      return result;
+    });
+  }
+
+  Uint8List readSync(int bytes) {
+    _checkAvailable();
+    ArgumentError.checkNotNull(bytes, 'bytes');
+    var result = _ops.read(bytes);
+    if (result is OSError) {
+      throw new FileSystemException("readSync failed", path, result);
+    }
+    _resourceInfo.addRead(result.length);
+    return result;
+  }
+
+  Future<int> readInto(List<int> buffer, [int start = 0, int end]) {
+    if ((buffer is! List) ||
+        ((start != null) && (start is! int)) ||
+        ((end != null) && (end is! int))) {
+      throw new ArgumentError();
+    }
+    end = RangeError.checkValidRange(start, end, buffer.length);
+    if (end == start) {
+      return new Future.value(0);
+    }
+    int length = end - start;
+    return _dispatch(_IOService.fileReadInto, [null, length]).then((response) {
+      if (_isErrorResponse(response)) {
+        throw _exceptionFromResponse(response, "readInto failed", path);
+      }
+      int read = response[1];
+      List<int> data = response[2];
+      buffer.setRange(start, start + read, data);
+      _resourceInfo.addRead(read);
+      return read;
+    });
+  }
+
+  int readIntoSync(List<int> buffer, [int start = 0, int end]) {
+    _checkAvailable();
+    if ((buffer is! List) ||
+        ((start != null) && (start is! int)) ||
+        ((end != null) && (end is! int))) {
+      throw new ArgumentError();
+    }
+    end = RangeError.checkValidRange(start, end, buffer.length);
+    if (end == start) {
+      return 0;
+    }
+    var result = _ops.readInto(buffer, start, end);
+    if (result is OSError) {
+      throw new FileSystemException("readInto failed", path, result);
+    }
+    _resourceInfo.addRead(result);
+    return result;
+  }
+
+  Future<RandomAccessFile> writeByte(int value) {
+    ArgumentError.checkNotNull(value, 'value');
+    return _dispatch(_IOService.fileWriteByte, [null, value]).then((response) {
+      if (_isErrorResponse(response)) {
+        throw _exceptionFromResponse(response, "writeByte failed", path);
+      }
+      _resourceInfo.addWrite(1);
+      return this;
+    });
+  }
+
+  int writeByteSync(int value) {
+    _checkAvailable();
+    ArgumentError.checkNotNull(value, 'value');
+    var result = _ops.writeByte(value);
+    if (result is OSError) {
+      throw new FileSystemException("writeByte failed", path, result);
+    }
+    _resourceInfo.addWrite(1);
+    return result;
+  }
+
+  Future<RandomAccessFile> writeFrom(List<int> buffer,
+      [int start = 0, int end]) {
+    if ((buffer is! List) ||
+        ((start != null) && (start is! int)) ||
+        ((end != null) && (end is! int))) {
+      throw new ArgumentError("Invalid arguments to writeFrom");
+    }
+    end = RangeError.checkValidRange(start, end, buffer.length);
+    if (end == start) {
+      return new Future.value(this);
+    }
+    _BufferAndStart result;
+    try {
+      result = _ensureFastAndSerializableByteData(buffer, start, end);
+    } catch (e) {
+      return new Future.error(e);
+    }
+
+    List request = new List(4);
+    request[0] = null;
+    request[1] = result.buffer;
+    request[2] = result.start;
+    request[3] = end - (start - result.start);
+    return _dispatch(_IOService.fileWriteFrom, request).then((response) {
+      if (_isErrorResponse(response)) {
+        throw _exceptionFromResponse(response, "writeFrom failed", path);
+      }
+      _resourceInfo.addWrite(end - (start - result.start));
+      return this;
+    });
+  }
+
+  void writeFromSync(List<int> buffer, [int start = 0, int end]) {
+    _checkAvailable();
+    if ((buffer is! List) ||
+        ((start != null) && (start is! int)) ||
+        ((end != null) && (end is! int))) {
+      throw new ArgumentError("Invalid arguments to writeFromSync");
+    }
+    end = RangeError.checkValidRange(start, end, buffer.length);
+    if (end == start) {
+      return;
+    }
+    _BufferAndStart bufferAndStart =
+        _ensureFastAndSerializableByteData(buffer, start, end);
+    var result = _ops.writeFrom(bufferAndStart.buffer, bufferAndStart.start,
+        end - (start - bufferAndStart.start));
+    if (result is OSError) {
+      throw new FileSystemException("writeFrom failed", path, result);
+    }
+    _resourceInfo.addWrite(end - (start - bufferAndStart.start));
+  }
+
+  Future<RandomAccessFile> writeString(String string,
+      {Encoding encoding: utf8}) {
+    ArgumentError.checkNotNull(encoding, 'encoding');
+    var data = encoding.encode(string);
+    return writeFrom(data, 0, data.length);
+  }
+
+  void writeStringSync(String string, {Encoding encoding: utf8}) {
+    ArgumentError.checkNotNull(encoding, 'encoding');
+    var data = encoding.encode(string);
+    writeFromSync(data, 0, data.length);
+  }
+
+  Future<int> position() {
+    return _dispatch(_IOService.filePosition, [null]).then((response) {
+      if (_isErrorResponse(response)) {
+        throw _exceptionFromResponse(response, "position failed", path);
+      }
+      return response;
+    });
+  }
+
+  int positionSync() {
+    _checkAvailable();
+    var result = _ops.position();
+    if (result is OSError) {
+      throw new FileSystemException("position failed", path, result);
+    }
+    return result;
+  }
+
+  Future<RandomAccessFile> setPosition(int position) {
+    return _dispatch(_IOService.fileSetPosition, [null, position])
+        .then((response) {
+      if (_isErrorResponse(response)) {
+        throw _exceptionFromResponse(response, "setPosition failed", path);
+      }
+      return this;
+    });
+  }
+
+  void setPositionSync(int position) {
+    _checkAvailable();
+    var result = _ops.setPosition(position);
+    if (result is OSError) {
+      throw new FileSystemException("setPosition failed", path, result);
+    }
+  }
+
+  Future<RandomAccessFile> truncate(int length) {
+    return _dispatch(_IOService.fileTruncate, [null, length]).then((response) {
+      if (_isErrorResponse(response)) {
+        throw _exceptionFromResponse(response, "truncate failed", path);
+      }
+      return this;
+    });
+  }
+
+  void truncateSync(int length) {
+    _checkAvailable();
+    var result = _ops.truncate(length);
+    if (result is OSError) {
+      throw new FileSystemException("truncate failed", path, result);
+    }
+  }
+
+  Future<int> length() {
+    return _dispatch(_IOService.fileLength, [null]).then((response) {
+      if (_isErrorResponse(response)) {
+        throw _exceptionFromResponse(response, "length failed", path);
+      }
+      return response;
+    });
+  }
+
+  int lengthSync() {
+    _checkAvailable();
+    var result = _ops.length();
+    if (result is OSError) {
+      throw new FileSystemException("length failed", path, result);
+    }
+    return result;
+  }
+
+  Future<RandomAccessFile> flush() {
+    return _dispatch(_IOService.fileFlush, [null]).then((response) {
+      if (_isErrorResponse(response)) {
+        throw _exceptionFromResponse(response, "flush failed", path);
+      }
+      return this;
+    });
+  }
+
+  void flushSync() {
+    _checkAvailable();
+    var result = _ops.flush();
+    if (result is OSError) {
+      throw new FileSystemException("flush failed", path, result);
+    }
+  }
+
+  static const int lockUnlock = 0;
+  // static const int lockShared = 1;
+  // static const int lockExclusive = 2;
+  // static const int lockBlockingShared = 3;
+  // static const int lockBlockingExclusive = 4;
+
+  int _fileLockValue(FileLock fl) => fl._type;
+
+  Future<RandomAccessFile> lock(
+      [FileLock mode = FileLock.exclusive, int start = 0, int end = -1]) {
+    if ((mode is! FileLock) || (start is! int) || (end is! int)) {
+      throw new ArgumentError();
+    }
+    if ((start < 0) || (end < -1) || ((end != -1) && (start >= end))) {
+      throw new ArgumentError();
+    }
+    int lock = _fileLockValue(mode);
+    return _dispatch(_IOService.fileLock, [null, lock, start, end])
+        .then((response) {
+      if (_isErrorResponse(response)) {
+        throw _exceptionFromResponse(response, 'lock failed', path);
+      }
+      return this;
+    });
+  }
+
+  Future<RandomAccessFile> unlock([int start = 0, int end = -1]) {
+    if ((start is! int) || (end is! int)) {
+      throw new ArgumentError();
+    }
+    if (start == end) {
+      throw new ArgumentError();
+    }
+    return _dispatch(_IOService.fileLock, [null, lockUnlock, start, end])
+        .then((response) {
+      if (_isErrorResponse(response)) {
+        throw _exceptionFromResponse(response, 'unlock failed', path);
+      }
+      return this;
+    });
+  }
+
+  void lockSync(
+      [FileLock mode = FileLock.exclusive, int start = 0, int end = -1]) {
+    _checkAvailable();
+    if ((mode is! FileLock) || (start is! int) || (end is! int)) {
+      throw new ArgumentError();
+    }
+    if ((start < 0) || (end < -1) || ((end != -1) && (start >= end))) {
+      throw new ArgumentError();
+    }
+    int lock = _fileLockValue(mode);
+    var result = _ops.lock(lock, start, end);
+    if (result is OSError) {
+      throw new FileSystemException('lock failed', path, result);
+    }
+  }
+
+  void unlockSync([int start = 0, int end = -1]) {
+    _checkAvailable();
+    if ((start is! int) || (end is! int)) {
+      throw new ArgumentError();
+    }
+    if (start == end) {
+      throw new ArgumentError();
+    }
+    var result = _ops.lock(lockUnlock, start, end);
+    if (result is OSError) {
+      throw new FileSystemException('unlock failed', path, result);
+    }
+  }
+
+  bool closed = false;
+
+  // WARNING:
+  // Calling this function will increase the reference count on the native
+  // object that implements the file operations. It should only be called to
+  // pass the pointer to the IO Service, which will decrement the reference
+  // count when it is finished with it.
+  int _pointer() => _ops.getPointer();
+
+  Future _dispatch(int request, List data, {bool markClosed: false}) {
+    if (closed) {
+      return new Future.error(new FileSystemException("File closed", path));
+    }
+    if (_asyncDispatched) {
+      var msg = "An async operation is currently pending";
+      return new Future.error(new FileSystemException(msg, path));
+    }
+    if (markClosed) {
+      // Set closed to true to ensure that no more async requests can be issued
+      // for this file.
+      closed = true;
+    }
+    _asyncDispatched = true;
+    data[0] = _pointer();
+    return _IOService._dispatch(request, data).whenComplete(() {
+      _asyncDispatched = false;
+    });
+  }
+
+  void _checkAvailable() {
+    if (_asyncDispatched) {
+      throw new FileSystemException(
+          "An async operation is currently pending", path);
+    }
+    if (closed) {
+      throw new FileSystemException("File closed", path);
+    }
+  }
+}
diff --git a/sdk_nnbd/lib/io/file_system_entity.dart b/sdk_nnbd/lib/io/file_system_entity.dart
new file mode 100644
index 0000000..16e99e6
--- /dev/null
+++ b/sdk_nnbd/lib/io/file_system_entity.dart
@@ -0,0 +1,1002 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.io;
+
+/**
+ * The type of an entity on the file system, such as a file, directory, or link.
+ *
+ * These constants are used by the [FileSystemEntity] class
+ * to indicate the object's type.
+ *
+ */
+
+class FileSystemEntityType {
+  static const file = const FileSystemEntityType._internal(0);
+  @Deprecated("Use file instead")
+  static const FILE = file;
+
+  static const directory = const FileSystemEntityType._internal(1);
+  @Deprecated("Use directory instead")
+  static const DIRECTORY = directory;
+
+  static const link = const FileSystemEntityType._internal(2);
+  @Deprecated("Use link instead")
+  static const LINK = link;
+
+  static const notFound = const FileSystemEntityType._internal(3);
+  @Deprecated("Use notFound instead")
+  static const NOT_FOUND = notFound;
+
+  static const _typeList = const [
+    FileSystemEntityType.file,
+    FileSystemEntityType.directory,
+    FileSystemEntityType.link,
+    FileSystemEntityType.notFound,
+  ];
+  final int _type;
+
+  const FileSystemEntityType._internal(this._type);
+
+  static FileSystemEntityType _lookup(int type) => _typeList[type];
+  String toString() => const ['file', 'directory', 'link', 'notFound'][_type];
+}
+
+/**
+ * A FileStat object represents the result of calling the POSIX stat() function
+ * on a file system object.  It is an immutable object, representing the
+ * snapshotted values returned by the stat() call.
+ */
+class FileStat {
+  // These must agree with enum FileStat in file.h.
+  static const _type = 0;
+  static const _changedTime = 1;
+  static const _modifiedTime = 2;
+  static const _accessedTime = 3;
+  static const _mode = 4;
+  static const _size = 5;
+
+  static const _notFound = const FileStat._internalNotFound();
+
+  /**
+   * The time of the last change to the data or metadata of the file system
+   * object.
+   *
+   * On Windows platforms, this is instead the file creation time.
+   */
+  final DateTime changed;
+
+  /**
+   * The time of the last change to the data of the file system object.
+   */
+  final DateTime modified;
+
+  /**
+   * The time of the last access to the data of the file system object.
+   *
+   * On Windows platforms, this may have 1 day granularity, and be
+   * out of date by an hour.
+   */
+  final DateTime accessed;
+
+  /**
+   * The type of the underlying file system object.
+   *
+   * [FileSystemEntityType.notFound] if [stat] or [statSync] failed.
+   */
+  final FileSystemEntityType type;
+
+  /**
+   * The mode of the file system object.
+   *
+   * Permissions are encoded in the lower 16 bits of this number, and can be
+   * decoded using the [modeString] getter.
+   */
+  final int mode;
+
+  /**
+   * The size of the file system object.
+   */
+  final int size;
+
+  FileStat._internal(this.changed, this.modified, this.accessed, this.type,
+      this.mode, this.size);
+
+  const FileStat._internalNotFound()
+      : changed = null,
+        modified = null,
+        accessed = null,
+        type = FileSystemEntityType.notFound,
+        mode = 0,
+        size = -1;
+
+  external static _statSync(_Namespace namespace, String path);
+
+  /**
+   * Calls the operating system's `stat()` function (or equivalent) on [path].
+   *
+   * Returns a [FileStat] object containing the data returned by `stat()`.
+   * If the call fails, returns a [FileStat] object with [FileStat.type] set to
+   * [FileSystemEntityType.notFound] and the other fields invalid.
+   */
+  static FileStat statSync(String path) {
+    final IOOverrides overrides = IOOverrides.current;
+    if (overrides == null) {
+      return _statSyncInternal(path);
+    }
+    return overrides.statSync(path);
+  }
+
+  static FileStat _statSyncInternal(String path) {
+    // Trailing path is not supported on Windows.
+    if (Platform.isWindows) {
+      path = FileSystemEntity._trimTrailingPathSeparators(path);
+    }
+    var data = _statSync(_Namespace._namespace, path);
+    if (data is OSError) return FileStat._notFound;
+    return new FileStat._internal(
+        new DateTime.fromMillisecondsSinceEpoch(data[_changedTime]),
+        new DateTime.fromMillisecondsSinceEpoch(data[_modifiedTime]),
+        new DateTime.fromMillisecondsSinceEpoch(data[_accessedTime]),
+        FileSystemEntityType._lookup(data[_type]),
+        data[_mode],
+        data[_size]);
+  }
+
+  /**
+   * Asynchronously calls the operating system's `stat()` function (or
+   * equivalent) on [path].
+   *
+   * Returns a [Future] which completes with the same results as [statSync].
+   */
+  static Future<FileStat> stat(String path) {
+    final IOOverrides overrides = IOOverrides.current;
+    if (overrides == null) {
+      return _stat(path);
+    }
+    return overrides.stat(path);
+  }
+
+  static Future<FileStat> _stat(String path) {
+    // Trailing path is not supported on Windows.
+    if (Platform.isWindows) {
+      path = FileSystemEntity._trimTrailingPathSeparators(path);
+    }
+    return _File._dispatchWithNamespace(_IOService.fileStat, [null, path])
+        .then((response) {
+      if (_isErrorResponse(response)) {
+        return FileStat._notFound;
+      }
+      // Unwrap the real list from the "I'm not an error" wrapper.
+      List data = response[1];
+      return new FileStat._internal(
+          new DateTime.fromMillisecondsSinceEpoch(data[_changedTime]),
+          new DateTime.fromMillisecondsSinceEpoch(data[_modifiedTime]),
+          new DateTime.fromMillisecondsSinceEpoch(data[_accessedTime]),
+          FileSystemEntityType._lookup(data[_type]),
+          data[_mode],
+          data[_size]);
+    });
+  }
+
+  String toString() => """
+FileStat: type $type
+          changed $changed
+          modified $modified
+          accessed $accessed
+          mode ${modeString()}
+          size $size""";
+
+  /**
+   * Returns the mode value as a human-readable string.
+   *
+   * The string is in the format "rwxrwxrwx", reflecting the user, group, and
+   * world permissions to read, write, and execute the file system object, with
+   * "-" replacing the letter for missing permissions.  Extra permission bits
+   * may be represented by prepending "(suid)", "(guid)", and/or "(sticky)" to
+   * the mode string.
+   */
+  String modeString() {
+    var permissions = mode & 0xFFF;
+    var codes = const ['---', '--x', '-w-', '-wx', 'r--', 'r-x', 'rw-', 'rwx'];
+    var result = [];
+    if ((permissions & 0x800) != 0) result.add("(suid) ");
+    if ((permissions & 0x400) != 0) result.add("(guid) ");
+    if ((permissions & 0x200) != 0) result.add("(sticky) ");
+    result
+      ..add(codes[(permissions >> 6) & 0x7])
+      ..add(codes[(permissions >> 3) & 0x7])
+      ..add(codes[permissions & 0x7]);
+    return result.join();
+  }
+}
+
+/**
+ * The common super class for [File], [Directory], and [Link] objects.
+ *
+ * [FileSystemEntity] objects are returned from directory listing
+ * operations. To determine if a FileSystemEntity is a [File], a
+ * [Directory], or a [Link] perform a type check:
+ *
+ *     if (entity is File) (entity as File).readAsStringSync();
+ *
+ * You can also use the [type] or [typeSync] methods to determine
+ * the type of a file system object.
+ *
+ * Most methods in this class occur in synchronous and asynchronous pairs,
+ * for example, [exists] and [existsSync].
+ * Unless you have a specific reason for using the synchronous version
+ * of a method, prefer the asynchronous version to avoid blocking your program.
+ *
+ * Here's the exists method in action:
+ *
+ *     entity.exists().then((isThere) {
+ *       isThere ? print('exists') : print('non-existent');
+ *     });
+ *
+ *
+ * ## Other resources
+ *
+ * * [Dart by
+ *   Example](https://www.dartlang.org/dart-by-example/#files-directories-and-symlinks)
+ *   provides additional task-oriented code samples that show how to use various
+ *   API from the [Directory] class and the [File] class, both subclasses of
+ *   FileSystemEntity.
+ *
+ * * [I/O for Command-Line
+ *   Apps](https://www.dartlang.org/docs/dart-up-and-running/ch03.html#dartio---io-for-command-line-apps),
+ *   a section from _A Tour of the Dart Libraries_ covers files and directories.
+ *
+ * * [Write Command-Line Apps](https://www.dartlang.org/docs/tutorials/cmdline/),
+ *   a tutorial about writing command-line apps, includes information about
+ *   files and directories.
+ */
+abstract class FileSystemEntity {
+  String _path;
+  Uint8List _rawPath;
+
+  String get path;
+
+  /**
+   * Returns a [Uri] representing the file system entity's location.
+   *
+   * The returned URI's scheme is always "file" if the entity's [path] is
+   * absolute, otherwise the scheme will be empty.
+   */
+  Uri get uri => new Uri.file(path);
+
+  /**
+   * Checks whether the file system entity with this path exists. Returns
+   * a [:Future<bool>:] that completes with the result.
+   *
+   * Since FileSystemEntity is abstract, every FileSystemEntity object
+   * is actually an instance of one of the subclasses [File],
+   * [Directory], and [Link].  Calling [exists] on an instance of one
+   * of these subclasses checks whether the object exists in the file
+   * system object exists and is of the correct type (file, directory,
+   * or link).  To check whether a path points to an object on the
+   * file system, regardless of the object's type, use the [type]
+   * static method.
+   *
+   */
+  Future<bool> exists();
+
+  /**
+   * Synchronously checks whether the file system entity with this path
+   * exists.
+   *
+   * Since FileSystemEntity is abstract, every FileSystemEntity object
+   * is actually an instance of one of the subclasses [File],
+   * [Directory], and [Link].  Calling [existsSync] on an instance of
+   * one of these subclasses checks whether the object exists in the
+   * file system object exists and is of the correct type (file,
+   * directory, or link).  To check whether a path points to an object
+   * on the file system, regardless of the object's type, use the
+   * [typeSync] static method.
+   */
+  bool existsSync();
+
+  /**
+   * Renames this file system entity.
+   *
+   * Returns a `Future<FileSystemEntity>` that completes with a
+   * [FileSystemEntity] instance for the renamed file system entity.
+   *
+   * If [newPath] identifies an existing entity of the same type, that entity
+   * is replaced. If [newPath] identifies an existing entity of a different
+   * type, the operation fails and the future completes with an exception.
+   */
+  Future<FileSystemEntity> rename(String newPath);
+
+  /**
+   * Synchronously renames this file system entity.
+   *
+   * Returns a [FileSystemEntity] instance for the renamed entity.
+   *
+   * If [newPath] identifies an existing entity of the same type, that entity
+   * is replaced. If [newPath] identifies an existing entity of a different
+   * type, the operation fails and an exception is thrown.
+   */
+  FileSystemEntity renameSync(String newPath);
+
+  /**
+   * Resolves the path of a file system object relative to the
+   * current working directory.
+   *
+   * Resolves all symbolic links on the path and resolves all `..` and `.` path
+   * segments.
+   *
+   * [resolveSymbolicLinks] uses the operating system's native
+   * file system API to resolve the path, using the `realpath` function
+   * on linux and OS X, and the `GetFinalPathNameByHandle` function on
+   * Windows. If the path does not point to an existing file system object,
+   * `resolveSymbolicLinks` throws a `FileSystemException`.
+   *
+   * On Windows the `..` segments are resolved _before_ resolving the symbolic
+   * link, and on other platforms the symbolic links are _resolved to their
+   * target_ before applying a `..` that follows.
+   *
+   * To ensure the same behavior on all platforms resolve `..` segments before
+   * calling `resolveSymbolicLinks`. One way of doing this is with the `Uri`
+   * class:
+   *
+   *     var path = Uri.parse('.').resolveUri(new Uri.file(input)).toFilePath();
+   *     if (path == '') path = '.';
+   *     new File(path).resolveSymbolicLinks().then((resolved) {
+   *       print(resolved);
+   *     });
+   *
+   * since `Uri.resolve` removes `..` segments. This will result in the Windows
+   * behavior.
+   */
+  Future<String> resolveSymbolicLinks() {
+    return _File._dispatchWithNamespace(
+        _IOService.fileResolveSymbolicLinks, [null, _rawPath]).then((response) {
+      if (_isErrorResponse(response)) {
+        throw _exceptionFromResponse(
+            response, "Cannot resolve symbolic links", path);
+      }
+      return response;
+    });
+  }
+
+  /**
+   * Resolves the path of a file system object relative to the
+   * current working directory.
+   *
+   * Resolves all symbolic links on the path and resolves all `..` and `.` path
+   * segments.
+   *
+   * [resolveSymbolicLinksSync] uses the operating system's native
+   * file system API to resolve the path, using the `realpath` function
+   * on linux and OS X, and the `GetFinalPathNameByHandle` function on
+   * Windows. If the path does not point to an existing file system object,
+   * `resolveSymbolicLinksSync` throws a `FileSystemException`.
+   *
+   * On Windows the `..` segments are resolved _before_ resolving the symbolic
+   * link, and on other platforms the symbolic links are _resolved to their
+   * target_ before applying a `..` that follows.
+   *
+   * To ensure the same behavior on all platforms resolve `..` segments before
+   * calling `resolveSymbolicLinksSync`. One way of doing this is with the `Uri`
+   * class:
+   *
+   *     var path = Uri.parse('.').resolveUri(new Uri.file(input)).toFilePath();
+   *     if (path == '') path = '.';
+   *     var resolved = new File(path).resolveSymbolicLinksSync();
+   *     print(resolved);
+   *
+   * since `Uri.resolve` removes `..` segments. This will result in the Windows
+   * behavior.
+   */
+  String resolveSymbolicLinksSync() {
+    var result = _resolveSymbolicLinks(_Namespace._namespace, _rawPath);
+    _throwIfError(result, "Cannot resolve symbolic links", path);
+    return result;
+  }
+
+  /**
+   * Calls the operating system's stat() function on the [path] of this
+   * [FileSystemEntity].
+   *
+   * Identical to [:FileStat.stat(this.path):].
+   *
+   * Returns a [:Future<FileStat>:] object containing the data returned by
+   * stat().
+   *
+   * If the call fails, completes the future with a [FileStat] object
+   * with `.type` set to [FileSystemEntityType.notFound] and the other fields
+   * invalid.
+   */
+  Future<FileStat> stat() => FileStat.stat(path);
+
+  /**
+   * Synchronously calls the operating system's stat() function on the
+   * [path] of this [FileSystemEntity].
+   *
+   * Identical to [:FileStat.statSync(this.path):].
+   *
+   * Returns a [FileStat] object containing the data returned by stat().
+   *
+   * If the call fails, returns a [FileStat] object with `.type` set to
+   * [FileSystemEntityType.notFound] and the other fields invalid.
+   */
+  FileStat statSync() => FileStat.statSync(path);
+
+  /**
+   * Deletes this [FileSystemEntity].
+   *
+   * If the [FileSystemEntity] is a directory, and if [recursive] is false,
+   * the directory must be empty. Otherwise, if [recursive] is true, the
+   * directory and all sub-directories and files in the directories are
+   * deleted. Links are not followed when deleting recursively. Only the link
+   * is deleted, not its target.
+   *
+   * If [recursive] is true, the [FileSystemEntity] is deleted even if the type
+   * of the [FileSystemEntity] doesn't match the content of the file system.
+   * This behavior allows [delete] to be used to unconditionally delete any file
+   * system object.
+   *
+   * Returns a [:Future<FileSystemEntity>:] that completes with this
+   * [FileSystemEntity] when the deletion is done. If the [FileSystemEntity]
+   * cannot be deleted, the future completes with an exception.
+   */
+  Future<FileSystemEntity> delete({bool recursive: false}) =>
+      _delete(recursive: recursive);
+
+  /**
+   * Synchronously deletes this [FileSystemEntity].
+   *
+   * If the [FileSystemEntity] is a directory, and if [recursive] is false,
+   * the directory must be empty. Otherwise, if [recursive] is true, the
+   * directory and all sub-directories and files in the directories are
+   * deleted. Links are not followed when deleting recursively. Only the link
+   * is deleted, not its target.
+   *
+   * If [recursive] is true, the [FileSystemEntity] is deleted even if the type
+   * of the [FileSystemEntity] doesn't match the content of the file system.
+   * This behavior allows [deleteSync] to be used to unconditionally delete any
+   * file system object.
+   *
+   * Throws an exception if the [FileSystemEntity] cannot be deleted.
+   */
+  void deleteSync({bool recursive: false}) => _deleteSync(recursive: recursive);
+
+  /**
+   * Start watching the [FileSystemEntity] for changes.
+   *
+   * The implementation uses platform-dependent event-based APIs for receiving
+   * file-system notifications, thus behavior depends on the platform.
+   *
+   *   * `Windows`: Uses `ReadDirectoryChangesW`. The implementation only
+   *     supports watching directories. Recursive watching is supported.
+   *   * `Linux`: Uses `inotify`. The implementation supports watching both
+   *     files and directories. Recursive watching is not supported.
+   *     Note: When watching files directly, delete events might not happen
+   *     as expected.
+   *   * `OS X`: Uses `FSEvents`. The implementation supports watching both
+   *     files and directories. Recursive watching is supported.
+   *
+   * The system will start listening for events once the returned [Stream] is
+   * being listened to, not when the call to [watch] is issued.
+   *
+   * The returned value is an endless broadcast [Stream], that only stops when
+   * one of the following happens:
+   *
+   *   * The [Stream] is canceled, e.g. by calling `cancel` on the
+   *      [StreamSubscription].
+   *   * The [FileSystemEntity] being watches, is deleted.
+   *
+   * Use `events` to specify what events to listen for. The constants in
+   * [FileSystemEvent] can be or'ed together to mix events. Default is
+   * [FileSystemEvent.ALL].
+   *
+   * A move event may be reported as seperate delete and create events.
+   */
+  Stream<FileSystemEvent> watch(
+      {int events: FileSystemEvent.all, bool recursive: false}) {
+    // FIXME(bkonyi): find a way to do this using the raw path.
+    final String trimmedPath = _trimTrailingPathSeparators(path);
+    final IOOverrides overrides = IOOverrides.current;
+    if (overrides == null) {
+      return _FileSystemWatcher._watch(trimmedPath, events, recursive);
+    }
+    return overrides.fsWatch(trimmedPath, events, recursive);
+  }
+
+  Future<FileSystemEntity> _delete({bool recursive: false});
+  void _deleteSync({bool recursive: false});
+
+  static Future<bool> _identical(String path1, String path2) {
+    return _File._dispatchWithNamespace(
+        _IOService.fileIdentical, [null, path1, path2]).then((response) {
+      if (_isErrorResponse(response)) {
+        throw _exceptionFromResponse(response,
+            "Error in FileSystemEntity.identical($path1, $path2)", "");
+      }
+      return response;
+    });
+  }
+
+  /**
+   * Checks whether two paths refer to the same object in the
+   * file system.
+   *
+   * Returns a [:Future<bool>:] that completes with the result.
+   *
+   * Comparing a link to its target returns false, as does comparing two links
+   * that point to the same target.  To check the target of a link, use
+   * Link.target explicitly to fetch it.  Directory links appearing
+   * inside a path are followed, though, to find the file system object.
+   *
+   * Completes the returned Future with an error if one of the paths points
+   * to an object that does not exist.
+   */
+  static Future<bool> identical(String path1, String path2) {
+    IOOverrides overrides = IOOverrides.current;
+    if (overrides == null) {
+      return _identical(path1, path2);
+    }
+    return overrides.fseIdentical(path1, path2);
+  }
+
+  static final RegExp _absoluteWindowsPathPattern =
+      new RegExp(r'^(\\\\|[a-zA-Z]:[/\\])');
+
+  /**
+   * Returns a [bool] indicating whether this object's path is absolute.
+   *
+   * On Windows, a path is absolute if it starts with \\\\ or a drive letter
+   * between a and z (upper or lower case) followed by :\\ or :/.
+   * On non-Windows, a path is absolute if it starts with /.
+   */
+  bool get isAbsolute {
+    if (Platform.isWindows) {
+      return path.startsWith(_absoluteWindowsPathPattern);
+    } else {
+      return path.startsWith('/');
+    }
+  }
+
+  /**
+   * Returns a [FileSystemEntity] whose path is the absolute path to [this].
+   *
+   * The type of the returned instance is the type of [this].
+   *
+   * The absolute path is computed by prefixing
+   * a relative path with the current working directory, and returning
+   * an absolute path unchanged.
+   */
+  FileSystemEntity get absolute;
+
+  String get _absolutePath {
+    if (isAbsolute) return path;
+    String current = Directory.current.path;
+    if (current.endsWith('/') ||
+        (Platform.isWindows && current.endsWith('\\'))) {
+      return '$current$path';
+    } else {
+      return '$current${Platform.pathSeparator}$path';
+    }
+  }
+
+  Uint8List get _rawAbsolutePath {
+    if (isAbsolute) return _rawPath;
+    var current = Directory.current._rawPath.toList();
+    assert(current.last == 0);
+    current.removeLast(); // Remove null terminator.
+    if ((current.last == '/'.codeUnitAt(0)) ||
+        (Platform.isWindows && (current.last == '\\'.codeUnitAt(0)))) {
+      current.addAll(_rawPath);
+      return new Uint8List.fromList(current);
+    } else {
+      current.addAll(utf8.encode(Platform.pathSeparator));
+      current.addAll(_rawPath);
+      return new Uint8List.fromList(current);
+    }
+  }
+
+  static bool _identicalSync(String path1, String path2) {
+    var result = _identicalNative(_Namespace._namespace, path1, path2);
+    _throwIfError(result, 'Error in FileSystemEntity.identicalSync');
+    return result;
+  }
+
+  /**
+   * Synchronously checks whether two paths refer to the same object in the
+   * file system.
+   *
+   * Comparing a link to its target returns false, as does comparing two links
+   * that point to the same target.  To check the target of a link, use
+   * Link.target explicitly to fetch it.  Directory links appearing
+   * inside a path are followed, though, to find the file system object.
+   *
+   * Throws an error if one of the paths points to an object that does not
+   * exist.
+   */
+  static bool identicalSync(String path1, String path2) {
+    IOOverrides overrides = IOOverrides.current;
+    if (overrides == null) {
+      return _identicalSync(path1, path2);
+    }
+    return overrides.fseIdenticalSync(path1, path2);
+  }
+
+  /**
+   * Test if [watch] is supported on the current system.
+   *
+   * OS X 10.6 and below is not supported.
+   */
+  static bool get isWatchSupported {
+    final IOOverrides overrides = IOOverrides.current;
+    if (overrides == null) {
+      return _FileSystemWatcher.isSupported;
+    }
+    return overrides.fsWatchIsSupported();
+  }
+
+  // The native methods which determine type of the FileSystemEntity require
+  // that the buffer provided is null terminated.
+  static Uint8List _toUtf8Array(String s) =>
+      _toNullTerminatedUtf8Array(utf8.encode(s));
+
+  static Uint8List _toNullTerminatedUtf8Array(Uint8List l) {
+    if (l == null) {
+      return null;
+    }
+    if (l.isNotEmpty && l.last != 0) {
+      final tmp = new Uint8List(l.length + 1);
+      tmp.setRange(0, l.length, l);
+      return tmp;
+    } else {
+      return l;
+    }
+  }
+
+  static String _toStringFromUtf8Array(Uint8List l) {
+    if (l == null) {
+      return '';
+    }
+    Uint8List nonNullTerminated = l;
+    if (l.last == 0) {
+      nonNullTerminated = new Uint8List.view(l.buffer, 0, l.length - 1);
+    }
+    return utf8.decode(nonNullTerminated, allowMalformed: true);
+  }
+
+  /**
+   * Finds the type of file system object that a path points to.
+   *
+   * Returns a [:Future<FileSystemEntityType>:] that completes with the same
+   * results as [typeSync].
+   */
+  static Future<FileSystemEntityType> type(String path,
+      {bool followLinks: true}) {
+    return _getType(_toUtf8Array(path), followLinks);
+  }
+
+  /**
+   * Synchronously finds the type of file system object that a path points to.
+   *
+   * Returns a [FileSystemEntityType].
+   *
+   * Returns [FileSystemEntityType.link] only if [followLinks] is false and if
+   * [path] points to a link.
+   *
+   * Returns [FileSystemEntityType.notFound] if [path] does not point to a file
+   * system object or if any other error occurs in looking up the path.
+   */
+  static FileSystemEntityType typeSync(String path, {bool followLinks: true}) {
+    return _getTypeSync(_toUtf8Array(path), followLinks);
+  }
+
+  /**
+   * Checks if type(path, followLinks: false) returns FileSystemEntityType.link.
+   */
+  static Future<bool> isLink(String path) => _isLinkRaw(_toUtf8Array(path));
+
+  static Future<bool> _isLinkRaw(Uint8List rawPath) => _getType(rawPath, false)
+      .then((type) => (type == FileSystemEntityType.link));
+
+  /**
+   * Checks if type(path) returns FileSystemEntityType.file.
+   */
+  static Future<bool> isFile(String path) => _getType(_toUtf8Array(path), true)
+      .then((type) => (type == FileSystemEntityType.file));
+
+  /**
+   * Checks if type(path) returns FileSystemEntityType.directory.
+   */
+  static Future<bool> isDirectory(String path) =>
+      _getType(_toUtf8Array(path), true)
+          .then((type) => (type == FileSystemEntityType.directory));
+
+  /**
+   * Synchronously checks if typeSync(path, followLinks: false) returns
+   * FileSystemEntityType.link.
+   */
+  static bool isLinkSync(String path) => _isLinkRawSync(_toUtf8Array(path));
+
+  static bool _isLinkRawSync(rawPath) =>
+      (_getTypeSync(rawPath, false) == FileSystemEntityType.link);
+
+  /**
+   * Synchronously checks if typeSync(path) returns
+   * FileSystemEntityType.file.
+   */
+  static bool isFileSync(String path) =>
+      (_getTypeSync(_toUtf8Array(path), true) == FileSystemEntityType.file);
+
+  /**
+   * Synchronously checks if typeSync(path) returns
+   * FileSystemEntityType.directory.
+   */
+  static bool isDirectorySync(String path) =>
+      (_getTypeSync(_toUtf8Array(path), true) ==
+          FileSystemEntityType.directory);
+
+  external static _getTypeNative(
+      _Namespace namespace, Uint8List rawPath, bool followLinks);
+  external static _identicalNative(
+      _Namespace namespace, String path1, String path2);
+  external static _resolveSymbolicLinks(_Namespace namespace, Uint8List path);
+
+  // Finds the next-to-last component when dividing at path separators.
+  static final RegExp _parentRegExp = Platform.isWindows
+      ? new RegExp(r'[^/\\][/\\]+[^/\\]')
+      : new RegExp(r'[^/]/+[^/]');
+
+  /**
+   * Removes the final path component of a path, using the platform's
+   * path separator to split the path.
+   *
+   * Will not remove the root component of a Windows path, like "C:\\" or
+   * "\\\\server_name\\". Ignores trailing path separators, and leaves no
+   * trailing path separators.
+   */
+  static String parentOf(String path) {
+    int rootEnd = -1;
+    if (Platform.isWindows) {
+      if (path.startsWith(_absoluteWindowsPathPattern)) {
+        // Root ends at first / or \ after the first two characters.
+        rootEnd = path.indexOf(new RegExp(r'[/\\]'), 2);
+        if (rootEnd == -1) return path;
+      } else if (path.startsWith('\\') || path.startsWith('/')) {
+        rootEnd = 0;
+      }
+    } else if (path.startsWith('/')) {
+      rootEnd = 0;
+    }
+    // Ignore trailing slashes.
+    // All non-trivial cases have separators between two non-separators.
+    int pos = path.lastIndexOf(_parentRegExp);
+    if (pos > rootEnd) {
+      return path.substring(0, pos + 1);
+    } else if (rootEnd > -1) {
+      return path.substring(0, rootEnd + 1);
+    } else {
+      return '.';
+    }
+  }
+
+  /**
+   * The directory containing [this].
+   */
+  Directory get parent => new Directory(parentOf(path));
+
+  static FileSystemEntityType _getTypeSyncHelper(
+      Uint8List rawPath, bool followLinks) {
+    var result = _getTypeNative(_Namespace._namespace, rawPath, followLinks);
+    _throwIfError(result, 'Error getting type of FileSystemEntity');
+    return FileSystemEntityType._lookup(result);
+  }
+
+  static FileSystemEntityType _getTypeSync(
+      Uint8List rawPath, bool followLinks) {
+    IOOverrides overrides = IOOverrides.current;
+    if (overrides == null) {
+      return _getTypeSyncHelper(rawPath, followLinks);
+    }
+    return overrides.fseGetTypeSync(
+        utf8.decode(rawPath, allowMalformed: true), followLinks);
+  }
+
+  static Future<FileSystemEntityType> _getTypeRequest(
+      Uint8List rawPath, bool followLinks) {
+    return _File._dispatchWithNamespace(
+        _IOService.fileType, [null, rawPath, followLinks]).then((response) {
+      if (_isErrorResponse(response)) {
+        throw _exceptionFromResponse(response, "Error getting type",
+            utf8.decode(rawPath, allowMalformed: true));
+      }
+      return FileSystemEntityType._lookup(response);
+    });
+  }
+
+  static Future<FileSystemEntityType> _getType(
+      Uint8List rawPath, bool followLinks) {
+    IOOverrides overrides = IOOverrides.current;
+    if (overrides == null) {
+      return _getTypeRequest(rawPath, followLinks);
+    }
+    return overrides.fseGetType(
+        utf8.decode(rawPath, allowMalformed: true), followLinks);
+  }
+
+  static _throwIfError(Object result, String msg, [String path]) {
+    if (result is OSError) {
+      throw new FileSystemException(msg, path, result);
+    } else if (result is ArgumentError) {
+      throw result;
+    }
+  }
+
+  // TODO(bkonyi): find a way to do this with raw paths.
+  static String _trimTrailingPathSeparators(String path) {
+    // Don't handle argument errors here.
+    if (path == null) return path;
+    if (Platform.isWindows) {
+      while (path.length > 1 &&
+          (path.endsWith(Platform.pathSeparator) || path.endsWith('/'))) {
+        path = path.substring(0, path.length - 1);
+      }
+    } else {
+      while (path.length > 1 && path.endsWith(Platform.pathSeparator)) {
+        path = path.substring(0, path.length - 1);
+      }
+    }
+    return path;
+  }
+
+  // TODO(bkonyi): find a way to do this with raw paths.
+  static String _ensureTrailingPathSeparators(String path) {
+    // Don't handle argument errors here.
+    if (path == null) return path;
+    if (path.isEmpty) path = '.';
+    if (Platform.isWindows) {
+      while (!path.endsWith(Platform.pathSeparator) && !path.endsWith('/')) {
+        path = "$path${Platform.pathSeparator}";
+      }
+    } else {
+      while (!path.endsWith(Platform.pathSeparator)) {
+        path = "$path${Platform.pathSeparator}";
+      }
+    }
+    return path;
+  }
+}
+
+/**
+ * Base event class emitted by [FileSystemEntity.watch].
+ */
+class FileSystemEvent {
+  /**
+   * Bitfield for [FileSystemEntity.watch], to enable [FileSystemCreateEvent]s.
+   */
+  static const int create = 1 << 0;
+  @Deprecated("Use create instead")
+  static const int CREATE = 1 << 0;
+
+  /**
+   * Bitfield for [FileSystemEntity.watch], to enable [FileSystemModifyEvent]s.
+   */
+  static const int modify = 1 << 1;
+  @Deprecated("Use modify instead")
+  static const int MODIFY = 1 << 1;
+
+  /**
+   * Bitfield for [FileSystemEntity.watch], to enable [FileSystemDeleteEvent]s.
+   */
+  static const int delete = 1 << 2;
+  @Deprecated("Use delete instead")
+  static const int DELETE = 1 << 2;
+
+  /**
+   * Bitfield for [FileSystemEntity.watch], to enable [FileSystemMoveEvent]s.
+   */
+  static const int move = 1 << 3;
+  @Deprecated("Use move instead")
+  static const int MOVE = 1 << 3;
+
+  /**
+   * Bitfield for [FileSystemEntity.watch], for enabling all of [create],
+   * [modify], [delete] and [move].
+   */
+  static const int all = create | modify | delete | move;
+  @Deprecated("Use all instead")
+  static const int ALL = create | modify | delete | move;
+
+  static const int _modifyAttributes = 1 << 4;
+  static const int _deleteSelf = 1 << 5;
+  static const int _isDir = 1 << 6;
+
+  /**
+   * The type of event. See [FileSystemEvent] for a list of events.
+   */
+  final int type;
+
+  /**
+   * The path that triggered the event.
+   *
+   * Depending on the platform and the FileSystemEntity, the path may be
+   * relative.
+   */
+  final String path;
+
+  /**
+   * Is `true` if the event target was a directory.
+   *
+   * Note that if the file has been deleted by the time the event has arrived,
+   * this will always be `false` on Windows. In particular, it will always be
+   * `false` for `delete` events.
+   */
+  final bool isDirectory;
+
+  FileSystemEvent._(this.type, this.path, this.isDirectory);
+}
+
+/**
+ * File system event for newly created file system objects.
+ */
+class FileSystemCreateEvent extends FileSystemEvent {
+  FileSystemCreateEvent._(path, isDirectory)
+      : super._(FileSystemEvent.create, path, isDirectory);
+
+  String toString() => "FileSystemCreateEvent('$path')";
+}
+
+/**
+ * File system event for modifications of file system objects.
+ */
+class FileSystemModifyEvent extends FileSystemEvent {
+  /**
+   * If the content was changed and not only the attributes, [contentChanged]
+   * is `true`.
+   */
+  final bool contentChanged;
+
+  FileSystemModifyEvent._(path, isDirectory, this.contentChanged)
+      : super._(FileSystemEvent.modify, path, isDirectory);
+
+  String toString() =>
+      "FileSystemModifyEvent('$path', contentChanged=$contentChanged)";
+}
+
+/**
+ * File system event for deletion of file system objects.
+ */
+class FileSystemDeleteEvent extends FileSystemEvent {
+  FileSystemDeleteEvent._(path, isDirectory)
+      : super._(FileSystemEvent.delete, path, isDirectory);
+
+  String toString() => "FileSystemDeleteEvent('$path')";
+}
+
+/**
+ * File system event for moving of file system objects.
+ */
+class FileSystemMoveEvent extends FileSystemEvent {
+  /**
+   * If the underlying implementation is able to identify the destination of
+   * the moved file, [destination] will be set. Otherwise, it will be `null`.
+   */
+  final String destination;
+
+  FileSystemMoveEvent._(path, isDirectory, this.destination)
+      : super._(FileSystemEvent.move, path, isDirectory);
+
+  String toString() {
+    var buffer = new StringBuffer();
+    buffer.write("FileSystemMoveEvent('$path'");
+    if (destination != null) buffer.write(", '$destination'");
+    buffer.write(')');
+    return buffer.toString();
+  }
+}
+
+class _FileSystemWatcher {
+  external static Stream<FileSystemEvent> _watch(
+      String path, int events, bool recursive);
+  external static bool get isSupported;
+}
diff --git a/sdk_nnbd/lib/io/io.dart b/sdk_nnbd/lib/io/io.dart
new file mode 100644
index 0000000..c640c5b
--- /dev/null
+++ b/sdk_nnbd/lib/io/io.dart
@@ -0,0 +1,227 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/**
+ * File, socket, HTTP, and other I/O support for non-web applications.
+ *
+ * **Important:** Browser-based applications can't use this library.
+ * Only servers, command-line scripts, and Flutter mobile apps can import
+ * and use dart:io.
+ *
+ * This library allows you to work with files, directories,
+ * sockets, processes, HTTP servers and clients, and more.
+ * Many operations related to input and output are asynchronous
+ * and are handled using [Future]s or [Stream]s, both of which
+ * are defined in the [dart:async
+ * library](../dart-async/dart-async-library.html).
+ *
+ * To use the dart:io library in your code:
+ *
+ *     import 'dart:io';
+ *
+ * For an introduction to I/O in Dart, see the [dart:io library
+ * tour](https://www.dartlang.org/dart-vm/io-library-tour).
+ *
+ * ## File, Directory, and Link
+ *
+ * An instance of [File], [Directory], or [Link] represents a file,
+ * directory, or link, respectively, in the native file system.
+ *
+ * You can manipulate the file system through objects of these types.
+ * For example, you can rename a file or directory:
+ *
+ *     File myFile = new File('myFile.txt');
+ *     myFile.rename('yourFile.txt').then((_) => print('file renamed'));
+ *
+ * Many methods provided by the File, Directory, and Link classes
+ * run asynchronously and return a Future.
+ *
+ * ## FileSystemEntity
+ *
+ * File, Directory, and Link all extend [FileSystemEntity].
+ * In addition to being the superclass for these classes,
+ * FileSystemEntity has a number of static methods for working with paths.
+ *
+ * To get information about a path,
+ * you can use the FileSystemEntity static methods
+ * such as 'isDirectory', 'isFile', and 'exists'.
+ * Because file system access involves I/O, these methods
+ * are asynchronous and return a Future.
+ *
+ *     FileSystemEntity.isDirectory(myPath).then((isDir) {
+ *       if (isDir) {
+ *         print('$myPath is a directory');
+ *       } else {
+ *         print('$myPath is not a directory');
+ *       }
+ *     });
+ *
+ * ## HttpServer and HttpClient
+ *
+ * The classes [HttpServer] and [HttpClient]
+ * provide HTTP server and HTTP client functionality.
+ *
+ * The [HttpServer] class provides the basic functionality for
+ * implementing an HTTP server.
+ * For some higher-level building-blocks, we recommend that you try
+ * the [shelf](https://pub.dartlang.org/packages/shelf)
+ * pub package, which contains
+ * a set of high-level classes that, together with the [HttpServer] class
+ * in this library, make it easier to implement HTTP servers.
+ *
+ * ## Process
+ *
+ * The [Process] class provides a way to run a process on
+ * the native machine.
+ * For example, the following code spawns a process that recursively lists
+ * the files under `web`.
+ *
+ *     Process.start('ls', ['-R', 'web']).then((process) {
+ *       stdout.addStream(process.stdout);
+ *       stderr.addStream(process.stderr);
+ *       process.exitCode.then(print);
+ *     });
+ *
+ * Using `start()` returns a Future, which completes with a [Process] object
+ * when the process has started. This [Process] object allows you to interact
+ * with the process while it is running. Using `run()` returns a Future, which
+ * completes with a [ProcessResult] object when the spawned process has
+ * terminated. This [ProcessResult] object collects the output and exit code
+ * from the process.
+ *
+ * When using `start()`,
+ * you need to read all data coming on the stdout and stderr streams otherwise
+ * the system resources will not be freed.
+ *
+ * ## WebSocket
+ *
+ * The [WebSocket] class provides support for the web socket protocol. This
+ * allows full-duplex communications between client and server applications.
+ *
+ * A web socket server uses a normal HTTP server for accepting web socket
+ * connections. The initial handshake is a HTTP request which is then upgraded to a
+ * web socket connection.
+ * The server upgrades the request using [WebSocketTransformer]
+ * and listens for the data on the returned web socket.
+ * For example, here's a mini server that listens for 'ws' data
+ * on a WebSocket:
+ *
+ *     runZoned(() async {
+ *       var server = await HttpServer.bind('127.0.0.1', 4040);
+ *       server.listen((HttpRequest req) async {
+ *         if (req.uri.path == '/ws') {
+ *           var socket = await WebSocketTransformer.upgrade(req);
+ *           socket.listen(handleMsg);
+ *         }
+ *       });
+ *     }, onError: (e) => print("An error occurred."));
+ *
+ * The client connects to the WebSocket using the `connect()` method
+ * and a URI that uses the Web Socket protocol.
+ * The client can write to the WebSocket with the `add()` method.
+ * For example,
+ *
+ *     var socket = await WebSocket.connect('ws://127.0.0.1:4040/ws');
+ *     socket.add('Hello, World!');
+ *
+ * Check out the
+ * [websocket_sample](https://github.com/dart-lang/dart-samples/tree/master/html5/web/websockets/basics)
+ * app, which uses WebSockets to communicate with a server.
+ *
+ * ## Socket and ServerSocket
+ *
+ * Clients and servers use [Socket]s to communicate using the TCP protocol.
+ * Use [ServerSocket] on the server side and [Socket] on the client.
+ * The server creates a listening socket using the `bind()` method and
+ * then listens for incoming connections on the socket. For example:
+ *
+ *     ServerSocket.bind('127.0.0.1', 4041)
+ *       .then((serverSocket) {
+ *         serverSocket.listen((socket) {
+ *           socket.transform(utf8.decoder).listen(print);
+ *         });
+ *       });
+ *
+ * A client connects a Socket using the `connect()` method,
+ * which returns a Future.
+ * Using `write()`, `writeln()`, or `writeAll()` are the easiest ways to
+ * send data over the socket.
+ * For example:
+ *
+ *     Socket.connect('127.0.0.1', 4041).then((socket) {
+ *       socket.write('Hello, World!');
+ *     });
+ *
+ * Besides [Socket] and [ServerSocket], the [RawSocket] and
+ * [RawServerSocket] classes are available for lower-level access
+ * to async socket IO.
+ *
+ * ## Standard output, error, and input streams
+ *
+ * This library provides the standard output, error, and input
+ * streams, named 'stdout', 'stderr', and 'stdin', respectively.
+ *
+ * The stdout and stderr streams are both [IOSink]s and have the same set
+ * of methods and properties.
+ *
+ * To write a string to 'stdout':
+ *
+ *     stdout.writeln('Hello, World!');
+ *
+ * To write a list of objects to 'stderr':
+ *
+ *     stderr.writeAll([ 'That ', 'is ', 'an ', 'error.', '\n']);
+ *
+ * The standard input stream is a true [Stream], so it inherits
+ * properties and methods from the Stream class.
+ *
+ * To read text synchronously from the command line
+ * (the program blocks waiting for user to type information):
+ *
+ *      String inputText = stdin.readLineSync();
+ *
+ * {@category VM}
+ */
+library dart.io;
+
+import 'dart:async';
+import 'dart:_internal' hide Symbol;
+import 'dart:collection'
+    show HashMap, HashSet, Queue, ListQueue, MapBase, UnmodifiableMapView;
+import 'dart:convert';
+import 'dart:developer' hide log;
+import 'dart:isolate';
+import 'dart:math';
+import 'dart:typed_data';
+
+export 'dart:_http';
+export 'dart:_internal' show HttpStatus;
+
+part 'bytes_builder.dart';
+part 'common.dart';
+part 'data_transformer.dart';
+part 'directory.dart';
+part 'directory_impl.dart';
+part 'embedder_config.dart';
+part 'eventhandler.dart';
+part 'file.dart';
+part 'file_impl.dart';
+part 'file_system_entity.dart';
+part 'io_resource_info.dart';
+part 'io_sink.dart';
+part 'io_service.dart';
+part 'link.dart';
+part 'namespace_impl.dart';
+part 'overrides.dart';
+part 'platform.dart';
+part 'platform_impl.dart';
+part 'process.dart';
+part 'secure_server_socket.dart';
+part 'secure_socket.dart';
+part 'security_context.dart';
+part 'service_object.dart';
+part 'socket.dart';
+part 'stdio.dart';
+part 'string_transformer.dart';
+part 'sync_socket.dart';
diff --git a/sdk_nnbd/lib/io/io_resource_info.dart b/sdk_nnbd/lib/io/io_resource_info.dart
new file mode 100644
index 0000000..3e29221
--- /dev/null
+++ b/sdk_nnbd/lib/io/io_resource_info.dart
@@ -0,0 +1,282 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.io;
+
+abstract class _IOResourceInfo {
+  final String type;
+  final int id;
+  String get name;
+  static int _count = 0;
+
+  static final Stopwatch _sw = new Stopwatch()..start();
+  static final _startTime = new DateTime.now().millisecondsSinceEpoch;
+
+  static double get timestamp => _startTime + _sw.elapsedMicroseconds / 1000;
+
+  _IOResourceInfo(this.type) : id = _IOResourceInfo.getNextID();
+
+  /// Get the full set of values for a specific implementation. This is normally
+  /// looked up based on an id from a referenceValueMap.
+  Map<String, dynamic> get fullValueMap;
+
+  /// The reference map, used to return a list of values, e.g., getting
+  /// all open sockets. The structure of this is shared among all subclasses.
+  Map<String, dynamic> get referenceValueMap => {
+        // The type for a reference object is prefixed with @ in observatory.
+        'type': '@$type',
+        'id': id,
+        'name': name,
+      };
+
+  static int getNextID() => _count++;
+}
+
+abstract class _ReadWriteResourceInfo extends _IOResourceInfo {
+  int totalRead;
+  int totalWritten;
+  int readCount;
+  int writeCount;
+  double lastRead;
+  double lastWrite;
+
+  // Not all call sites use this. In some cases, e.g., a socket, a read does
+  // not always mean that we actually read some bytes (we may do a read to see
+  // if there are some bytes available).
+  void addRead(int bytes) {
+    totalRead += bytes;
+    readCount++;
+    lastRead = _IOResourceInfo.timestamp;
+  }
+
+  // In cases where we read but did not necessarily get any bytes, use this to
+  // update the readCount and timestamp. Manually update totalRead if any bytes
+  // where actually read.
+  void didRead() {
+    addRead(0);
+  }
+
+  void addWrite(int bytes) {
+    totalWritten += bytes;
+    writeCount++;
+    lastWrite = _IOResourceInfo.timestamp;
+  }
+
+  _ReadWriteResourceInfo(String type)
+      : totalRead = 0,
+        totalWritten = 0,
+        readCount = 0,
+        writeCount = 0,
+        lastRead = 0.0,
+        lastWrite = 0.0,
+        super(type);
+
+  Map<String, dynamic> get fullValueMap => {
+        'type': type,
+        'id': id,
+        'name': name,
+        'totalRead': totalRead,
+        'totalWritten': totalWritten,
+        'readCount': readCount,
+        'writeCount': writeCount,
+        'lastRead': lastRead,
+        'lastWrite': lastWrite
+      };
+}
+
+class _FileResourceInfo extends _ReadWriteResourceInfo {
+  static const String _type = '_file';
+
+  final file;
+
+  static Map<int, _FileResourceInfo> openFiles =
+      new Map<int, _FileResourceInfo>();
+
+  _FileResourceInfo(this.file) : super(_type) {
+    FileOpened(this);
+  }
+
+  static FileOpened(_FileResourceInfo info) {
+    assert(!openFiles.containsKey(info.id));
+    openFiles[info.id] = info;
+  }
+
+  static FileClosed(_FileResourceInfo info) {
+    assert(openFiles.containsKey(info.id));
+    openFiles.remove(info.id);
+  }
+
+  static Iterable<Map<String, dynamic>> getOpenFilesList() {
+    return new List.from(openFiles.values.map((e) => e.referenceValueMap));
+  }
+
+  static Future<ServiceExtensionResponse> getOpenFiles(function, params) {
+    assert(function == 'ext.dart.io.getOpenFiles');
+    var data = {'type': '_openfiles', 'data': getOpenFilesList()};
+    var jsonValue = json.encode(data);
+    return new Future.value(new ServiceExtensionResponse.result(jsonValue));
+  }
+
+  Map<String, dynamic> getFileInfoMap() {
+    return fullValueMap;
+  }
+
+  static Future<ServiceExtensionResponse> getFileInfoMapByID(function, params) {
+    assert(params.containsKey('id'));
+    var id = int.parse(params['id']);
+    var result =
+        openFiles.containsKey(id) ? openFiles[id].getFileInfoMap() : {};
+    var jsonValue = json.encode(result);
+    return new Future.value(new ServiceExtensionResponse.result(jsonValue));
+  }
+
+  String get name {
+    return '${file.path}';
+  }
+}
+
+class _ProcessResourceInfo extends _IOResourceInfo {
+  static const String _type = '_process';
+  final process;
+  final double startedAt;
+
+  static Map<int, _ProcessResourceInfo> startedProcesses =
+      new Map<int, _ProcessResourceInfo>();
+
+  _ProcessResourceInfo(this.process)
+      : startedAt = _IOResourceInfo.timestamp,
+        super(_type) {
+    ProcessStarted(this);
+  }
+
+  String get name => process._path;
+
+  void stopped() {
+    ProcessStopped(this);
+  }
+
+  Map<String, dynamic> get fullValueMap => {
+        'type': type,
+        'id': id,
+        'name': name,
+        'pid': process.pid,
+        'startedAt': startedAt,
+        'arguments': process._arguments,
+        'workingDirectory':
+            process._workingDirectory == null ? '.' : process._workingDirectory,
+      };
+
+  static ProcessStarted(_ProcessResourceInfo info) {
+    assert(!startedProcesses.containsKey(info.id));
+    startedProcesses[info.id] = info;
+  }
+
+  static ProcessStopped(_ProcessResourceInfo info) {
+    assert(startedProcesses.containsKey(info.id));
+    startedProcesses.remove(info.id);
+  }
+
+  static Iterable<Map<String, dynamic>> getStartedProcessesList() =>
+      new List.from(startedProcesses.values.map((e) => e.referenceValueMap));
+
+  static Future<ServiceExtensionResponse> getStartedProcesses(
+      String function, Map<String, String> params) {
+    assert(function == 'ext.dart.io.getProcesses');
+    var data = {'type': '_startedprocesses', 'data': getStartedProcessesList()};
+    var jsonValue = json.encode(data);
+    return new Future.value(new ServiceExtensionResponse.result(jsonValue));
+  }
+
+  static Future<ServiceExtensionResponse> getProcessInfoMapById(
+      String function, Map<String, String> params) {
+    var id = int.parse(params['id']);
+    var result = startedProcesses.containsKey(id)
+        ? startedProcesses[id].fullValueMap
+        : {};
+    var jsonValue = json.encode(result);
+    return new Future.value(new ServiceExtensionResponse.result(jsonValue));
+  }
+}
+
+class _SocketResourceInfo extends _ReadWriteResourceInfo {
+  static const String _tcpString = 'TCP';
+  static const String _udpString = 'UDP';
+  static const String _type = '_socket';
+
+  final /*_NativeSocket|*/ socket;
+
+  static Map<int, _SocketResourceInfo> openSockets =
+      new Map<int, _SocketResourceInfo>();
+
+  _SocketResourceInfo(this.socket) : super(_type) {
+    SocketOpened(this);
+  }
+
+  String get name {
+    if (socket.isListening) {
+      return 'listening:${socket.address.host}:${socket.port}';
+    }
+    var remote = '';
+    try {
+      var remoteHost = socket.remoteAddress.host;
+      var remotePort = socket.remotePort;
+      remote = ' -> $remoteHost:$remotePort';
+    } catch (e) {} // ignored if we can't get the information
+    return '${socket.address.host}:${socket.port}$remote';
+  }
+
+  static Iterable<Map<String, dynamic>> getOpenSocketsList() {
+    return new List.from(openSockets.values.map((e) => e.referenceValueMap));
+  }
+
+  Map<String, dynamic> getSocketInfoMap() {
+    var result = fullValueMap;
+    result['socketType'] = socket.isTcp ? _tcpString : _udpString;
+    result['listening'] = socket.isListening;
+    result['host'] = socket.address.host;
+    result['port'] = socket.port;
+    if (!socket.isListening) {
+      try {
+        result['remoteHost'] = socket.remoteAddress.host;
+        result['remotePort'] = socket.remotePort;
+      } catch (e) {
+        // UDP.
+        result['remotePort'] = 'NA';
+        result['remoteHost'] = 'NA';
+      }
+    } else {
+      result['remotePort'] = 'NA';
+      result['remoteHost'] = 'NA';
+    }
+    result['addressType'] = socket.address.type.name;
+    return result;
+  }
+
+  static Future<ServiceExtensionResponse> getSocketInfoMapByID(
+      String function, Map<String, String> params) {
+    assert(params.containsKey('id'));
+    var id = int.parse(params['id']);
+    var result =
+        openSockets.containsKey(id) ? openSockets[id].getSocketInfoMap() : {};
+    var jsonValue = json.encode(result);
+    return new Future.value(new ServiceExtensionResponse.result(jsonValue));
+  }
+
+  static Future<ServiceExtensionResponse> getOpenSockets(function, params) {
+    assert(function == 'ext.dart.io.getOpenSockets');
+    var data = {'type': '_opensockets', 'data': getOpenSocketsList()};
+    var jsonValue = json.encode(data);
+    return new Future.value(new ServiceExtensionResponse.result(jsonValue));
+  }
+
+  static SocketOpened(_SocketResourceInfo info) {
+    assert(!openSockets.containsKey(info.id));
+    openSockets[info.id] = info;
+  }
+
+  static SocketClosed(_SocketResourceInfo info) {
+    assert(openSockets.containsKey(info.id));
+    openSockets.remove(info.id);
+  }
+}
diff --git a/sdk_nnbd/lib/io/io_service.dart b/sdk_nnbd/lib/io/io_service.dart
new file mode 100644
index 0000000..7af382c
--- /dev/null
+++ b/sdk_nnbd/lib/io/io_service.dart
@@ -0,0 +1,54 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.io;
+
+class _IOService {
+  // This list must be kept in sync with the list in runtime/bin/io_service.h
+  static const int fileExists = 0;
+  static const int fileCreate = 1;
+  static const int fileDelete = 2;
+  static const int fileRename = 3;
+  static const int fileCopy = 4;
+  static const int fileOpen = 5;
+  static const int fileResolveSymbolicLinks = 6;
+  static const int fileClose = 7;
+  static const int filePosition = 8;
+  static const int fileSetPosition = 9;
+  static const int fileTruncate = 10;
+  static const int fileLength = 11;
+  static const int fileLengthFromPath = 12;
+  static const int fileLastAccessed = 13;
+  static const int fileSetLastAccessed = 14;
+  static const int fileLastModified = 15;
+  static const int fileSetLastModified = 16;
+  static const int fileFlush = 17;
+  static const int fileReadByte = 18;
+  static const int fileWriteByte = 19;
+  static const int fileRead = 20;
+  static const int fileReadInto = 21;
+  static const int fileWriteFrom = 22;
+  static const int fileCreateLink = 23;
+  static const int fileDeleteLink = 24;
+  static const int fileRenameLink = 25;
+  static const int fileLinkTarget = 26;
+  static const int fileType = 27;
+  static const int fileIdentical = 28;
+  static const int fileStat = 29;
+  static const int fileLock = 30;
+  static const int socketLookup = 31;
+  static const int socketListInterfaces = 32;
+  static const int socketReverseLookup = 33;
+  static const int directoryCreate = 34;
+  static const int directoryDelete = 35;
+  static const int directoryExists = 36;
+  static const int directoryCreateTemp = 37;
+  static const int directoryListStart = 38;
+  static const int directoryListNext = 39;
+  static const int directoryListStop = 40;
+  static const int directoryRename = 41;
+  static const int sslProcessFilter = 42;
+
+  external static Future _dispatch(int request, List data);
+}
diff --git a/sdk_nnbd/lib/io/io_sink.dart b/sdk_nnbd/lib/io/io_sink.dart
new file mode 100644
index 0000000..5481265
--- /dev/null
+++ b/sdk_nnbd/lib/io/io_sink.dart
@@ -0,0 +1,316 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.io;
+
+/**
+ * A combined byte and text output.
+ *
+ * An [IOSink] combines a [StreamSink] of bytes with a [StringSink],
+ * and allows easy output of both bytes and text.
+ *
+ * Writing text ([write]) and adding bytes ([add]) may be interleaved freely.
+ *
+ * While a stream is being added using [addStream], any further attempts
+ * to add or write to the [IOSink] will fail until the [addStream] completes.
+ *
+ * It is an error to add data to the [IOSink] after the sink is closed.
+ */
+abstract class IOSink implements StreamSink<List<int>>, StringSink {
+  /**
+   * Create an [IOSink] that outputs to a [target] [StreamConsumer] of bytes.
+   *
+   * Text written to [StreamSink] methods is encoded to bytes using [encoding]
+   * before being output on [target].
+   */
+  factory IOSink(StreamConsumer<List<int>> target, {Encoding encoding: utf8}) =>
+      new _IOSinkImpl(target, encoding);
+
+  /**
+   * The [Encoding] used when writing strings. Depending on the
+   * underlying consumer this property might be mutable.
+   */
+  Encoding encoding;
+
+  /**
+   * Adds byte [data] to the target consumer, ignoring [encoding].
+   *
+   * The [encoding] does not apply to this method, and the `data` list is passed
+   * directly to the target consumer as a stream event.
+   *
+   * This function must not be called when a stream is currently being added
+   * using [addStream].
+   *
+   * This operation is non-blocking. See [flush] or [done] for how to get any
+   * errors generated by this call.
+   *
+   * The data list should not be modified after it has been passed to `add`.
+   */
+  void add(List<int> data);
+
+  /**
+   * Converts [obj] to a String by invoking [Object.toString] and
+   * [add]s the encoding of the result to the target consumer.
+   *
+   * This operation is non-blocking. See [flush] or [done] for how to get any
+   * errors generated by this call.
+   */
+  void write(Object obj);
+
+  /**
+   * Iterates over the given [objects] and [write]s them in sequence.
+   *
+   * If [separator] is provided, a `write` with the `separator` is performed
+   * between any two elements of objects`.
+   *
+   * This operation is non-blocking. See [flush] or [done] for how to get any
+   * errors generated by this call.
+   */
+  void writeAll(Iterable objects, [String separator = ""]);
+
+  /**
+   * Converts [obj] to a String by invoking [Object.toString] and
+   * writes the result to `this`, followed by a newline.
+   *
+   * This operation is non-blocking. See [flush] or [done] for how to get any
+   * errors generated by this call.
+   */
+  void writeln([Object obj = ""]);
+
+  /**
+   * Writes the character of [charCode].
+   *
+   * This method is equivalent to `write(new String.fromCharCode(charCode))`.
+   *
+   * This operation is non-blocking. See [flush] or [done] for how to get any
+   * errors generated by this call.
+   */
+  void writeCharCode(int charCode);
+
+  /**
+   * Passes the error to the target consumer as an error event.
+   *
+   * This function must not be called when a stream is currently being added
+   * using [addStream].
+   *
+   * This operation is non-blocking. See [flush] or [done] for how to get any
+   * errors generated by this call.
+   */
+  void addError(error, [StackTrace stackTrace]);
+
+  /**
+   * Adds all elements of the given [stream] to `this`.
+   *
+   * Returns a [Future] that completes when
+   * all elements of the given [stream] are added to `this`.
+   *
+   * This function must not be called when a stream is currently being added
+   * using this function.
+   */
+  Future addStream(Stream<List<int>> stream);
+
+  /**
+   * Returns a [Future] that completes once all buffered data is accepted by the
+   * underlying [StreamConsumer].
+   *
+   * This method must not be called while an [addStream] is incomplete.
+   *
+   * NOTE: This is not necessarily the same as the data being flushed by the
+   * operating system.
+   */
+  Future flush();
+
+  /**
+   * Close the target consumer.
+   *
+   * NOTE: Writes to the [IOSink] may be buffered, and may not be flushed by
+   * a call to `close()`. To flush all buffered writes, call `flush()` before
+   * calling `close()`.
+   */
+  Future close();
+
+  /**
+   * Get a future that will complete when the consumer closes, or when an
+   * error occurs. This future is identical to the future returned by
+   * [close].
+   */
+  Future get done;
+}
+
+class _StreamSinkImpl<T> implements StreamSink<T> {
+  final StreamConsumer<T> _target;
+  final Completer _doneCompleter = new Completer();
+  StreamController<T> _controllerInstance;
+  Completer _controllerCompleter;
+  bool _isClosed = false;
+  bool _isBound = false;
+  bool _hasError = false;
+
+  _StreamSinkImpl(this._target);
+
+  void add(T data) {
+    if (_isClosed) {
+      throw StateError("StreamSink is closed");
+    }
+    _controller.add(data);
+  }
+
+  void addError(error, [StackTrace stackTrace]) {
+    if (_isClosed) {
+      throw StateError("StreamSink is closed");
+    }
+    _controller.addError(error, stackTrace);
+  }
+
+  Future addStream(Stream<T> stream) {
+    if (_isBound) {
+      throw new StateError("StreamSink is already bound to a stream");
+    }
+    if (_hasError) return done;
+
+    _isBound = true;
+    var future = _controllerCompleter == null
+        ? _target.addStream(stream)
+        : _controllerCompleter.future.then((_) => _target.addStream(stream));
+    _controllerInstance?.close();
+
+    // Wait for any pending events in [_controller] to be dispatched before
+    // adding [stream].
+    return future.whenComplete(() {
+      _isBound = false;
+    });
+  }
+
+  Future flush() {
+    if (_isBound) {
+      throw new StateError("StreamSink is bound to a stream");
+    }
+    if (_controllerInstance == null) return new Future.value(this);
+    // Adding an empty stream-controller will return a future that will complete
+    // when all data is done.
+    _isBound = true;
+    var future = _controllerCompleter.future;
+    _controllerInstance.close();
+    return future.whenComplete(() {
+      _isBound = false;
+    });
+  }
+
+  Future close() {
+    if (_isBound) {
+      throw new StateError("StreamSink is bound to a stream");
+    }
+    if (!_isClosed) {
+      _isClosed = true;
+      if (_controllerInstance != null) {
+        _controllerInstance.close();
+      } else {
+        _closeTarget();
+      }
+    }
+    return done;
+  }
+
+  void _closeTarget() {
+    _target.close().then(_completeDoneValue, onError: _completeDoneError);
+  }
+
+  Future get done => _doneCompleter.future;
+
+  void _completeDoneValue(value) {
+    if (!_doneCompleter.isCompleted) {
+      _doneCompleter.complete(value);
+    }
+  }
+
+  void _completeDoneError(error, StackTrace stackTrace) {
+    if (!_doneCompleter.isCompleted) {
+      _hasError = true;
+      _doneCompleter.completeError(error, stackTrace);
+    }
+  }
+
+  StreamController<T> get _controller {
+    if (_isBound) {
+      throw new StateError("StreamSink is bound to a stream");
+    }
+    if (_isClosed) {
+      throw new StateError("StreamSink is closed");
+    }
+    if (_controllerInstance == null) {
+      _controllerInstance = new StreamController<T>(sync: true);
+      _controllerCompleter = new Completer();
+      _target.addStream(_controller.stream).then((_) {
+        if (_isBound) {
+          // A new stream takes over - forward values to that stream.
+          _controllerCompleter.complete(this);
+          _controllerCompleter = null;
+          _controllerInstance = null;
+        } else {
+          // No new stream, .close was called. Close _target.
+          _closeTarget();
+        }
+      }, onError: (error, stackTrace) {
+        if (_isBound) {
+          // A new stream takes over - forward errors to that stream.
+          _controllerCompleter.completeError(error, stackTrace);
+          _controllerCompleter = null;
+          _controllerInstance = null;
+        } else {
+          // No new stream. No need to close target, as it has already
+          // failed.
+          _completeDoneError(error, stackTrace);
+        }
+      });
+    }
+    return _controllerInstance;
+  }
+}
+
+class _IOSinkImpl extends _StreamSinkImpl<List<int>> implements IOSink {
+  Encoding _encoding;
+  bool _encodingMutable = true;
+
+  _IOSinkImpl(StreamConsumer<List<int>> target, this._encoding) : super(target);
+
+  Encoding get encoding => _encoding;
+
+  void set encoding(Encoding value) {
+    if (!_encodingMutable) {
+      throw new StateError("IOSink encoding is not mutable");
+    }
+    _encoding = value;
+  }
+
+  void write(Object obj) {
+    String string = '$obj';
+    if (string.isEmpty) return;
+    add(_encoding.encode(string));
+  }
+
+  void writeAll(Iterable objects, [String separator = ""]) {
+    Iterator iterator = objects.iterator;
+    if (!iterator.moveNext()) return;
+    if (separator.isEmpty) {
+      do {
+        write(iterator.current);
+      } while (iterator.moveNext());
+    } else {
+      write(iterator.current);
+      while (iterator.moveNext()) {
+        write(separator);
+        write(iterator.current);
+      }
+    }
+  }
+
+  void writeln([Object object = ""]) {
+    write(object);
+    write("\n");
+  }
+
+  void writeCharCode(int charCode) {
+    write(new String.fromCharCode(charCode));
+  }
+}
diff --git a/sdk_nnbd/lib/io/io_sources.gni b/sdk_nnbd/lib/io/io_sources.gni
new file mode 100644
index 0000000..51e283a
--- /dev/null
+++ b/sdk_nnbd/lib/io/io_sources.gni
@@ -0,0 +1,36 @@
+# 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.
+
+io_sdk_sources = [
+  "io.dart",
+
+  # The above file needs to be first if additional parts are added to the lib.
+  "bytes_builder.dart",
+  "common.dart",
+  "data_transformer.dart",
+  "directory.dart",
+  "directory_impl.dart",
+  "embedder_config.dart",
+  "eventhandler.dart",
+  "file.dart",
+  "file_impl.dart",
+  "file_system_entity.dart",
+  "io_resource_info.dart",
+  "io_sink.dart",
+  "io_service.dart",
+  "link.dart",
+  "namespace_impl.dart",
+  "overrides.dart",
+  "platform.dart",
+  "platform_impl.dart",
+  "process.dart",
+  "service_object.dart",
+  "secure_server_socket.dart",
+  "secure_socket.dart",
+  "security_context.dart",
+  "socket.dart",
+  "stdio.dart",
+  "string_transformer.dart",
+  "sync_socket.dart",
+]
diff --git a/sdk_nnbd/lib/io/link.dart b/sdk_nnbd/lib/io/link.dart
new file mode 100644
index 0000000..79f8656
--- /dev/null
+++ b/sdk_nnbd/lib/io/link.dart
@@ -0,0 +1,300 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.io;
+
+/**
+ * [Link] objects are references to filesystem links.
+ *
+ */
+@pragma("vm:entry-point")
+abstract class Link implements FileSystemEntity {
+  /**
+   * Creates a Link object.
+   */
+  @pragma("vm:entry-point")
+  factory Link(String path) {
+    final IOOverrides overrides = IOOverrides.current;
+    if (overrides == null) {
+      return new _Link(path);
+    }
+    return overrides.createLink(path);
+  }
+
+  @pragma("vm:entry-point")
+  factory Link.fromRawPath(Uint8List rawPath) {
+    // TODO(bkonyi): handle overrides
+    return new _Link.fromRawPath(rawPath);
+  }
+
+  /**
+   * Creates a [Link] object.
+   *
+   * If [path] is a relative path, it will be interpreted relative to the
+   * current working directory (see [Directory.current]), when used.
+   *
+   * If [path] is an absolute path, it will be immune to changes to the
+   * current working directory.
+   */
+  factory Link.fromUri(Uri uri) => new Link(uri.toFilePath());
+
+  /**
+   * Creates a symbolic link. Returns a [:Future<Link>:] that completes with
+   * the link when it has been created. If the link exists,
+   * the future will complete with an error.
+   *
+   * If [recursive] is false, the default, the link is created
+   * only if all directories in its path exist.
+   * If [recursive] is true, all non-existing path
+   * components are created. The directories in the path of [target] are
+   * not affected, unless they are also in [path].
+   *
+   * On the Windows platform, this call will create a true symbolic link
+   * instead of a Junction. In order to create a symbolic link on Windows, Dart
+   * must be run in Administrator mode or the system must have Developer Mode
+   * enabled, otherwise a [FileSystemException] will be raised with 
+   * `ERROR_PRIVILEGE_NOT_HELD` set as the errno when this call is made.
+   *
+   * On other platforms, the posix symlink() call is used to make a symbolic
+   * link containing the string [target].  If [target] is a relative path,
+   * it will be interpreted relative to the directory containing the link.
+   */
+  Future<Link> create(String target, {bool recursive: false});
+
+  /**
+   * Synchronously create the link. Calling [createSync] on an existing link
+   * will throw an exception.
+   *
+   * If [recursive] is false, the default, the link is created only if all
+   * directories in its path exist. If [recursive] is true, all
+   * non-existing path components are created. The directories in
+   * the path of [target] are not affected, unless they are also in [path].
+   *
+   * On the Windows platform, this call will create a true symbolic link
+   * instead of a Junction. In order to create a symbolic link on Windows, Dart
+   * must be run in Administrator mode or the system must have Developer Mode
+   * enabled, otherwise a [FileSystemException] will be raised with 
+   * `ERROR_PRIVILEGE_NOT_HELD` set as the errno when this call is made.
+   *
+   * On other platforms, the posix symlink() call is used to make a symbolic
+   * link containing the string [target].  If [target] is a relative path,
+   * it will be interpreted relative to the directory containing the link.
+   */
+  void createSync(String target, {bool recursive: false});
+
+  /**
+   * Synchronously updates the link. Calling [updateSync] on a non-existing link
+   * will throw an exception.
+   */
+  void updateSync(String target);
+
+  /**
+   * Updates the link. Returns a [:Future<Link>:] that completes with the
+   * link when it has been updated.  Calling [update] on a non-existing link
+   * will complete its returned future with an exception.
+   */
+  Future<Link> update(String target);
+
+  Future<String> resolveSymbolicLinks();
+
+  String resolveSymbolicLinksSync();
+
+  /**
+   * Renames this link. Returns a `Future<Link>` that completes
+   * with a [Link] instance for the renamed link.
+   *
+   * If [newPath] identifies an existing link, that link is
+   * replaced. If [newPath] identifies an existing file or directory,
+   * the operation fails and the future completes with an exception.
+   */
+  Future<Link> rename(String newPath);
+
+  /**
+   * Synchronously renames this link. Returns a [Link]
+   * instance for the renamed link.
+   *
+   * If [newPath] identifies an existing link, that link is
+   * replaced. If [newPath] identifies an existing file or directory
+   * the operation fails and an exception is thrown.
+   */
+  Link renameSync(String newPath);
+
+  /**
+   * Returns a [Link] instance whose path is the absolute path to [this].
+   *
+   * The absolute path is computed by prefixing
+   * a relative path with the current working directory, and returning
+   * an absolute path unchanged.
+   */
+  Link get absolute;
+
+  /**
+   * Gets the target of the link. Returns a future that completes with
+   * the path to the target.
+   *
+   * If the returned target is a relative path, it is relative to the
+   * directory containing the link.
+   *
+   * If the link does not exist, or is not a link, the future completes with
+   * a FileSystemException.
+   */
+  Future<String> target();
+
+  /**
+   * Synchronously gets the target of the link. Returns the path to the target.
+   *
+   * If the returned target is a relative path, it is relative to the
+   * directory containing the link.
+   *
+   * If the link does not exist, or is not a link, throws a FileSystemException.
+   */
+  String targetSync();
+}
+
+class _Link extends FileSystemEntity implements Link {
+  String _path;
+  Uint8List _rawPath;
+
+  _Link(String path) {
+    ArgumentError.checkNotNull(path, 'path');
+    _path = path;
+    _rawPath = FileSystemEntity._toUtf8Array(path);
+  }
+
+  _Link.fromRawPath(Uint8List rawPath) {
+    _rawPath = FileSystemEntity._toNullTerminatedUtf8Array(rawPath);
+    _path = FileSystemEntity._toStringFromUtf8Array(rawPath);
+  }
+
+  String get path => _path;
+
+  String toString() => "Link: '$path'";
+
+  Future<bool> exists() => FileSystemEntity._isLinkRaw(_rawPath);
+
+  bool existsSync() => FileSystemEntity._isLinkRawSync(_rawPath);
+
+  Link get absolute => new Link.fromRawPath(_rawAbsolutePath);
+
+  Future<Link> create(String target, {bool recursive: false}) {
+    var result =
+        recursive ? parent.create(recursive: true) : new Future.value(null);
+    return result
+        .then((_) => _File._dispatchWithNamespace(
+            _IOService.fileCreateLink, [null, _rawPath, target]))
+        .then((response) {
+      if (_isErrorResponse(response)) {
+        throw _exceptionFromResponse(
+            response, "Cannot create link to target '$target'", path);
+      }
+      return this;
+    });
+  }
+
+  void createSync(String target, {bool recursive: false}) {
+    if (recursive) {
+      parent.createSync(recursive: true);
+    }
+    var result = _File._createLink(_Namespace._namespace, _rawPath, target);
+    throwIfError(result, "Cannot create link", path);
+  }
+
+  void updateSync(String target) {
+    // TODO(12414): Replace with atomic update, where supported by platform.
+    // Atomically changing a link can be done by creating the new link, with
+    // a different name, and using the rename() posix call to move it to
+    // the old name atomically.
+    deleteSync();
+    createSync(target);
+  }
+
+  Future<Link> update(String target) {
+    // TODO(12414): Replace with atomic update, where supported by platform.
+    // Atomically changing a link can be done by creating the new link, with
+    // a different name, and using the rename() posix call to move it to
+    // the old name atomically.
+    return delete().then<Link>((_) => create(target));
+  }
+
+  Future<Link> _delete({bool recursive: false}) {
+    if (recursive) {
+      return new Directory.fromRawPath(_rawPath)
+          .delete(recursive: true)
+          .then((_) => this);
+    }
+    return _File._dispatchWithNamespace(
+        _IOService.fileDeleteLink, [null, _rawPath]).then((response) {
+      if (_isErrorResponse(response)) {
+        throw _exceptionFromResponse(response, "Cannot delete link", path);
+      }
+      return this;
+    });
+  }
+
+  void _deleteSync({bool recursive: false}) {
+    if (recursive) {
+      return new Directory.fromRawPath(_rawPath).deleteSync(recursive: true);
+    }
+    var result = _File._deleteLinkNative(_Namespace._namespace, _rawPath);
+    throwIfError(result, "Cannot delete link", path);
+  }
+
+  Future<Link> rename(String newPath) {
+    return _File._dispatchWithNamespace(
+        _IOService.fileRenameLink, [null, _rawPath, newPath]).then((response) {
+      if (_isErrorResponse(response)) {
+        throw _exceptionFromResponse(
+            response, "Cannot rename link to '$newPath'", path);
+      }
+      return new Link(newPath);
+    });
+  }
+
+  Link renameSync(String newPath) {
+    var result = _File._renameLink(_Namespace._namespace, _rawPath, newPath);
+    throwIfError(result, "Cannot rename link '$path' to '$newPath'");
+    return new Link(newPath);
+  }
+
+  Future<String> target() {
+    return _File._dispatchWithNamespace(
+        _IOService.fileLinkTarget, [null, _rawPath]).then((response) {
+      if (_isErrorResponse(response)) {
+        throw _exceptionFromResponse(
+            response, "Cannot get target of link", path);
+      }
+      return response;
+    });
+  }
+
+  String targetSync() {
+    var result = _File._linkTarget(_Namespace._namespace, _rawPath);
+    throwIfError(result, "Cannot read link", path);
+    return result;
+  }
+
+  static throwIfError(Object result, String msg, [String path = ""]) {
+    if (result is OSError) {
+      throw new FileSystemException(msg, path, result);
+    }
+  }
+
+  bool _isErrorResponse(response) {
+    return response is List && response[0] != _successResponse;
+  }
+
+  _exceptionFromResponse(response, String message, String path) {
+    assert(_isErrorResponse(response));
+    switch (response[_errorResponseErrorType]) {
+      case _illegalArgumentResponse:
+        return new ArgumentError();
+      case _osErrorResponse:
+        var err = new OSError(response[_osErrorResponseMessage],
+            response[_osErrorResponseErrorCode]);
+        return new FileSystemException(message, path, err);
+      default:
+        return new Exception("Unknown error");
+    }
+  }
+}
diff --git a/sdk_nnbd/lib/io/namespace_impl.dart b/sdk_nnbd/lib/io/namespace_impl.dart
new file mode 100644
index 0000000..88987b6
--- /dev/null
+++ b/sdk_nnbd/lib/io/namespace_impl.dart
@@ -0,0 +1,24 @@
+// 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.
+
+part of dart.io;
+
+// Each Isolate may run in a different "namespace", which provides the scope in
+// which file paths are resolved.
+abstract class _Namespace {
+  // This getter does not increase the reference count on the underlying native
+  // object. It cannot be passed in a dispatch message to the IOService thread.
+  external static _Namespace get _namespace;
+
+  // This getter does increase the reference count on the underlying native
+  // object. It must be passed in a dispatch message to the IOService thread.
+  external static int get _namespacePointer;
+
+  // This sets up the Isolate's namespace. It should be set up by the embedder.
+  // If it is not set up by the embedder, relative paths will be resolved
+  // relative to the process's current working directory and absolute paths will
+  // be left relative to the file system root.
+  @pragma("vm:entry-point")
+  external static void _setupNamespace(var namespace);
+}
diff --git a/sdk_nnbd/lib/io/overrides.dart b/sdk_nnbd/lib/io/overrides.dart
new file mode 100644
index 0000000..1a71881
--- /dev/null
+++ b/sdk_nnbd/lib/io/overrides.dart
@@ -0,0 +1,481 @@
+// 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.
+
+part of dart.io;
+
+final _ioOverridesToken = new Object();
+
+const _asyncRunZoned = runZoned;
+
+/// This class facilitates overriding various APIs of dart:io with mock
+/// implementations.
+///
+/// This abstract base class should be extended with overrides for the
+/// operations needed to construct mocks. The implementations in this base class
+/// default to the actual dart:io implementation. For example:
+///
+/// ```
+/// class MyDirectory implements Directory {
+///   ...
+///   // An implementation of the Directory interface
+///   ...
+/// }
+///
+/// main() {
+///   IOOverrides.runZoned(() {
+///     ...
+///     // Operations will use MyDirectory instead of dart:io's Directory
+///     // implementation whenever Directory is used.
+///     ...
+///   }, createDirectory: (String path) => new MyDirectory(path));
+/// }
+/// ```
+abstract class IOOverrides {
+  static IOOverrides _global;
+
+  static IOOverrides get current {
+    return Zone.current[_ioOverridesToken] ?? _global;
+  }
+
+  /// The [IOOverrides] to use in the root [Zone].
+  ///
+  /// These are the [IOOverrides] that will be used in the root Zone, and in
+  /// Zone's that do not set [IOOverrides] and whose ancestors up to the root
+  /// Zone do not set [IOOverrides].
+  static set global(IOOverrides overrides) {
+    _global = overrides;
+  }
+
+  /// Runs [body] in a fresh [Zone] using the provided overrides.
+  ///
+  /// See the documentation on the corresponding methods of IOOverrides for
+  /// information about what the optional arguments do.
+  static R runZoned<R>(R body(),
+      {
+      // Directory
+      Directory Function(String) createDirectory,
+      Directory Function() getCurrentDirectory,
+      void Function(String) setCurrentDirectory,
+      Directory Function() getSystemTempDirectory,
+
+      // File
+      File Function(String) createFile,
+
+      // FileStat
+      Future<FileStat> Function(String) stat,
+      FileStat Function(String) statSync,
+
+      // FileSystemEntity
+      Future<bool> Function(String, String) fseIdentical,
+      bool Function(String, String) fseIdenticalSync,
+      Future<FileSystemEntityType> Function(String, bool) fseGetType,
+      FileSystemEntityType Function(String, bool) fseGetTypeSync,
+
+      // _FileSystemWatcher
+      Stream<FileSystemEvent> Function(String, int, bool) fsWatch,
+      bool Function() fsWatchIsSupported,
+
+      // Link
+      Link Function(String) createLink,
+
+      // Socket
+      Future<Socket> Function(dynamic, int,
+              {dynamic sourceAddress, Duration timeout})
+          socketConnect,
+      Future<ConnectionTask<Socket>> Function(dynamic, int,
+              {dynamic sourceAddress})
+          socketStartConnect,
+
+      // Optional Zone parameters
+      ZoneSpecification zoneSpecification,
+      Function onError}) {
+    IOOverrides overrides = new _IOOverridesScope(
+      // Directory
+      createDirectory,
+      getCurrentDirectory,
+      setCurrentDirectory,
+      getSystemTempDirectory,
+
+      // File
+      createFile,
+
+      // FileStat
+      stat,
+      statSync,
+
+      // FileSystemEntity
+      fseIdentical,
+      fseIdenticalSync,
+      fseGetType,
+      fseGetTypeSync,
+
+      // _FileSystemWatcher
+      fsWatch,
+      fsWatchIsSupported,
+
+      // Link
+      createLink,
+
+      // Socket
+      socketConnect,
+      socketStartConnect,
+    );
+    return _asyncRunZoned<R>(body,
+        zoneValues: {_ioOverridesToken: overrides},
+        zoneSpecification: zoneSpecification,
+        onError: onError);
+  }
+
+  /// Runs [body] in a fresh [Zone] using the overrides found in [overrides].
+  ///
+  /// Note that [overrides] should be an instance of a class that extends
+  /// [IOOverrides].
+  static R runWithIOOverrides<R>(R body(), IOOverrides overrides,
+      {ZoneSpecification zoneSpecification, Function onError}) {
+    return _asyncRunZoned<R>(body,
+        zoneValues: {_ioOverridesToken: overrides},
+        zoneSpecification: zoneSpecification,
+        onError: onError);
+  }
+
+  // Directory
+
+  /// Creates a new [Directory] object for the given [path].
+  ///
+  /// When this override is installed, this function overrides the behavior of
+  /// `new Directory()` and `new Directory.fromUri()`.
+  Directory createDirectory(String path) => new _Directory(path);
+
+  /// Returns the current working directory.
+  ///
+  /// When this override is installed, this function overrides the behavior of
+  /// the static getter `Directory.current`
+  Directory getCurrentDirectory() => _Directory.current;
+
+  /// Sets the current working directory to be [path].
+  ///
+  /// When this override is installed, this function overrides the behavior of
+  /// the setter `Directory.current`.
+  void setCurrentDirectory(String path) {
+    _Directory.current = path;
+  }
+
+  /// Returns the system temporary directory.
+  ///
+  /// When this override is installed, this function overrides the behavior of
+  /// `Directory.systemTemp`.
+  Directory getSystemTempDirectory() => _Directory.systemTemp;
+
+  // File
+
+  /// Creates a new [File] object for the given [path].
+  ///
+  /// When this override is installed, this function overrides the behavior of
+  /// `new File()` and `new File.fromUri()`.
+  File createFile(String path) => new _File(path);
+
+  // FileStat
+
+  /// Asynchronously returns [FileStat] information for [path].
+  ///
+  /// When this override is installed, this function overrides the behavior of
+  /// `FileStat.stat()`.
+  Future<FileStat> stat(String path) {
+    return FileStat._stat(path);
+  }
+
+  /// Returns [FileStat] information for [path].
+  ///
+  /// When this override is installed, this function overrides the behavior of
+  /// `FileStat.statSync()`.
+  FileStat statSync(String path) {
+    return FileStat._statSyncInternal(path);
+  }
+
+  // FileSystemEntity
+
+  /// Asynchronously returns `true` if [path1] and [path2] are paths to the
+  /// same file system object.
+  ///
+  /// When this override is installed, this function overrides the behavior of
+  /// `FileSystemEntity.identical`.
+  Future<bool> fseIdentical(String path1, String path2) {
+    return FileSystemEntity._identical(path1, path2);
+  }
+
+  /// Returns `true` if [path1] and [path2] are paths to the
+  /// same file system object.
+  ///
+  /// When this override is installed, this function overrides the behavior of
+  /// `FileSystemEntity.identicalSync`.
+  bool fseIdenticalSync(String path1, String path2) {
+    return FileSystemEntity._identicalSync(path1, path2);
+  }
+
+  /// Asynchronously returns the [FileSystemEntityType] for [path].
+  ///
+  /// When this override is installed, this function overrides the behavior of
+  /// `FileSystemEntity.type`.
+  Future<FileSystemEntityType> fseGetType(String path, bool followLinks) {
+    return FileSystemEntity._getTypeRequest(utf8.encode(path), followLinks);
+  }
+
+  /// Returns the [FileSystemEntityType] for [path].
+  ///
+  /// When this override is installed, this function overrides the behavior of
+  /// `FileSystemEntity.typeSync`.
+  FileSystemEntityType fseGetTypeSync(String path, bool followLinks) {
+    return FileSystemEntity._getTypeSyncHelper(utf8.encode(path), followLinks);
+  }
+
+  // _FileSystemWatcher
+
+  /// Returns a [Stream] of [FileSystemEvent]s.
+  ///
+  /// When this override is installed, this function overrides the behavior of
+  /// `FileSystemEntity.watch()`.
+  Stream<FileSystemEvent> fsWatch(String path, int events, bool recursive) {
+    return _FileSystemWatcher._watch(path, events, recursive);
+  }
+
+  /// Returns `true` when [FileSystemEntity.watch] is supported.
+  ///
+  /// When this override is installed, this function overrides the behavior of
+  /// `FileSystemEntity.isWatchSupported`.
+  bool fsWatchIsSupported() => _FileSystemWatcher.isSupported;
+
+  // Link
+
+  /// Returns a new [Link] object for the given [path].
+  ///
+  /// When this override is installed, this function overrides the behavior of
+  /// `new Link()` and `new Link.fromUri()`.
+  Link createLink(String path) => new _Link(path);
+
+  // Socket
+
+  /// Asynchronously returns a [Socket] connected to the given host and port.
+  ///
+  /// When this override is installed, this functions overrides the behavior of
+  /// `Socket.connect(...)`.
+  Future<Socket> socketConnect(host, int port,
+      {sourceAddress, Duration timeout}) {
+    return Socket._connect(host, port,
+        sourceAddress: sourceAddress, timeout: timeout);
+  }
+
+  /// Asynchronously returns a [ConnectionTask] that connects to the given host
+  /// and port when successful.
+  ///
+  /// When this override is installed, this functions overrides the behavior of
+  /// `Socket.startConnect(...)`.
+  Future<ConnectionTask<Socket>> socketStartConnect(host, int port,
+      {sourceAddress}) {
+    return Socket._startConnect(host, port, sourceAddress: sourceAddress);
+  }
+}
+
+class _IOOverridesScope extends IOOverrides {
+  final IOOverrides _previous = IOOverrides.current;
+
+  // Directory
+  Directory Function(String) _createDirectory;
+  Directory Function() _getCurrentDirectory;
+  void Function(String) _setCurrentDirectory;
+  Directory Function() _getSystemTempDirectory;
+
+  // File
+  File Function(String) _createFile;
+
+  // FileStat
+  Future<FileStat> Function(String) _stat;
+  FileStat Function(String) _statSync;
+
+  // FileSystemEntity
+  Future<bool> Function(String, String) _fseIdentical;
+  bool Function(String, String) _fseIdenticalSync;
+  Future<FileSystemEntityType> Function(String, bool) _fseGetType;
+  FileSystemEntityType Function(String, bool) _fseGetTypeSync;
+
+  // _FileSystemWatcher
+  Stream<FileSystemEvent> Function(String, int, bool) _fsWatch;
+  bool Function() _fsWatchIsSupported;
+
+  // Link
+  Link Function(String) _createLink;
+
+  // Socket
+  Future<Socket> Function(dynamic, int,
+      {dynamic sourceAddress, Duration timeout}) _socketConnect;
+  Future<ConnectionTask<Socket>> Function(dynamic, int, {dynamic sourceAddress})
+      _socketStartConnect;
+
+  _IOOverridesScope(
+    // Directory
+    this._createDirectory,
+    this._getCurrentDirectory,
+    this._setCurrentDirectory,
+    this._getSystemTempDirectory,
+
+    // File
+    this._createFile,
+
+    // FileStat
+    this._stat,
+    this._statSync,
+
+    // FileSystemEntity
+    this._fseIdentical,
+    this._fseIdenticalSync,
+    this._fseGetType,
+    this._fseGetTypeSync,
+
+    // _FileSystemWatcher
+    this._fsWatch,
+    this._fsWatchIsSupported,
+
+    // Link
+    this._createLink,
+
+    // Socket
+    this._socketConnect,
+    this._socketStartConnect,
+  );
+
+  // Directory
+  @override
+  Directory createDirectory(String path) {
+    if (_createDirectory != null) return _createDirectory(path);
+    if (_previous != null) return _previous.createDirectory(path);
+    return super.createDirectory(path);
+  }
+
+  @override
+  Directory getCurrentDirectory() {
+    if (_getCurrentDirectory != null) return _getCurrentDirectory();
+    if (_previous != null) return _previous.getCurrentDirectory();
+    return super.getCurrentDirectory();
+  }
+
+  @override
+  void setCurrentDirectory(String path) {
+    if (_setCurrentDirectory != null)
+      _setCurrentDirectory(path);
+    else if (_previous != null)
+      _previous.setCurrentDirectory(path);
+    else
+      super.setCurrentDirectory(path);
+  }
+
+  @override
+  Directory getSystemTempDirectory() {
+    if (_getSystemTempDirectory != null) return _getSystemTempDirectory();
+    if (_previous != null) return _previous.getSystemTempDirectory();
+    return super.getSystemTempDirectory();
+  }
+
+  // File
+  @override
+  File createFile(String path) {
+    if (_createFile != null) return _createFile(path);
+    if (_previous != null) return _previous.createFile(path);
+    return super.createFile(path);
+  }
+
+  // FileStat
+  @override
+  Future<FileStat> stat(String path) {
+    if (_stat != null) return _stat(path);
+    if (_previous != null) return _previous.stat(path);
+    return super.stat(path);
+  }
+
+  @override
+  FileStat statSync(String path) {
+    if (_stat != null) return _statSync(path);
+    if (_previous != null) return _previous.statSync(path);
+    return super.statSync(path);
+  }
+
+  // FileSystemEntity
+  @override
+  Future<bool> fseIdentical(String path1, String path2) {
+    if (_fseIdentical != null) return _fseIdentical(path1, path2);
+    if (_previous != null) return _previous.fseIdentical(path1, path2);
+    return super.fseIdentical(path1, path2);
+  }
+
+  @override
+  bool fseIdenticalSync(String path1, String path2) {
+    if (_fseIdenticalSync != null) return _fseIdenticalSync(path1, path2);
+    if (_previous != null) return _previous.fseIdenticalSync(path1, path2);
+    return super.fseIdenticalSync(path1, path2);
+  }
+
+  @override
+  Future<FileSystemEntityType> fseGetType(String path, bool followLinks) {
+    if (_fseGetType != null) return _fseGetType(path, followLinks);
+    if (_previous != null) return _previous.fseGetType(path, followLinks);
+    return super.fseGetType(path, followLinks);
+  }
+
+  @override
+  FileSystemEntityType fseGetTypeSync(String path, bool followLinks) {
+    if (_fseGetTypeSync != null) return _fseGetTypeSync(path, followLinks);
+    if (_previous != null) return _previous.fseGetTypeSync(path, followLinks);
+    return super.fseGetTypeSync(path, followLinks);
+  }
+
+  // _FileSystemWatcher
+  @override
+  Stream<FileSystemEvent> fsWatch(String path, int events, bool recursive) {
+    if (_fsWatch != null) return _fsWatch(path, events, recursive);
+    if (_previous != null) return _previous.fsWatch(path, events, recursive);
+    return super.fsWatch(path, events, recursive);
+  }
+
+  @override
+  bool fsWatchIsSupported() {
+    if (_fsWatchIsSupported != null) return _fsWatchIsSupported();
+    if (_previous != null) return _previous.fsWatchIsSupported();
+    return super.fsWatchIsSupported();
+  }
+
+  // Link
+  @override
+  Link createLink(String path) {
+    if (_createLink != null) return _createLink(path);
+    if (_previous != null) return _previous.createLink(path);
+    return super.createLink(path);
+  }
+
+  // Socket
+  @override
+  Future<Socket> socketConnect(host, int port,
+      {sourceAddress, Duration timeout}) {
+    if (_socketConnect != null) {
+      return _socketConnect(host, port,
+          sourceAddress: sourceAddress, timeout: timeout);
+    }
+    if (_previous != null) {
+      return _previous.socketConnect(host, port,
+          sourceAddress: sourceAddress, timeout: timeout);
+    }
+    return super.socketConnect(host, port,
+        sourceAddress: sourceAddress, timeout: timeout);
+  }
+
+  @override
+  Future<ConnectionTask<Socket>> socketStartConnect(host, int port,
+      {sourceAddress}) {
+    if (_socketStartConnect != null) {
+      return _socketStartConnect(host, port, sourceAddress: sourceAddress);
+    }
+    if (_previous != null) {
+      return _previous.socketStartConnect(host, port,
+          sourceAddress: sourceAddress);
+    }
+    return super.socketStartConnect(host, port, sourceAddress: sourceAddress);
+  }
+}
diff --git a/sdk_nnbd/lib/io/platform.dart b/sdk_nnbd/lib/io/platform.dart
new file mode 100644
index 0000000..f7c9053
--- /dev/null
+++ b/sdk_nnbd/lib/io/platform.dart
@@ -0,0 +1,232 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.io;
+
+/**
+ * Information about the environment in which the current program is running.
+ *
+ * Platform provides information such as the operating system,
+ * the hostname of the computer, the value of environment variables,
+ * the path to the running program,
+ * and so on.
+ *
+ * ## Get the URI to the current Dart script
+ *
+ * Use the [script] getter to get the URI to the currently running
+ * Dart script.
+ *
+ *     import 'dart:io' show Platform;
+ *
+ *     void main() {
+ *       // Get the URI of the script being run.
+ *       var uri = Platform.script;
+ *       // Convert the URI to a path.
+ *       var path = uri.toFilePath();
+ *     }
+ *
+ * ## Get the value of an environment variable
+ *
+ * The [environment] getter returns a the names and values of environment
+ * variables in a [Map] that contains key-value pairs of strings. The Map is
+ * unmodifiable. This sample shows how to get the value of the `PATH`
+ * environment variable.
+ *
+ *     import 'dart:io' show Platform;
+ *
+ *     void main() {
+ *       Map<String, String> envVars = Platform.environment;
+ *       print(envVars['PATH']);
+ *     }
+ *
+ * ## Determine the OS
+ *
+ * You can get the name of the operating system as a string with the
+ * [operatingSystem] getter. You can also use one of the static boolean
+ * getters: [isMacOS], [isLinux], and [isWindows].
+ *
+ *     import 'dart:io' show Platform, stdout;
+ *
+ *     void main() {
+ *       // Get the operating system as a string.
+ *       String os = Platform.operatingSystem;
+ *       // Or, use a predicate getter.
+ *       if (Platform.isMacOS) {
+ *         print('is a Mac');
+ *       } else {
+ *         print('is not a Mac');
+ *       }
+ *     }
+ *
+ * ## Other resources
+ *
+ * [Dart by Example](https://www.dartlang.org/dart-by-example/#dart-io-and-command-line-apps)
+ * provides additional task-oriented code samples that show how to use
+ * various API from the [dart:io] library.
+ */
+class Platform {
+  static final _numberOfProcessors = _Platform.numberOfProcessors;
+  static final _pathSeparator = _Platform.pathSeparator;
+  static final _operatingSystem = _Platform.operatingSystem;
+  static final _operatingSystemVersion = _Platform.operatingSystemVersion;
+  static final _localHostname = _Platform.localHostname;
+  static final _version = _Platform.version;
+
+  /**
+   * The number of individual execution units of the machine.
+   */
+  static int get numberOfProcessors => _numberOfProcessors;
+
+  /**
+   * The path separator used by the operating system to separate
+   * components in file paths.
+   */
+  static String get pathSeparator => _pathSeparator;
+
+  /**
+   * Get the name of the current locale.
+   */
+  static String get localeName => _Platform.localeName();
+
+  /**
+   * A string representing the operating system or platform.
+   */
+  static String get operatingSystem => _operatingSystem;
+
+  /**
+   * A string representing the version of the operating system or platform.
+   */
+  static String get operatingSystemVersion => _operatingSystemVersion;
+
+  /**
+   * The local hostname for the system.
+   */
+  static String get localHostname => _localHostname;
+
+  /**
+   * Whether the operating system is a version of
+   * [Linux](https://en.wikipedia.org/wiki/Linux).
+   *
+   * This value is `false` if the operating system is a specialized
+   * version of Linux that identifies itself by a different name,
+   * for example Android (see [isAndroid]).
+   */
+  static final bool isLinux = (_operatingSystem == "linux");
+
+  /**
+   * Whether the operating system is a version of
+   * [macOS](https://en.wikipedia.org/wiki/MacOS).
+   */
+  static final bool isMacOS = (_operatingSystem == "macos");
+
+  /**
+   * Whether the operating system is a version of
+   * [Microsoft Windows](https://en.wikipedia.org/wiki/Microsoft_Windows).
+   */
+  static final bool isWindows = (_operatingSystem == "windows");
+
+  /**
+   * Whether the operating system is a version of
+   * [Android](https://en.wikipedia.org/wiki/Android_%28operating_system%29).
+   */
+  static final bool isAndroid = (_operatingSystem == "android");
+
+  /**
+   * Whether the operating system is a version of
+   * [iOS](https://en.wikipedia.org/wiki/IOS).
+   */
+  static final bool isIOS = (_operatingSystem == "ios");
+
+  /**
+   * Whether the operating system is a version of
+   * [Fuchsia](https://en.wikipedia.org/wiki/Google_Fuchsia).
+   */
+  static final bool isFuchsia = (_operatingSystem == "fuchsia");
+
+  /**
+   * The environment for this process as a map from string key to string value.
+   *
+   * The map is unmodifiable,
+   * and its content is retrieved from the operating system on its first use.
+   *
+   * Environment variables on Windows are case-insensitive,
+   * so on Windows the map is case-insensitive and will convert
+   * all keys to upper case.
+   * On other platforms, keys can be distinguished by case.
+   */
+  static Map<String, String> get environment => _Platform.environment;
+
+  /**
+   * The path of the executable used to run the script in this isolate.
+   *
+   * The literal path used to identify the script.
+   * This path might be relative or just be a name from which the executable
+   * was found by searching the system path.
+   *
+   * Use [resolvedExecutable] to get an absolute path to the executable.
+   */
+  static String get executable => _Platform.executable;
+
+  /**
+   * The path of the executable used to run the script in this
+   * isolate after it has been resolved by the OS.
+   *
+   * This is the absolute path, with all symlinks resolved, to the
+   * executable used to run the script.
+   */
+  static String get resolvedExecutable => _Platform.resolvedExecutable;
+
+  /**
+   * The absolute URI of the script being run in this isolate.
+   *
+   * If the script argument on the command line is relative,
+   * it is resolved to an absolute URI before fetching the script, and
+   * that absolute URI is returned.
+   *
+   * URI resolution only does string manipulation on the script path, and this
+   * may be different from the file system's path resolution behavior. For
+   * example, a symbolic link immediately followed by '..' will not be
+   * looked up.
+   *
+   * If the executable environment does not support [script],
+   * the URI is empty.
+   */
+  static Uri get script => _Platform.script;
+
+  /**
+   * The flags passed to the executable used to run the script in this isolate.
+   *
+   * These are the command-line flags to the executable that precedes
+   * the script name.
+   * Provides a new list every time the value is read.
+   */
+  static List<String> get executableArguments => _Platform.executableArguments;
+
+  /**
+   * This returns `null`, as `packages/` directories are no longer supported.
+   *
+   */
+  @Deprecated('packages/ directory resolution is not supported in Dart 2')
+  static String get packageRoot => null; // TODO(mfairhurst): remove this
+
+  /**
+   * The `--packages` flag passed to the executable used to run the script
+   * in this isolate.
+   *
+   * If present, it specifies a file describing how Dart packages are looked up.
+   *
+   * Is `null` if there is no `--packages` flag.
+   */
+  static String get packageConfig => _Platform.packageConfig;
+
+  /**
+   * The version of the current Dart runtime.
+   *
+   * The value is a [semantic versioning](http://semver.org)
+   * string representing the version of the current Dart runtime,
+   * possibly followed by whitespace and other version and
+   * build details.
+   */
+  static String get version => _version;
+}
diff --git a/sdk_nnbd/lib/io/platform_impl.dart b/sdk_nnbd/lib/io/platform_impl.dart
new file mode 100644
index 0000000..a350119
--- /dev/null
+++ b/sdk_nnbd/lib/io/platform_impl.dart
@@ -0,0 +1,178 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.io;
+
+class _Platform {
+  external static int _numberOfProcessors();
+  external static String _pathSeparator();
+  external static String _operatingSystem();
+  external static _operatingSystemVersion();
+  external static _localHostname();
+  external static _executable();
+  external static _resolvedExecutable();
+
+  /**
+   * Retrieve the entries of the process environment.
+   *
+   * The result is an [Iterable] of strings, where each string represents
+   * an environment entry.
+   *
+   * Environment entries should be strings containing
+   * a non-empty name and a value separated by a '=' character.
+   * The name does not contain a '=' character,
+   * so the name is everything up to the first '=' character.
+   * Values are everything after the first '=' character.
+   * A value may contain further '=' characters, and it may be empty.
+   *
+   * Returns an [OSError] if retrieving the environment fails.
+   */
+  external static _environment();
+  external static List<String> _executableArguments();
+  external static String _packageRoot(); // TODO(mfairhurst): remove this
+  external static String _packageConfig();
+  external static String _version();
+  external static String _localeName();
+  external static Uri _script();
+
+  static String executable = _executable();
+  static String resolvedExecutable = _resolvedExecutable();
+  static String packageRoot; // TODO(mfairhurst): remove this
+  static String packageConfig = _packageConfig();
+
+  @pragma("vm:entry-point")
+  static String Function() _localeClosure;
+  static String localeName() {
+    final result = (_localeClosure == null) ? _localeName() : _localeClosure();
+    if (result is OSError) {
+      throw result;
+    }
+    return result;
+  }
+
+  // Cache the OS environment. This can be an OSError instance if
+  // retrieving the environment failed.
+  static var /*OSError|Map<String,String>*/ _environmentCache;
+
+  static int get numberOfProcessors => _numberOfProcessors();
+  static String get pathSeparator => _pathSeparator();
+  static String get operatingSystem => _operatingSystem();
+  static Uri get script => _script();
+
+  static String _cachedOSVersion;
+  static String get operatingSystemVersion {
+    if (_cachedOSVersion == null) {
+      var result = _operatingSystemVersion();
+      if (result is OSError) {
+        throw result;
+      }
+      _cachedOSVersion = result;
+    }
+    return _cachedOSVersion;
+  }
+
+  static String get localHostname {
+    var result = _localHostname();
+    if (result is OSError) {
+      throw result;
+    }
+    return result;
+  }
+
+  static List<String> get executableArguments => _executableArguments();
+
+  static Map<String, String> get environment {
+    if (_environmentCache == null) {
+      var env = _environment();
+      if (env is! OSError) {
+        var isWindows = operatingSystem == 'windows';
+        var result = isWindows
+            ? new _CaseInsensitiveStringMap<String>()
+            : new Map<String, String>();
+        for (var str in env) {
+          if (str == null) {
+            continue;
+          }
+          // The Strings returned by [_environment()] are expected to be
+          // valid environment entries, but exceptions have been seen
+          // (e.g., an entry of just '=' has been seen on OS/X).
+          // Invalid entries (lines without a '=' or with an empty name)
+          // are discarded.
+          var equalsIndex = str.indexOf('=');
+          if (equalsIndex > 0) {
+            result[str.substring(0, equalsIndex)] =
+                str.substring(equalsIndex + 1);
+          }
+        }
+        _environmentCache = new UnmodifiableMapView<String, String>(result);
+      } else {
+        _environmentCache = env;
+      }
+    }
+
+    if (_environmentCache is OSError) {
+      throw _environmentCache;
+    } else {
+      return _environmentCache;
+    }
+  }
+
+  static String get version => _version();
+}
+
+// Environment variables are case-insensitive on Windows. In order
+// to reflect that we use a case-insensitive string map on Windows.
+class _CaseInsensitiveStringMap<V> extends MapBase<String, V> {
+  final Map<String, V> _map = new Map<String, V>();
+
+  bool containsKey(Object key) =>
+      key is String && _map.containsKey(key.toUpperCase());
+  bool containsValue(Object value) => _map.containsValue(value);
+  V operator [](Object key) => key is String ? _map[key.toUpperCase()] : null;
+  void operator []=(String key, V value) {
+    _map[key.toUpperCase()] = value;
+  }
+
+  V putIfAbsent(String key, V ifAbsent()) {
+    return _map.putIfAbsent(key.toUpperCase(), ifAbsent);
+  }
+
+  void addAll(Map<String, V> other) {
+    other.forEach((key, value) => this[key.toUpperCase()] = value);
+  }
+
+  V remove(Object key) => key is String ? _map.remove(key.toUpperCase()) : null;
+
+  void clear() {
+    _map.clear();
+  }
+
+  void forEach(void f(String key, V value)) {
+    _map.forEach(f);
+  }
+
+  Iterable<String> get keys => _map.keys;
+  Iterable<V> get values => _map.values;
+  int get length => _map.length;
+  bool get isEmpty => _map.isEmpty;
+  bool get isNotEmpty => _map.isNotEmpty;
+
+  Iterable<MapEntry<String, V>> get entries => _map.entries;
+
+  Map<K2, V2> map<K2, V2>(MapEntry<K2, V2> transform(String key, V value)) =>
+      _map.map(transform);
+
+  V update(String key, V update(V value), {V ifAbsent()}) =>
+      _map.update(key.toUpperCase(), update, ifAbsent: ifAbsent);
+
+  void updateAll(V update(String key, V value)) {
+    _map.updateAll(update);
+  }
+
+  void removeWhere(bool test(String key, V value)) {
+    _map.removeWhere(test);
+  }
+
+  String toString() => _map.toString();
+}
diff --git a/sdk_nnbd/lib/io/process.dart b/sdk_nnbd/lib/io/process.dart
new file mode 100644
index 0000000..4cf78b9
--- /dev/null
+++ b/sdk_nnbd/lib/io/process.dart
@@ -0,0 +1,700 @@
+// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.io;
+
+// TODO(ager): The only reason for this class is that we
+// cannot patch a top-level at this point.
+class _ProcessUtils {
+  external static void _exit(int status);
+  external static void _setExitCode(int status);
+  external static int _getExitCode();
+  external static void _sleep(int millis);
+  external static int _pid(Process process);
+  external static Stream<ProcessSignal> _watchSignal(ProcessSignal signal);
+}
+
+/**
+ * Exit the Dart VM process immediately with the given exit code.
+ *
+ * This does not wait for any asynchronous operations to terminate. Using
+ * [exit] is therefore very likely to lose data.
+ *
+ * While debugging, the VM will not respect the `--pause-isolates-on-exit`
+ * flag if [exit] is called as invoking this method causes the Dart VM
+ * process to shutdown immediately. To properly break on exit, consider
+ * calling [debugger] from `dart:developer` or [Isolate.pause] from
+ * `dart:isolate` on [Isolate.current] to pause the isolate before
+ * invoking [exit].
+ *
+ * The handling of exit codes is platform specific.
+ *
+ * On Linux and OS X an exit code for normal termination will always
+ * be in the range [0..255]. If an exit code outside this range is
+ * set the actual exit code will be the lower 8 bits masked off and
+ * treated as an unsigned value. E.g. using an exit code of -1 will
+ * result in an actual exit code of 255 being reported.
+ *
+ * On Windows the exit code can be set to any 32-bit value. However
+ * some of these values are reserved for reporting system errors like
+ * crashes.
+ *
+ * Besides this the Dart executable itself uses an exit code of `254`
+ * for reporting compile time errors and an exit code of `255` for
+ * reporting runtime error (unhandled exception).
+ *
+ * Due to these facts it is recommended to only use exit codes in the
+ * range [0..127] for communicating the result of running a Dart
+ * program to the surrounding environment. This will avoid any
+ * cross-platform issues.
+ */
+void exit(int code) {
+  ArgumentError.checkNotNull(code, "code");
+  if (!_EmbedderConfig._mayExit) {
+    throw new UnsupportedError(
+        "This embedder disallows calling dart:io's exit()");
+  }
+  _ProcessUtils._exit(code);
+}
+
+/**
+ * Set the global exit code for the Dart VM.
+ *
+ * The exit code is global for the Dart VM and the last assignment to
+ * exitCode from any isolate determines the exit code of the Dart VM
+ * on normal termination.
+ *
+ * Default value is `0`.
+ *
+ * See [exit] for more information on how to chose a value for the
+ * exit code.
+ */
+void set exitCode(int code) {
+  ArgumentError.checkNotNull(code, "code");
+  _ProcessUtils._setExitCode(code);
+}
+
+/**
+ * Get the global exit code for the Dart VM.
+ *
+ * The exit code is global for the Dart VM and the last assignment to
+ * exitCode from any isolate determines the exit code of the Dart VM
+ * on normal termination.
+ *
+ * See [exit] for more information on how to chose a value for the
+ * exit code.
+ */
+int get exitCode => _ProcessUtils._getExitCode();
+
+/**
+ * Sleep for the duration specified in [duration].
+ *
+ * Use this with care, as no asynchronous operations can be processed
+ * in a isolate while it is blocked in a [sleep] call.
+ */
+void sleep(Duration duration) {
+  int milliseconds = duration.inMilliseconds;
+  if (milliseconds < 0) {
+    throw new ArgumentError("sleep: duration cannot be negative");
+  }
+  if (!_EmbedderConfig._maySleep) {
+    throw new UnsupportedError(
+        "This embedder disallows calling dart:io's sleep()");
+  }
+  _ProcessUtils._sleep(milliseconds);
+}
+
+/**
+ * Returns the PID of the current process.
+ */
+int get pid => _ProcessUtils._pid(null);
+
+/**
+ * [ProcessInfo] provides methods for retrieving information about the
+ * current process.
+ */
+class ProcessInfo {
+  /**
+   * The current resident set size of memory for the process.
+   *
+   * Note that the meaning of this field is platform dependent. For example,
+   * some memory accounted for here may be shared with other processes, or if
+   * the same page is mapped into a process's address space, it may be counted
+   * twice.
+   */
+  external static int get currentRss;
+
+  /**
+   * The high-watermark in bytes for the resident set size of memory for the
+   * process.
+   *
+   * Note that the meaning of this field is platform dependent. For example,
+   * some memory accounted for here may be shared with other processes, or if
+   * the same page is mapped into a process's address space, it may be counted
+   * twice.
+   */
+  external static int get maxRss;
+}
+
+/**
+ * Modes for running a new process.
+ */
+class ProcessStartMode {
+  /// Normal child process.
+  static const normal = const ProcessStartMode._internal(0);
+  @Deprecated("Use normal instead")
+  static const NORMAL = normal;
+
+  /// Stdio handles are inherited by the child process.
+  static const inheritStdio = const ProcessStartMode._internal(1);
+  @Deprecated("Use inheritStdio instead")
+  static const INHERIT_STDIO = inheritStdio;
+
+  /// Detached child process with no open communication channel.
+  static const detached = const ProcessStartMode._internal(2);
+  @Deprecated("Use detached instead")
+  static const DETACHED = detached;
+
+  /// Detached child process with stdin, stdout and stderr still open
+  /// for communication with the child.
+  static const detachedWithStdio = const ProcessStartMode._internal(3);
+  @Deprecated("Use detachedWithStdio instead")
+  static const DETACHED_WITH_STDIO = detachedWithStdio;
+
+  static List<ProcessStartMode> get values => const <ProcessStartMode>[
+        normal,
+        inheritStdio,
+        detached,
+        detachedWithStdio
+      ];
+  String toString() =>
+      const ["normal", "inheritStdio", "detached", "detachedWithStdio"][_mode];
+
+  final int _mode;
+  const ProcessStartMode._internal(this._mode);
+}
+
+/**
+ * The means to execute a program.
+ *
+ * Use the static [start] and [run] methods to start a new process.
+ * The run method executes the process non-interactively to completion.
+ * In contrast, the start method allows your code to interact with the
+ * running process.
+ *
+ * ## Start a process with the run method
+ *
+ * The following code sample uses the run method to create a process
+ * that runs the UNIX command `ls`, which lists the contents of a directory.
+ * The run method completes with a [ProcessResult] object when the process
+ * terminates. This provides access to the output and exit code from the
+ * process. The run method does not return a Process object; this prevents your
+ * code from interacting with the running process.
+ *
+ *     import 'dart:io';
+ *
+ *     main() {
+ *       // List all files in the current directory in UNIX-like systems.
+ *       Process.run('ls', ['-l']).then((ProcessResult results) {
+ *         print(results.stdout);
+ *       });
+ *     }
+ *
+ * ## Start a process with the start method
+ *
+ * The following example uses start to create the process.
+ * The start method returns a [Future] for a Process object.
+ * When the future completes the process is started and
+ * your code can interact with the
+ * Process: writing to stdin, listening to stdout, and so on.
+ *
+ * The following sample starts the UNIX `cat` utility, which when given no
+ * command-line arguments, echos its input.
+ * The program writes to the process's standard input stream
+ * and prints data from its standard output stream.
+ *
+ *     import 'dart:io';
+ *     import 'dart:convert';
+ *
+ *     main() {
+ *       Process.start('cat', []).then((Process process) {
+ *         process.stdout
+ *             .transform(utf8.decoder)
+ *             .listen((data) { print(data); });
+ *         process.stdin.writeln('Hello, world!');
+ *         process.stdin.writeln('Hello, galaxy!');
+ *         process.stdin.writeln('Hello, universe!');
+ *       });
+ *     }
+ *
+ * ## Standard I/O streams
+ *
+ * As seen in the previous code sample, you can interact with the Process's
+ * standard output stream through the getter [stdout],
+ * and you can interact with the Process's standard input stream through
+ * the getter [stdin].
+ * In addition, Process provides a getter [stderr] for using the Process's
+ * standard error stream.
+ *
+ * A Process's streams are distinct from the top-level streams
+ * for the current program.
+ *
+ * ## Exit codes
+ *
+ * Call the [exitCode] method to get the exit code of the process.
+ * The exit code indicates whether the program terminated successfully
+ * (usually indicated with an exit code of 0) or with an error.
+ *
+ * If the start method is used, the exitCode is available through a future
+ * on the Process object (as shown in the example below).
+ * If the run method is used, the exitCode is available
+ * through a getter on the ProcessResult instance.
+ *
+ *     import 'dart:io';
+ *
+ *     main() {
+ *       Process.start('ls', ['-l']).then((process) {
+ *         // Get the exit code from the new process.
+ *         process.exitCode.then((exitCode) {
+ *           print('exit code: $exitCode');
+ *         });
+ *       });
+ *     }
+ *
+ * ## Other resources
+ *
+ * [Dart by Example](https://www.dartlang.org/dart-by-example/#dart-io-and-command-line-apps)
+ * provides additional task-oriented code samples that show how to use
+ * various API from the [dart:io] library.
+ */
+abstract class Process {
+  /**
+   * Returns a [:Future:] which completes with the exit code of the process
+   * when the process completes.
+   *
+   * The handling of exit codes is platform specific.
+   *
+   * On Linux and OS X a normal exit code will be a positive value in
+   * the range [0..255]. If the process was terminated due to a signal
+   * the exit code will be a negative value in the range [-255..-1],
+   * where the absolute value of the exit code is the signal
+   * number. For example, if a process crashes due to a segmentation
+   * violation the exit code will be -11, as the signal SIGSEGV has the
+   * number 11.
+   *
+   * On Windows a process can report any 32-bit value as an exit
+   * code. When returning the exit code this exit code is turned into
+   * a signed value. Some special values are used to report
+   * termination due to some system event. E.g. if a process crashes
+   * due to an access violation the 32-bit exit code is `0xc0000005`,
+   * which will be returned as the negative number `-1073741819`. To
+   * get the original 32-bit value use `(0x100000000 + exitCode) &
+   * 0xffffffff`.
+   *
+   * There is no guarantee that [stdout] and [stderr] have finished reporting
+   * the buffered output of the process when the returned future completes.
+   * To be sure that all output is captured,
+   * wait for the done event on the streams.
+   */
+  Future<int> get exitCode;
+
+  /**
+   * Starts a process running the [executable] with the specified
+   * [arguments]. Returns a [:Future<Process>:] that completes with a
+   * Process instance when the process has been successfully
+   * started. That [Process] object can be used to interact with the
+   * process. If the process cannot be started the returned [Future]
+   * completes with an exception.
+   *
+   * Use [workingDirectory] to set the working directory for the process. Note
+   * that the change of directory occurs before executing the process on some
+   * platforms, which may have impact when using relative paths for the
+   * executable and the arguments.
+   *
+   * Use [environment] to set the environment variables for the process. If not
+   * set the environment of the parent process is inherited. Currently, only
+   * US-ASCII environment variables are supported and errors are likely to occur
+   * if an environment variable with code-points outside the US-ASCII range is
+   * passed in.
+   *
+   * If [includeParentEnvironment] is `true`, the process's environment will
+   * include the parent process's environment, with [environment] taking
+   * precedence. Default is `true`.
+   *
+   * If [runInShell] is `true`, the process will be spawned through a system
+   * shell. On Linux and OS X, [:/bin/sh:] is used, while
+   * [:%WINDIR%\system32\cmd.exe:] is used on Windows.
+   *
+   * Users must read all data coming on the [stdout] and [stderr]
+   * streams of processes started with [:Process.start:]. If the user
+   * does not read all data on the streams the underlying system
+   * resources will not be released since there is still pending data.
+   *
+   * The following code uses `Process.start` to grep for `main` in the
+   * file `test.dart` on Linux.
+   *
+   *     Process.start('grep', ['-i', 'main', 'test.dart']).then((process) {
+   *       stdout.addStream(process.stdout);
+   *       stderr.addStream(process.stderr);
+   *     });
+   *
+   * If [mode] is [ProcessStartMode.normal] (the default) a child
+   * process will be started with `stdin`, `stdout` and `stderr`
+   * connected.
+   *
+   * If `mode` is [ProcessStartMode.detached] a detached process will
+   * be created. A detached process has no connection to its parent,
+   * and can keep running on its own when the parent dies. The only
+   * information available from a detached process is its `pid`. There
+   * is no connection to its `stdin`, `stdout` or `stderr`, nor will
+   * the process' exit code become available when it terminates.
+   *
+   * If `mode` is [ProcessStartMode.detachedWithStdio] a detached
+   * process will be created where the `stdin`, `stdout` and `stderr`
+   * are connected. The creator can communicate with the child through
+   * these. The detached process will keep running even if these
+   * communication channels are closed. The process' exit code will
+   * not become available when it terminated.
+   *
+   * The default value for `mode` is `ProcessStartMode.normal`.
+   */
+  external static Future<Process> start(
+      String executable, List<String> arguments,
+      {String workingDirectory,
+      Map<String, String> environment,
+      bool includeParentEnvironment: true,
+      bool runInShell: false,
+      ProcessStartMode mode: ProcessStartMode.normal});
+
+  /**
+   * Starts a process and runs it non-interactively to completion. The
+   * process run is [executable] with the specified [arguments].
+   *
+   * Use [workingDirectory] to set the working directory for the process. Note
+   * that the change of directory occurs before executing the process on some
+   * platforms, which may have impact when using relative paths for the
+   * executable and the arguments.
+   *
+   * Use [environment] to set the environment variables for the process. If not
+   * set the environment of the parent process is inherited. Currently, only
+   * US-ASCII environment variables are supported and errors are likely to occur
+   * if an environment variable with code-points outside the US-ASCII range is
+   * passed in.
+   *
+   * If [includeParentEnvironment] is `true`, the process's environment will
+   * include the parent process's environment, with [environment] taking
+   * precedence. Default is `true`.
+   *
+   * If [runInShell] is true, the process will be spawned through a system
+   * shell. On Linux and OS X, `/bin/sh` is used, while
+   * `%WINDIR%\system32\cmd.exe` is used on Windows.
+   *
+   * The encoding used for decoding `stdout` and `stderr` into text is
+   * controlled through [stdoutEncoding] and [stderrEncoding]. The
+   * default encoding is [systemEncoding]. If `null` is used no
+   * decoding will happen and the [ProcessResult] will hold binary
+   * data.
+   *
+   * Returns a `Future<ProcessResult>` that completes with the
+   * result of running the process, i.e., exit code, standard out and
+   * standard in.
+   *
+   * The following code uses `Process.run` to grep for `main` in the
+   * file `test.dart` on Linux.
+   *
+   *     Process.run('grep', ['-i', 'main', 'test.dart']).then((result) {
+   *       stdout.write(result.stdout);
+   *       stderr.write(result.stderr);
+   *     });
+   */
+  external static Future<ProcessResult> run(
+      String executable, List<String> arguments,
+      {String workingDirectory,
+      Map<String, String> environment,
+      bool includeParentEnvironment: true,
+      bool runInShell: false,
+      Encoding stdoutEncoding: systemEncoding,
+      Encoding stderrEncoding: systemEncoding});
+
+  /**
+   * Starts a process and runs it to completion. This is a synchronous
+   * call and will block until the child process terminates.
+   *
+   * The arguments are the same as for `Process.run`.
+   *
+   * Returns a `ProcessResult` with the result of running the process,
+   * i.e., exit code, standard out and standard in.
+   */
+  external static ProcessResult runSync(
+      String executable, List<String> arguments,
+      {String workingDirectory,
+      Map<String, String> environment,
+      bool includeParentEnvironment: true,
+      bool runInShell: false,
+      Encoding stdoutEncoding: systemEncoding,
+      Encoding stderrEncoding: systemEncoding});
+
+  /**
+   * Kills the process with id [pid].
+   *
+   * Where possible, sends the [signal] to the process with id
+   * `pid`. This includes Linux and OS X. The default signal is
+   * [ProcessSignal.sigterm] which will normally terminate the
+   * process.
+   *
+   * On platforms without signal support, including Windows, the call
+   * just terminates the process with id `pid` in a platform specific
+   * way, and the `signal` parameter is ignored.
+   *
+   * Returns `true` if the signal is successfully delivered to the
+   * process. Otherwise the signal could not be sent, usually meaning
+   * that the process is already dead.
+   */
+  external static bool killPid(int pid,
+      [ProcessSignal signal = ProcessSignal.sigterm]);
+
+  /**
+   * Returns the standard output stream of the process as a [:Stream:].
+   */
+  Stream<List<int>> get stdout;
+
+  /**
+   * Returns the standard error stream of the process as a [:Stream:].
+   */
+  Stream<List<int>> get stderr;
+
+  /**
+   * Returns the standard input stream of the process as an [IOSink].
+   */
+  IOSink get stdin;
+
+  /**
+   * Returns the process id of the process.
+   */
+  int get pid;
+
+  /**
+   * Kills the process.
+   *
+   * Where possible, sends the [signal] to the process. This includes
+   * Linux and OS X. The default signal is [ProcessSignal.sigterm]
+   * which will normally terminate the process.
+   *
+   * On platforms without signal support, including Windows, the call
+   * just terminates the process in a platform specific way, and the
+   * `signal` parameter is ignored.
+   *
+   * Returns `true` if the signal is successfully delivered to the
+   * process. Otherwise the signal could not be sent, usually meaning
+   * that the process is already dead.
+   */
+  bool kill([ProcessSignal signal = ProcessSignal.sigterm]);
+}
+
+/**
+ * [ProcessResult] represents the result of running a non-interactive
+ * process started with [Process.run] or [Process.runSync].
+ */
+class ProcessResult {
+  /**
+   * Exit code for the process.
+   *
+   * See [Process.exitCode] for more information in the exit code
+   * value.
+   */
+  final int exitCode;
+
+  /**
+   * Standard output from the process. The value used for the
+   * `stdoutEncoding` argument to `Process.run` determines the type. If
+   * `null` was used this value is of type `List<int>` otherwise it is
+   * of type `String`.
+   */
+  final stdout;
+
+  /**
+   * Standard error from the process. The value used for the
+   * `stderrEncoding` argument to `Process.run` determines the type. If
+   * `null` was used this value is of type `List<int>`
+   * otherwise it is of type `String`.
+   */
+  final stderr;
+
+  /**
+   * Process id of the process.
+   */
+  final int pid;
+
+  ProcessResult(this.pid, this.exitCode, this.stdout, this.stderr);
+}
+
+/**
+ * On Posix systems, [ProcessSignal] is used to send a specific signal
+ * to a child process, see [:Process.kill:].
+ *
+ * Some [ProcessSignal]s can also be watched, as a way to intercept the default
+ * signal handler and implement another. See [ProcessSignal.watch] for more
+ * information.
+ */
+class ProcessSignal {
+  static const ProcessSignal sighup = const ProcessSignal._(1, "SIGHUP");
+  static const ProcessSignal sigint = const ProcessSignal._(2, "SIGINT");
+  static const ProcessSignal sigquit = const ProcessSignal._(3, "SIGQUIT");
+  static const ProcessSignal sigill = const ProcessSignal._(4, "SIGILL");
+  static const ProcessSignal sigtrap = const ProcessSignal._(5, "SIGTRAP");
+  static const ProcessSignal sigabrt = const ProcessSignal._(6, "SIGABRT");
+  static const ProcessSignal sigbus = const ProcessSignal._(7, "SIGBUS");
+  static const ProcessSignal sigfpe = const ProcessSignal._(8, "SIGFPE");
+  static const ProcessSignal sigkill = const ProcessSignal._(9, "SIGKILL");
+  static const ProcessSignal sigusr1 = const ProcessSignal._(10, "SIGUSR1");
+  static const ProcessSignal sigsegv = const ProcessSignal._(11, "SIGSEGV");
+  static const ProcessSignal sigusr2 = const ProcessSignal._(12, "SIGUSR2");
+  static const ProcessSignal sigpipe = const ProcessSignal._(13, "SIGPIPE");
+  static const ProcessSignal sigalrm = const ProcessSignal._(14, "SIGALRM");
+  static const ProcessSignal sigterm = const ProcessSignal._(15, "SIGTERM");
+  static const ProcessSignal sigchld = const ProcessSignal._(17, "SIGCHLD");
+  static const ProcessSignal sigcont = const ProcessSignal._(18, "SIGCONT");
+  static const ProcessSignal sigstop = const ProcessSignal._(19, "SIGSTOP");
+  static const ProcessSignal sigtstp = const ProcessSignal._(20, "SIGTSTP");
+  static const ProcessSignal sigttin = const ProcessSignal._(21, "SIGTTIN");
+  static const ProcessSignal sigttou = const ProcessSignal._(22, "SIGTTOU");
+  static const ProcessSignal sigurg = const ProcessSignal._(23, "SIGURG");
+  static const ProcessSignal sigxcpu = const ProcessSignal._(24, "SIGXCPU");
+  static const ProcessSignal sigxfsz = const ProcessSignal._(25, "SIGXFSZ");
+  static const ProcessSignal sigvtalrm = const ProcessSignal._(26, "SIGVTALRM");
+  static const ProcessSignal sigprof = const ProcessSignal._(27, "SIGPROF");
+  static const ProcessSignal sigwinch = const ProcessSignal._(28, "SIGWINCH");
+  static const ProcessSignal sigpoll = const ProcessSignal._(29, "SIGPOLL");
+  static const ProcessSignal sigsys = const ProcessSignal._(31, "SIGSYS");
+
+  @Deprecated("Use sighup instead")
+  static const ProcessSignal SIGHUP = sighup;
+  @Deprecated("Use sigint instead")
+  static const ProcessSignal SIGINT = sigint;
+  @Deprecated("Use sigquit instead")
+  static const ProcessSignal SIGQUIT = sigquit;
+  @Deprecated("Use sigill instead")
+  static const ProcessSignal SIGILL = sigill;
+  @Deprecated("Use sigtrap instead")
+  static const ProcessSignal SIGTRAP = sigtrap;
+  @Deprecated("Use sigabrt instead")
+  static const ProcessSignal SIGABRT = sigabrt;
+  @Deprecated("Use sigbus instead")
+  static const ProcessSignal SIGBUS = sigbus;
+  @Deprecated("Use sigfpe instead")
+  static const ProcessSignal SIGFPE = sigfpe;
+  @Deprecated("Use sigkill instead")
+  static const ProcessSignal SIGKILL = sigkill;
+  @Deprecated("Use sigusr1 instead")
+  static const ProcessSignal SIGUSR1 = sigusr1;
+  @Deprecated("Use sigsegv instead")
+  static const ProcessSignal SIGSEGV = sigsegv;
+  @Deprecated("Use sigusr2 instead")
+  static const ProcessSignal SIGUSR2 = sigusr2;
+  @Deprecated("Use sigpipe instead")
+  static const ProcessSignal SIGPIPE = sigpipe;
+  @Deprecated("Use sigalrm instead")
+  static const ProcessSignal SIGALRM = sigalrm;
+  @Deprecated("Use sigterm instead")
+  static const ProcessSignal SIGTERM = sigterm;
+  @Deprecated("Use sigchld instead")
+  static const ProcessSignal SIGCHLD = sigchld;
+  @Deprecated("Use sigcont instead")
+  static const ProcessSignal SIGCONT = sigcont;
+  @Deprecated("Use sigstop instead")
+  static const ProcessSignal SIGSTOP = sigstop;
+  @Deprecated("Use sigtstp instead")
+  static const ProcessSignal SIGTSTP = sigtstp;
+  @Deprecated("Use sigttin instead")
+  static const ProcessSignal SIGTTIN = sigttin;
+  @Deprecated("Use sigttou instead")
+  static const ProcessSignal SIGTTOU = sigttou;
+  @Deprecated("Use sigurg instead")
+  static const ProcessSignal SIGURG = sigurg;
+  @Deprecated("Use sigxcpu instead")
+  static const ProcessSignal SIGXCPU = sigxcpu;
+  @Deprecated("Use sigxfsz instead")
+  static const ProcessSignal SIGXFSZ = sigxfsz;
+  @Deprecated("Use sigvtalrm instead")
+  static const ProcessSignal SIGVTALRM = sigvtalrm;
+  @Deprecated("Use sigprof instead")
+  static const ProcessSignal SIGPROF = sigprof;
+  @Deprecated("Use sigwinch instead")
+  static const ProcessSignal SIGWINCH = sigwinch;
+  @Deprecated("Use sigpoll instead")
+  static const ProcessSignal SIGPOLL = sigpoll;
+  @Deprecated("Use sigsys instead")
+  static const ProcessSignal SIGSYS = sigsys;
+
+  final int _signalNumber;
+  final String _name;
+
+  const ProcessSignal._(this._signalNumber, this._name);
+
+  String toString() => _name;
+
+  /**
+   * Watch for process signals.
+   *
+   * The following [ProcessSignal]s can be listened to:
+   *
+   *   * [ProcessSignal.sighup].
+   *   * [ProcessSignal.sigint]. Signal sent by e.g. CTRL-C.
+   *   * [ProcessSignal.sigterm]. Not available on Windows.
+   *   * [ProcessSignal.sigusr1]. Not available on Windows.
+   *   * [ProcessSignal.sigusr2]. Not available on Windows.
+   *   * [ProcessSignal.sigwinch]. Not available on Windows.
+   *
+   * Other signals are disallowed, as they may be used by the VM.
+   *
+   * A signal can be watched multiple times, from multiple isolates, where all
+   * callbacks are invoked when signaled, in no specific order.
+   */
+  Stream<ProcessSignal> watch() => _ProcessUtils._watchSignal(this);
+}
+
+class SignalException implements IOException {
+  final String message;
+  final osError;
+
+  const SignalException(this.message, [this.osError]);
+
+  String toString() {
+    var msg = "";
+    if (osError != null) {
+      msg = ", osError: $osError";
+    }
+    return "SignalException: $message$msg";
+  }
+}
+
+class ProcessException implements IOException {
+  /**
+   * Contains the executable provided for the process.
+   */
+  final String executable;
+
+  /**
+   * Contains the arguments provided for the process.
+   */
+  final List<String> arguments;
+
+  /**
+   * Contains the system message for the process exception if any.
+   */
+  final String message;
+
+  /**
+   * Contains the OS error code for the process exception if any.
+   */
+  final int errorCode;
+
+  const ProcessException(this.executable, this.arguments,
+      [this.message = "", this.errorCode = 0]);
+  String toString() {
+    var msg = (message == null) ? 'OS error code: $errorCode' : message;
+    var args = arguments.join(' ');
+    return "ProcessException: $msg\n  Command: $executable $args";
+  }
+}
diff --git a/sdk_nnbd/lib/io/secure_server_socket.dart b/sdk_nnbd/lib/io/secure_server_socket.dart
new file mode 100644
index 0000000..b4ca32e
--- /dev/null
+++ b/sdk_nnbd/lib/io/secure_server_socket.dart
@@ -0,0 +1,291 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.io;
+
+/**
+ * The [SecureServerSocket] is a server socket, providing a stream of high-level
+ * [Socket]s.
+ *
+ * See [SecureSocket] for more info.
+ */
+class SecureServerSocket extends Stream<SecureSocket> {
+  final RawSecureServerSocket _socket;
+
+  SecureServerSocket._(this._socket);
+
+  /**
+   * Returns a future for a [SecureServerSocket]. When the future
+   * completes the server socket is bound to the given [address] and
+   * [port] and has started listening on it.
+   *
+   * The [address] can either be a [String] or an
+   * [InternetAddress]. If [address] is a [String], [bind] will
+   * perform a [InternetAddress.lookup] and use the first value in the
+   * list. To listen on the loopback adapter, which will allow only
+   * incoming connections from the local host, use the value
+   * [InternetAddress.loopbackIPv4] or
+   * [InternetAddress.loopbackIPv6]. To allow for incoming
+   * connection from the network use either one of the values
+   * [InternetAddress.anyIPv4] or [InternetAddress.anyIPv6] to
+   * bind to all interfaces or the IP address of a specific interface.
+   *
+   * If [port] has the value [:0:] an ephemeral port will be chosen by
+   * the system. The actual port used can be retrieved using the
+   * [port] getter.
+   *
+   * The optional argument [backlog] can be used to specify the listen
+   * backlog for the underlying OS listen setup. If [backlog] has the
+   * value of [:0:] (the default) a reasonable value will be chosen by
+   * the system.
+   *
+   * Incoming client connections are promoted to secure connections, using
+   * the server certificate and key set in [context].
+   *
+   * [address] must be given as a numeric address, not a host name.
+   *
+   * To request or require that clients authenticate by providing an SSL (TLS)
+   * client certificate, set the optional parameter [requestClientCertificate]
+   * or [requireClientCertificate] to true.  Requiring a certificate implies
+   * requesting a certificate, so setting both is redundant.
+   * To check whether a client certificate was received, check
+   * SecureSocket.peerCertificate after connecting.  If no certificate
+   * was received, the result will be null.
+   *
+   * [supportedProtocols] is an optional list of protocols (in decreasing
+   * order of preference) to use during the ALPN protocol negogiation with
+   * clients.  Example values are "http/1.1" or "h2".  The selected protocol
+   * can be obtained via [SecureSocket.selectedProtocol].
+   *
+   * The optional argument [shared] specifies whether additional
+   * SecureServerSocket objects can bind to the same combination of `address`,
+   * `port` and `v6Only`.  If `shared` is `true` and more `SecureServerSocket`s
+   * from this isolate or other isolates are bound to the port, then the
+   * incoming connections will be distributed among all the bound
+   * `SecureServerSocket`s. Connections can be distributed over multiple
+   * isolates this way.
+   */
+  static Future<SecureServerSocket> bind(
+      address, int port, SecurityContext context,
+      {int backlog: 0,
+      bool v6Only: false,
+      bool requestClientCertificate: false,
+      bool requireClientCertificate: false,
+      List<String> supportedProtocols,
+      bool shared: false}) {
+    return RawSecureServerSocket
+        .bind(address, port, context,
+            backlog: backlog,
+            v6Only: v6Only,
+            requestClientCertificate: requestClientCertificate,
+            requireClientCertificate: requireClientCertificate,
+            supportedProtocols: supportedProtocols,
+            shared: shared)
+        .then((serverSocket) => new SecureServerSocket._(serverSocket));
+  }
+
+  StreamSubscription<SecureSocket> listen(void onData(SecureSocket socket),
+      {Function onError, void onDone(), bool cancelOnError}) {
+    return _socket.map((rawSocket) => new SecureSocket._(rawSocket)).listen(
+        onData,
+        onError: onError,
+        onDone: onDone,
+        cancelOnError: cancelOnError);
+  }
+
+  /**
+   * Returns the port used by this socket.
+   */
+  int get port => _socket.port;
+
+  /**
+   * Returns the address used by this socket.
+   */
+  InternetAddress get address => _socket.address;
+
+  /**
+   * Closes the socket. The returned future completes when the socket
+   * is fully closed and is no longer bound.
+   */
+  Future<SecureServerSocket> close() => _socket.close().then((_) => this);
+
+  void set _owner(owner) {
+    _socket._owner = owner;
+  }
+}
+
+/**
+ * The RawSecureServerSocket is a server socket, providing a stream of low-level
+ * [RawSecureSocket]s.
+ *
+ * See [RawSecureSocket] for more info.
+ */
+class RawSecureServerSocket extends Stream<RawSecureSocket> {
+  final RawServerSocket _socket;
+  StreamController<RawSecureSocket> _controller;
+  StreamSubscription<RawSocket> _subscription;
+  final SecurityContext _context;
+  final bool requestClientCertificate;
+  final bool requireClientCertificate;
+  final List<String> supportedProtocols;
+  bool _closed = false;
+
+  RawSecureServerSocket._(
+      this._socket,
+      this._context,
+      this.requestClientCertificate,
+      this.requireClientCertificate,
+      this.supportedProtocols) {
+    _controller = new StreamController<RawSecureSocket>(
+        sync: true,
+        onListen: _onSubscriptionStateChange,
+        onPause: _onPauseStateChange,
+        onResume: _onPauseStateChange,
+        onCancel: _onSubscriptionStateChange);
+  }
+
+  /**
+   * Returns a future for a [RawSecureServerSocket]. When the future
+   * completes the server socket is bound to the given [address] and
+   * [port] and has started listening on it.
+   *
+   * The [address] can either be a [String] or an
+   * [InternetAddress]. If [address] is a [String], [bind] will
+   * perform a [InternetAddress.lookup] and use the first value in the
+   * list. To listen on the loopback adapter, which will allow only
+   * incoming connections from the local host, use the value
+   * [InternetAddress.loopbackIPv4] or
+   * [InternetAddress.loopbackIPv6]. To allow for incoming
+   * connection from the network use either one of the values
+   * [InternetAddress.anyIPv4] or [InternetAddress.anyIPv6] to
+   * bind to all interfaces or the IP address of a specific interface.
+   *
+   * If [port] has the value [:0:] an ephemeral port will be chosen by
+   * the system. The actual port used can be retrieved using the
+   * [port] getter.
+   *
+   * The optional argument [backlog] can be used to specify the listen
+   * backlog for the underlying OS listen setup. If [backlog] has the
+   * value of [:0:] (the default) a reasonable value will be chosen by
+   * the system.
+   *
+   * Incoming client connections are promoted to secure connections,
+   * using the server certificate and key set in [context].
+   *
+   * [address] must be given as a numeric address, not a host name.
+   *
+   * To request or require that clients authenticate by providing an SSL (TLS)
+   * client certificate, set the optional parameters requestClientCertificate or
+   * requireClientCertificate to true.  Require implies request, so one doesn't
+   * need to specify both.  To check whether a client certificate was received,
+   * check SecureSocket.peerCertificate after connecting.  If no certificate
+   * was received, the result will be null.
+   *
+   * [supportedProtocols] is an optional list of protocols (in decreasing
+   * order of preference) to use during the ALPN protocol negotiation with
+   * clients.  Example values are "http/1.1" or "h2".  The selected protocol
+   * can be obtained via [RawSecureSocket.selectedProtocol].
+   *
+   * The optional argument [shared] specifies whether additional
+   * RawSecureServerSocket objects can bind to the same combination of
+   * `address`, `port` and `v6Only`.  If `shared` is `true` and more
+   * `RawSecureServerSocket`s from this isolate or other isolates are bound to
+   * the port, then the incoming connections will be distributed among all the
+   * bound `RawSecureServerSocket`s. Connections can be distributed over
+   * multiple isolates this way.
+   */
+  static Future<RawSecureServerSocket> bind(
+      address, int port, SecurityContext context,
+      {int backlog: 0,
+      bool v6Only: false,
+      bool requestClientCertificate: false,
+      bool requireClientCertificate: false,
+      List<String> supportedProtocols,
+      bool shared: false}) {
+    return RawServerSocket
+        .bind(address, port, backlog: backlog, v6Only: v6Only, shared: shared)
+        .then((serverSocket) => new RawSecureServerSocket._(
+            serverSocket,
+            context,
+            requestClientCertificate,
+            requireClientCertificate,
+            supportedProtocols));
+  }
+
+  StreamSubscription<RawSecureSocket> listen(void onData(RawSecureSocket s),
+      {Function onError, void onDone(), bool cancelOnError}) {
+    return _controller.stream.listen(onData,
+        onError: onError, onDone: onDone, cancelOnError: cancelOnError);
+  }
+
+  /**
+   * Returns the port used by this socket.
+   */
+  int get port => _socket.port;
+
+  /**
+   * Returns the address used by this socket.
+   */
+  InternetAddress get address => _socket.address;
+
+  /**
+   * Closes the socket. The returned future completes when the socket
+   * is fully closed and is no longer bound.
+   */
+  Future<RawSecureServerSocket> close() {
+    _closed = true;
+    return _socket.close().then((_) => this);
+  }
+
+  void _onData(RawSocket connection) {
+    var remotePort;
+    try {
+      remotePort = connection.remotePort;
+    } catch (e) {
+      // If connection is already closed, remotePort throws an exception.
+      // Do nothing - connection is closed.
+      return;
+    }
+    _RawSecureSocket
+        .connect(connection.address, remotePort,
+            context: _context,
+            is_server: true,
+            socket: connection,
+            requestClientCertificate: requestClientCertificate,
+            requireClientCertificate: requireClientCertificate,
+            supportedProtocols: supportedProtocols)
+        .then((RawSecureSocket secureConnection) {
+      if (_closed) {
+        secureConnection.close();
+      } else {
+        _controller.add(secureConnection);
+      }
+    }).catchError((e, s) {
+      if (!_closed) {
+        _controller.addError(e, s);
+      }
+    });
+  }
+
+  void _onPauseStateChange() {
+    if (_controller.isPaused) {
+      _subscription.pause();
+    } else {
+      _subscription.resume();
+    }
+  }
+
+  void _onSubscriptionStateChange() {
+    if (_controller.hasListener) {
+      _subscription = _socket.listen(_onData,
+          onError: _controller.addError, onDone: _controller.close);
+    } else {
+      close();
+    }
+  }
+
+  void set _owner(owner) {
+    (_socket as dynamic)._owner = owner;
+  }
+}
diff --git a/sdk_nnbd/lib/io/secure_socket.dart b/sdk_nnbd/lib/io/secure_socket.dart
new file mode 100644
index 0000000..a4751ef
--- /dev/null
+++ b/sdk_nnbd/lib/io/secure_socket.dart
@@ -0,0 +1,1319 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.io;
+
+/**
+ * A high-level class for communicating securely over a TCP socket, using
+ * TLS and SSL. The [SecureSocket] exposes both a [Stream] and an
+ * [IOSink] interface, making it ideal for using together with
+ * other [Stream]s.
+ */
+abstract class SecureSocket implements Socket {
+  external factory SecureSocket._(RawSecureSocket rawSocket);
+
+  /**
+   * Constructs a new secure client socket and connects it to the given
+   * [host] on port [port]. The returned Future will complete with a
+   * [SecureSocket] that is connected and ready for subscription.
+   *
+   * The certificate provided by the server is checked
+   * using the trusted certificates set in the SecurityContext object.
+   * The default SecurityContext object contains a built-in set of trusted
+   * root certificates for well-known certificate authorities.
+   *
+   * [onBadCertificate] is an optional handler for unverifiable certificates.
+   * The handler receives the [X509Certificate], and can inspect it and
+   * decide (or let the user decide) whether to accept
+   * the connection or not.  The handler should return true
+   * to continue the [SecureSocket] connection.
+   *
+   * [supportedProtocols] is an optional list of protocols (in decreasing
+   * order of preference) to use during the ALPN protocol negotiation with the
+   * server.  Example values are "http/1.1" or "h2".  The selected protocol
+   * can be obtained via [SecureSocket.selectedProtocol].
+   *
+   * The argument [timeout] is used to specify the maximum allowed time to wait
+   * for a connection to be established. If [timeout] is longer than the system
+   * level timeout duration, a timeout may occur sooner than specified in
+   * [timeout]. On timeout, a [SocketException] is thrown and all ongoing
+   * connection attempts to [host] are cancelled.
+
+   */
+  static Future<SecureSocket> connect(host, int port,
+      {SecurityContext context,
+      bool onBadCertificate(X509Certificate certificate),
+      List<String> supportedProtocols,
+      Duration timeout}) {
+    return RawSecureSocket.connect(host, port,
+            context: context,
+            onBadCertificate: onBadCertificate,
+            supportedProtocols: supportedProtocols,
+            timeout: timeout)
+        .then((rawSocket) => new SecureSocket._(rawSocket));
+  }
+
+  /// Like [connect], but returns a [Future] that completes with a
+  /// [ConnectionTask] that can be cancelled if the [SecureSocket] is no
+  /// longer needed.
+  static Future<ConnectionTask<SecureSocket>> startConnect(host, int port,
+      {SecurityContext context,
+      bool onBadCertificate(X509Certificate certificate),
+      List<String> supportedProtocols}) {
+    return RawSecureSocket.startConnect(host, port,
+            context: context,
+            onBadCertificate: onBadCertificate,
+            supportedProtocols: supportedProtocols)
+        .then((rawState) {
+      Future<SecureSocket> socket =
+          rawState.socket.then((rawSocket) => new SecureSocket._(rawSocket));
+      return new ConnectionTask<SecureSocket>._(
+          socket: socket, onCancel: rawState._onCancel);
+    });
+  }
+
+  /**
+   * Takes an already connected [socket] and starts client side TLS
+   * handshake to make the communication secure. When the returned
+   * future completes the [SecureSocket] has completed the TLS
+   * handshake. Using this function requires that the other end of the
+   * connection is prepared for TLS handshake.
+   *
+   * If the [socket] already has a subscription, this subscription
+   * will no longer receive and events. In most cases calling
+   * `pause` on this subscription before starting TLS handshake is
+   * the right thing to do.
+   *
+   * The given [socket] is closed and may not be used anymore.
+   *
+   * If the [host] argument is passed it will be used as the host name
+   * for the TLS handshake. If [host] is not passed the host name from
+   * the [socket] will be used. The [host] can be either a [String] or
+   * an [InternetAddress].
+   *
+   * [supportedProtocols] is an optional list of protocols (in decreasing
+   * order of preference) to use during the ALPN protocol negotiation with the
+   * server.  Example values are "http/1.1" or "h2".  The selected protocol
+   * can be obtained via [SecureSocket.selectedProtocol].
+   *
+   * Calling this function will _not_ cause a DNS host lookup. If the
+   * [host] passed is a [String] the [InternetAddress] for the
+   * resulting [SecureSocket] will have the passed in [host] as its
+   * host value and the internet address of the already connected
+   * socket as its address value.
+   *
+   * See [connect] for more information on the arguments.
+   *
+   */
+  static Future<SecureSocket> secure(Socket socket,
+      {host,
+      SecurityContext context,
+      bool onBadCertificate(X509Certificate certificate),
+      @Since("2.6") List<String> supportedProtocols}) {
+    return ((socket as dynamic /*_Socket*/)._detachRaw() as Future)
+        .then<RawSecureSocket>((detachedRaw) {
+      return RawSecureSocket.secure(detachedRaw[0] as RawSocket,
+          subscription: detachedRaw[1] as StreamSubscription<RawSocketEvent>,
+          host: host,
+          context: context,
+          onBadCertificate: onBadCertificate,
+          supportedProtocols: supportedProtocols);
+    }).then<SecureSocket>((raw) => new SecureSocket._(raw));
+  }
+
+  /**
+   * Takes an already connected [socket] and starts server side TLS
+   * handshake to make the communication secure. When the returned
+   * future completes the [SecureSocket] has completed the TLS
+   * handshake. Using this function requires that the other end of the
+   * connection is going to start the TLS handshake.
+   *
+   * If the [socket] already has a subscription, this subscription
+   * will no longer receive and events. In most cases calling
+   * [:pause:] on this subscription before starting TLS handshake is
+   * the right thing to do.
+   *
+   * If some of the data of the TLS handshake has already been read
+   * from the socket this data can be passed in the [bufferedData]
+   * parameter. This data will be processed before any other data
+   * available on the socket.
+   *
+   * See [SecureServerSocket.bind] for more information on the
+   * arguments.
+   *
+   */
+  static Future<SecureSocket> secureServer(
+      Socket socket, SecurityContext context,
+      {List<int> bufferedData,
+      bool requestClientCertificate: false,
+      bool requireClientCertificate: false,
+      List<String> supportedProtocols}) {
+    return ((socket as dynamic /*_Socket*/)._detachRaw() as Future)
+        .then<RawSecureSocket>((detachedRaw) {
+      return RawSecureSocket.secureServer(detachedRaw[0] as RawSocket, context,
+          subscription: detachedRaw[1] as StreamSubscription<RawSocketEvent>,
+          bufferedData: bufferedData,
+          requestClientCertificate: requestClientCertificate,
+          requireClientCertificate: requireClientCertificate,
+          supportedProtocols: supportedProtocols);
+    }).then<SecureSocket>((raw) => new SecureSocket._(raw));
+  }
+
+  /**
+   * Get the peer certificate for a connected SecureSocket.  If this
+   * SecureSocket is the server end of a secure socket connection,
+   * [peerCertificate] will return the client certificate, or null, if no
+   * client certificate was received.  If it is the client end,
+   * [peerCertificate] will return the server's certificate.
+   */
+  X509Certificate get peerCertificate;
+
+  /**
+   * The protocol which was selected during ALPN protocol negotiation.
+   *
+   * Returns null if one of the peers does not have support for ALPN, did not
+   * specify a list of supported ALPN protocols or there was no common
+   * protocol between client and server.
+   */
+  String get selectedProtocol;
+
+  /**
+   * Renegotiate an existing secure connection, renewing the session keys
+   * and possibly changing the connection properties.
+   *
+   * This repeats the SSL or TLS handshake, with options that allow clearing
+   * the session cache and requesting a client certificate.
+   */
+  void renegotiate(
+      {bool useSessionCache: true,
+      bool requestClientCertificate: false,
+      bool requireClientCertificate: false});
+}
+
+/**
+ * RawSecureSocket provides a secure (SSL or TLS) network connection.
+ * Client connections to a server are provided by calling
+ * RawSecureSocket.connect.  A secure server, created with
+ * [RawSecureServerSocket], also returns RawSecureSocket objects representing
+ * the server end of a secure connection.
+ * The certificate provided by the server is checked
+ * using the trusted certificates set in the SecurityContext object.
+ * The default [SecurityContext] object contains a built-in set of trusted
+ * root certificates for well-known certificate authorities.
+ */
+abstract class RawSecureSocket implements RawSocket {
+  /**
+   * Constructs a new secure client socket and connect it to the given
+   * host on the given port. The returned [Future] is completed with the
+   * RawSecureSocket when it is connected and ready for subscription.
+   *
+   * The certificate provided by the server is checked using the trusted
+   * certificates set in the SecurityContext object If a certificate and key are
+   * set on the client, using [SecurityContext.useCertificateChain] and
+   * [SecurityContext.usePrivateKey], and the server asks for a client
+   * certificate, then that client certificate is sent to the server.
+   *
+   * [onBadCertificate] is an optional handler for unverifiable certificates.
+   * The handler receives the [X509Certificate], and can inspect it and
+   * decide (or let the user decide) whether to accept
+   * the connection or not.  The handler should return true
+   * to continue the [RawSecureSocket] connection.
+   *
+   * [supportedProtocols] is an optional list of protocols (in decreasing
+   * order of preference) to use during the ALPN protocol negotiation with the
+   * server.  Example values are "http/1.1" or "h2".  The selected protocol
+   * can be obtained via [RawSecureSocket.selectedProtocol].
+   */
+  static Future<RawSecureSocket> connect(host, int port,
+      {SecurityContext context,
+      bool onBadCertificate(X509Certificate certificate),
+      List<String> supportedProtocols,
+      Duration timeout}) {
+    _RawSecureSocket._verifyFields(
+        host, port, false, false, false, onBadCertificate);
+    return RawSocket.connect(host, port, timeout: timeout).then((socket) {
+      return secure(socket,
+          context: context,
+          onBadCertificate: onBadCertificate,
+          supportedProtocols: supportedProtocols);
+    });
+  }
+
+  /// Like [connect], but returns a [Future] that completes with a
+  /// [ConnectionTask] that can be cancelled if the [RawSecureSocket] is no
+  /// longer needed.
+  static Future<ConnectionTask<RawSecureSocket>> startConnect(host, int port,
+      {SecurityContext context,
+      bool onBadCertificate(X509Certificate certificate),
+      List<String> supportedProtocols}) {
+    return RawSocket.startConnect(host, port)
+        .then((ConnectionTask<RawSocket> rawState) {
+      Future<RawSecureSocket> socket = rawState.socket.then((rawSocket) {
+        return secure(rawSocket,
+            context: context,
+            onBadCertificate: onBadCertificate,
+            supportedProtocols: supportedProtocols);
+      });
+      return new ConnectionTask<RawSecureSocket>._(
+          socket: socket, onCancel: rawState._onCancel);
+    });
+  }
+
+  /**
+   * Takes an already connected [socket] and starts client side TLS
+   * handshake to make the communication secure. When the returned
+   * future completes the [RawSecureSocket] has completed the TLS
+   * handshake. Using this function requires that the other end of the
+   * connection is prepared for TLS handshake.
+   *
+   * If the [socket] already has a subscription, pass the existing
+   * subscription in the [subscription] parameter. The [secure]
+   * operation will take over the subscription by replacing the
+   * handlers with it own secure processing. The caller must not touch
+   * this subscription anymore. Passing a paused subscription is an
+   * error.
+   *
+   * If the [host] argument is passed it will be used as the host name
+   * for the TLS handshake. If [host] is not passed the host name from
+   * the [socket] will be used. The [host] can be either a [String] or
+   * an [InternetAddress].
+   *
+   * [supportedProtocols] is an optional list of protocols (in decreasing
+   * order of preference) to use during the ALPN protocol negotiation with the
+   * server.  Example values are "http/1.1" or "h2".  The selected protocol
+   * can be obtained via [SecureSocket.selectedProtocol].
+   *
+   * Calling this function will _not_ cause a DNS host lookup. If the
+   * [host] passed is a [String] the [InternetAddress] for the
+   * resulting [SecureSocket] will have this passed in [host] as its
+   * host value and the internet address of the already connected
+   * socket as its address value.
+   *
+   * See [connect] for more information on the arguments.
+   *
+   */
+  static Future<RawSecureSocket> secure(RawSocket socket,
+      {StreamSubscription<RawSocketEvent> subscription,
+      host,
+      SecurityContext context,
+      bool onBadCertificate(X509Certificate certificate),
+      List<String> supportedProtocols}) {
+    socket.readEventsEnabled = false;
+    socket.writeEventsEnabled = false;
+    return _RawSecureSocket.connect(
+        host != null ? host : socket.address.host, socket.port,
+        is_server: false,
+        socket: socket,
+        subscription: subscription,
+        context: context,
+        onBadCertificate: onBadCertificate,
+        supportedProtocols: supportedProtocols);
+  }
+
+  /**
+   * Takes an already connected [socket] and starts server side TLS
+   * handshake to make the communication secure. When the returned
+   * future completes the [RawSecureSocket] has completed the TLS
+   * handshake. Using this function requires that the other end of the
+   * connection is going to start the TLS handshake.
+   *
+   * If the [socket] already has a subscription, pass the existing
+   * subscription in the [subscription] parameter. The [secureServer]
+   * operation will take over the subscription by replacing the
+   * handlers with it own secure processing. The caller must not touch
+   * this subscription anymore. Passing a paused subscription is an
+   * error.
+   *
+   * If some of the data of the TLS handshake has already been read
+   * from the socket this data can be passed in the [bufferedData]
+   * parameter. This data will be processed before any other data
+   * available on the socket.
+   *
+   * See [RawSecureServerSocket.bind] for more information on the
+   * arguments.
+   *
+   */
+  static Future<RawSecureSocket> secureServer(
+      RawSocket socket, SecurityContext context,
+      {StreamSubscription<RawSocketEvent> subscription,
+      List<int> bufferedData,
+      bool requestClientCertificate: false,
+      bool requireClientCertificate: false,
+      List<String> supportedProtocols}) {
+    socket.readEventsEnabled = false;
+    socket.writeEventsEnabled = false;
+    return _RawSecureSocket.connect(socket.address, socket.remotePort,
+        context: context,
+        is_server: true,
+        socket: socket,
+        subscription: subscription,
+        bufferedData: bufferedData,
+        requestClientCertificate: requestClientCertificate,
+        requireClientCertificate: requireClientCertificate,
+        supportedProtocols: supportedProtocols);
+  }
+
+  /**
+   * Renegotiate an existing secure connection, renewing the session keys
+   * and possibly changing the connection properties.
+   *
+   * This repeats the SSL or TLS handshake, with options that allow clearing
+   * the session cache and requesting a client certificate.
+   */
+  void renegotiate(
+      {bool useSessionCache: true,
+      bool requestClientCertificate: false,
+      bool requireClientCertificate: false});
+
+  /**
+   * Get the peer certificate for a connected RawSecureSocket.  If this
+   * RawSecureSocket is the server end of a secure socket connection,
+   * [peerCertificate] will return the client certificate, or null, if no
+   * client certificate was received.  If it is the client end,
+   * [peerCertificate] will return the server's certificate.
+   */
+  X509Certificate get peerCertificate;
+
+  /**
+   * The protocol which was selected during protocol negotiation.
+   *
+   * Returns null if one of the peers does not have support for ALPN, did not
+   * specify a list of supported ALPN protocols or there was no common
+   * protocol between client and server.
+   */
+  String get selectedProtocol;
+}
+
+/**
+ * X509Certificate represents an SSL certificate, with accessors to
+ * get the fields of the certificate.
+ */
+@pragma("vm:entry-point")
+abstract class X509Certificate {
+  @pragma("vm:entry-point")
+  external factory X509Certificate._();
+
+  /// The DER encoded bytes of the certificate.
+  Uint8List get der;
+
+  /// The PEM encoded String of the certificate.
+  String get pem;
+
+  /// The SHA1 hash of the certificate.
+  Uint8List get sha1;
+
+  String get subject;
+  String get issuer;
+  DateTime get startValidity;
+  DateTime get endValidity;
+}
+
+class _FilterStatus {
+  bool progress = false; // The filter read or wrote data to the buffers.
+  bool readEmpty = true; // The read buffers and decryption filter are empty.
+  bool writeEmpty = true; // The write buffers and encryption filter are empty.
+  // These are set if a buffer changes state from empty or full.
+  bool readPlaintextNoLongerEmpty = false;
+  bool writePlaintextNoLongerFull = false;
+  bool readEncryptedNoLongerFull = false;
+  bool writeEncryptedNoLongerEmpty = false;
+
+  _FilterStatus();
+}
+
+class _RawSecureSocket extends Stream<RawSocketEvent>
+    implements RawSecureSocket {
+  // Status states
+  static const int handshakeStatus = 201;
+  static const int connectedStatus = 202;
+  static const int closedStatus = 203;
+
+  // Buffer identifiers.
+  // These must agree with those in the native C++ implementation.
+  static const int readPlaintextId = 0;
+  static const int writePlaintextId = 1;
+  static const int readEncryptedId = 2;
+  static const int writeEncryptedId = 3;
+  static const int bufferCount = 4;
+
+  // Is a buffer identifier for an encrypted buffer?
+  static bool _isBufferEncrypted(int identifier) =>
+      identifier >= readEncryptedId;
+
+  RawSocket _socket;
+  final Completer<_RawSecureSocket> _handshakeComplete =
+      new Completer<_RawSecureSocket>();
+  StreamController<RawSocketEvent> _controller;
+  Stream<RawSocketEvent> _stream;
+  StreamSubscription<RawSocketEvent> _socketSubscription;
+  List<int> _bufferedData;
+  int _bufferedDataIndex = 0;
+  final InternetAddress address;
+  final bool is_server;
+  SecurityContext context;
+  final bool requestClientCertificate;
+  final bool requireClientCertificate;
+  final Function onBadCertificate;
+
+  var _status = handshakeStatus;
+  bool _writeEventsEnabled = true;
+  bool _readEventsEnabled = true;
+  int _pauseCount = 0;
+  bool _pendingReadEvent = false;
+  bool _socketClosedRead = false; // The network socket is closed for reading.
+  bool _socketClosedWrite = false; // The network socket is closed for writing.
+  bool _closedRead = false; // The secure socket has fired an onClosed event.
+  bool _closedWrite = false; // The secure socket has been closed for writing.
+  // The network socket is gone.
+  Completer<RawSecureSocket> _closeCompleter = new Completer<RawSecureSocket>();
+  _FilterStatus _filterStatus = new _FilterStatus();
+  bool _connectPending = true;
+  bool _filterPending = false;
+  bool _filterActive = false;
+
+  _SecureFilter _secureFilter = new _SecureFilter._();
+  String _selectedProtocol;
+
+  static Future<_RawSecureSocket> connect(
+      dynamic /*String|InternetAddress*/ host, int requestedPort,
+      {bool is_server,
+      SecurityContext context,
+      RawSocket socket,
+      StreamSubscription<RawSocketEvent> subscription,
+      List<int> bufferedData,
+      bool requestClientCertificate: false,
+      bool requireClientCertificate: false,
+      bool onBadCertificate(X509Certificate certificate),
+      List<String> supportedProtocols}) {
+    _verifyFields(host, requestedPort, is_server, requestClientCertificate,
+        requireClientCertificate, onBadCertificate);
+    if (host is InternetAddress) host = host.host;
+    InternetAddress address = socket.address;
+    if (host != null) {
+      address = InternetAddress._cloneWithNewHost(address, host);
+    }
+    return new _RawSecureSocket(
+            address,
+            requestedPort,
+            is_server,
+            context,
+            socket,
+            subscription,
+            bufferedData,
+            requestClientCertificate,
+            requireClientCertificate,
+            onBadCertificate,
+            supportedProtocols)
+        ._handshakeComplete
+        .future;
+  }
+
+  _RawSecureSocket(
+      this.address,
+      int requestedPort,
+      this.is_server,
+      this.context,
+      this._socket,
+      this._socketSubscription,
+      this._bufferedData,
+      this.requestClientCertificate,
+      this.requireClientCertificate,
+      this.onBadCertificate,
+      List<String> supportedProtocols) {
+    context ??= SecurityContext.defaultContext;
+    _controller = new StreamController<RawSocketEvent>(
+        sync: true,
+        onListen: _onSubscriptionStateChange,
+        onPause: _onPauseStateChange,
+        onResume: _onPauseStateChange,
+        onCancel: _onSubscriptionStateChange);
+    _stream = _controller.stream;
+    // Throw an ArgumentError if any field is invalid.  After this, all
+    // errors will be reported through the future or the stream.
+    _secureFilter.init();
+    _secureFilter
+        .registerHandshakeCompleteCallback(_secureHandshakeCompleteHandler);
+    if (onBadCertificate != null) {
+      _secureFilter.registerBadCertificateCallback(_onBadCertificateWrapper);
+    }
+    _socket.readEventsEnabled = true;
+    _socket.writeEventsEnabled = false;
+    if (_socketSubscription == null) {
+      // If a current subscription is provided use this otherwise
+      // create a new one.
+      _socketSubscription = _socket.listen(_eventDispatcher,
+          onError: _reportError, onDone: _doneHandler);
+    } else {
+      if (_socketSubscription.isPaused) {
+        _socket.close();
+        throw new ArgumentError("Subscription passed to TLS upgrade is paused");
+      }
+      // If we are upgrading a socket that is already closed for read,
+      // report an error as if we received readClosed during the handshake.
+      dynamic s = _socket; // Cast to dynamic to avoid warning.
+      if (s._socket.closedReadEventSent) {
+        _eventDispatcher(RawSocketEvent.readClosed);
+      }
+      _socketSubscription
+        ..onData(_eventDispatcher)
+        ..onError(_reportError)
+        ..onDone(_doneHandler);
+    }
+    try {
+      var encodedProtocols =
+          SecurityContext._protocolsToLengthEncoding(supportedProtocols);
+      _secureFilter.connect(
+          address.host,
+          context,
+          is_server,
+          requestClientCertificate || requireClientCertificate,
+          requireClientCertificate,
+          encodedProtocols);
+      _secureHandshake();
+    } catch (e, s) {
+      _reportError(e, s);
+    }
+  }
+
+  StreamSubscription<RawSocketEvent> listen(void onData(RawSocketEvent data),
+      {Function onError, void onDone(), bool cancelOnError}) {
+    _sendWriteEvent();
+    return _stream.listen(onData,
+        onError: onError, onDone: onDone, cancelOnError: cancelOnError);
+  }
+
+  static void _verifyFields(
+      host,
+      int requestedPort,
+      bool is_server,
+      bool requestClientCertificate,
+      bool requireClientCertificate,
+      Function onBadCertificate) {
+    if (host is! String && host is! InternetAddress) {
+      throw new ArgumentError("host is not a String or an InternetAddress");
+    }
+    ArgumentError.checkNotNull(requestedPort, "requestedPort");
+    if (requestedPort < 0 || requestedPort > 65535) {
+      throw ArgumentError("requestedPort is not in the range 0..65535");
+    }
+    ArgumentError.checkNotNull(
+        requestClientCertificate, "requestClientCertificate");
+    ArgumentError.checkNotNull(
+        requireClientCertificate, "requireClientCertificate");
+  }
+
+  int get port => _socket.port;
+
+  InternetAddress get remoteAddress => _socket.remoteAddress;
+
+  int get remotePort => _socket.remotePort;
+
+  void set _owner(owner) {
+    (_socket as dynamic)._owner = owner;
+  }
+
+  int available() {
+    return _status != connectedStatus
+        ? 0
+        : _secureFilter.buffers[readPlaintextId].length;
+  }
+
+  Future<RawSecureSocket> close() {
+    shutdown(SocketDirection.both);
+    return _closeCompleter.future;
+  }
+
+  void _completeCloseCompleter([RawSocket dummy]) {
+    if (!_closeCompleter.isCompleted) _closeCompleter.complete(this);
+  }
+
+  void _close() {
+    _closedWrite = true;
+    _closedRead = true;
+    if (_socket != null) {
+      _socket.close().then(_completeCloseCompleter);
+    } else {
+      _completeCloseCompleter();
+    }
+    _socketClosedWrite = true;
+    _socketClosedRead = true;
+    if (!_filterActive && _secureFilter != null) {
+      _secureFilter.destroy();
+      _secureFilter = null;
+    }
+    if (_socketSubscription != null) {
+      _socketSubscription.cancel();
+    }
+    _controller.close();
+    _status = closedStatus;
+  }
+
+  void shutdown(SocketDirection direction) {
+    if (direction == SocketDirection.send ||
+        direction == SocketDirection.both) {
+      _closedWrite = true;
+      if (_filterStatus.writeEmpty) {
+        _socket.shutdown(SocketDirection.send);
+        _socketClosedWrite = true;
+        if (_closedRead) {
+          _close();
+        }
+      }
+    }
+    if (direction == SocketDirection.receive ||
+        direction == SocketDirection.both) {
+      _closedRead = true;
+      _socketClosedRead = true;
+      _socket.shutdown(SocketDirection.receive);
+      if (_socketClosedWrite) {
+        _close();
+      }
+    }
+  }
+
+  bool get writeEventsEnabled => _writeEventsEnabled;
+
+  void set writeEventsEnabled(bool value) {
+    _writeEventsEnabled = value;
+    if (value) {
+      Timer.run(() => _sendWriteEvent());
+    }
+  }
+
+  bool get readEventsEnabled => _readEventsEnabled;
+
+  void set readEventsEnabled(bool value) {
+    _readEventsEnabled = value;
+    _scheduleReadEvent();
+  }
+
+  Uint8List read([int length]) {
+    if (length != null && (length is! int || length < 0)) {
+      throw new ArgumentError(
+          "Invalid length parameter in SecureSocket.read (length: $length)");
+    }
+    if (_closedRead) {
+      throw new SocketException("Reading from a closed socket");
+    }
+    if (_status != connectedStatus) {
+      return null;
+    }
+    var result = _secureFilter.buffers[readPlaintextId].read(length);
+    _scheduleFilter();
+    return result;
+  }
+
+  // Write the data to the socket, and schedule the filter to encrypt it.
+  int write(List<int> data, [int offset, int bytes]) {
+    if (bytes != null && (bytes is! int || bytes < 0)) {
+      throw new ArgumentError(
+          "Invalid bytes parameter in SecureSocket.read (bytes: $bytes)");
+    }
+    if (offset != null && (offset is! int || offset < 0)) {
+      throw new ArgumentError(
+          "Invalid offset parameter in SecureSocket.read (offset: $offset)");
+    }
+    if (_closedWrite) {
+      _controller.addError(new SocketException("Writing to a closed socket"));
+      return 0;
+    }
+    if (_status != connectedStatus) return 0;
+    offset ??= 0;
+    bytes ??= data.length - offset;
+
+    int written =
+        _secureFilter.buffers[writePlaintextId].write(data, offset, bytes);
+    if (written > 0) {
+      _filterStatus.writeEmpty = false;
+    }
+    _scheduleFilter();
+    return written;
+  }
+
+  X509Certificate get peerCertificate => _secureFilter.peerCertificate;
+
+  String get selectedProtocol => _selectedProtocol;
+
+  bool _onBadCertificateWrapper(X509Certificate certificate) {
+    if (onBadCertificate == null) return false;
+    var result = onBadCertificate(certificate);
+    if (result is bool) return result;
+    throw new HandshakeException(
+        "onBadCertificate callback returned non-boolean $result");
+  }
+
+  bool setOption(SocketOption option, bool enabled) {
+    if (_socket == null) return false;
+    return _socket.setOption(option, enabled);
+  }
+
+  Uint8List getRawOption(RawSocketOption option) {
+    return _socket?.getRawOption(option);
+  }
+
+  void setRawOption(RawSocketOption option) {
+    _socket?.setRawOption(option);
+  }
+
+  void _eventDispatcher(RawSocketEvent event) {
+    try {
+      if (event == RawSocketEvent.read) {
+        _readHandler();
+      } else if (event == RawSocketEvent.write) {
+        _writeHandler();
+      } else if (event == RawSocketEvent.readClosed) {
+        _closeHandler();
+      }
+    } catch (e, stackTrace) {
+      _reportError(e, stackTrace);
+    }
+  }
+
+  void _readHandler() {
+    _readSocket();
+    _scheduleFilter();
+  }
+
+  void _writeHandler() {
+    _writeSocket();
+    _scheduleFilter();
+  }
+
+  void _doneHandler() {
+    if (_filterStatus.readEmpty) {
+      _close();
+    }
+  }
+
+  void _reportError(e, [StackTrace stackTrace]) {
+    if (_status == closedStatus) {
+      return;
+    } else if (_connectPending) {
+      // _connectPending is true until the handshake has completed, and the
+      // _handshakeComplete future returned from SecureSocket.connect has
+      // completed.  Before this point, we must complete it with an error.
+      _handshakeComplete.completeError(e, stackTrace);
+    } else {
+      _controller.addError(e, stackTrace);
+    }
+    _close();
+  }
+
+  void _closeHandler() {
+    if (_status == connectedStatus) {
+      if (_closedRead) return;
+      _socketClosedRead = true;
+      if (_filterStatus.readEmpty) {
+        _closedRead = true;
+        _controller.add(RawSocketEvent.readClosed);
+        if (_socketClosedWrite) {
+          _close();
+        }
+      } else {
+        _scheduleFilter();
+      }
+    } else if (_status == handshakeStatus) {
+      _socketClosedRead = true;
+      if (_filterStatus.readEmpty) {
+        _reportError(
+            new HandshakeException('Connection terminated during handshake'),
+            null);
+      } else {
+        _secureHandshake();
+      }
+    }
+  }
+
+  void _secureHandshake() {
+    try {
+      _secureFilter.handshake();
+      _filterStatus.writeEmpty = false;
+      _readSocket();
+      _writeSocket();
+      _scheduleFilter();
+    } catch (e, stackTrace) {
+      _reportError(e, stackTrace);
+    }
+  }
+
+  void renegotiate(
+      {bool useSessionCache: true,
+      bool requestClientCertificate: false,
+      bool requireClientCertificate: false}) {
+    if (_status != connectedStatus) {
+      throw new HandshakeException(
+          "Called renegotiate on a non-connected socket");
+    }
+    _secureFilter.renegotiate(
+        useSessionCache, requestClientCertificate, requireClientCertificate);
+    _status = handshakeStatus;
+    _filterStatus.writeEmpty = false;
+    _scheduleFilter();
+  }
+
+  void _secureHandshakeCompleteHandler() {
+    _status = connectedStatus;
+    if (_connectPending) {
+      _connectPending = false;
+      try {
+        _selectedProtocol = _secureFilter.selectedProtocol();
+        // We don't want user code to run synchronously in this callback.
+        Timer.run(() => _handshakeComplete.complete(this));
+      } catch (error, stack) {
+        _handshakeComplete.completeError(error, stack);
+      }
+    }
+  }
+
+  void _onPauseStateChange() {
+    if (_controller.isPaused) {
+      _pauseCount++;
+    } else {
+      _pauseCount--;
+      if (_pauseCount == 0) {
+        _scheduleReadEvent();
+        _sendWriteEvent(); // Can send event synchronously.
+      }
+    }
+
+    if (!_socketClosedRead || !_socketClosedWrite) {
+      if (_controller.isPaused) {
+        _socketSubscription.pause();
+      } else {
+        _socketSubscription.resume();
+      }
+    }
+  }
+
+  void _onSubscriptionStateChange() {
+    if (_controller.hasListener) {
+      // TODO(ajohnsen): Do something here?
+    }
+  }
+
+  void _scheduleFilter() {
+    _filterPending = true;
+    _tryFilter();
+  }
+
+  void _tryFilter() {
+    if (_status == closedStatus) {
+      return;
+    }
+    if (_filterPending && !_filterActive) {
+      _filterActive = true;
+      _filterPending = false;
+      _pushAllFilterStages().then((status) {
+        _filterStatus = status;
+        _filterActive = false;
+        if (_status == closedStatus) {
+          _secureFilter.destroy();
+          _secureFilter = null;
+          return;
+        }
+        _socket.readEventsEnabled = true;
+        if (_filterStatus.writeEmpty && _closedWrite && !_socketClosedWrite) {
+          // Checks for and handles all cases of partially closed sockets.
+          shutdown(SocketDirection.send);
+          if (_status == closedStatus) {
+            return;
+          }
+        }
+        if (_filterStatus.readEmpty && _socketClosedRead && !_closedRead) {
+          if (_status == handshakeStatus) {
+            _secureFilter.handshake();
+            if (_status == handshakeStatus) {
+              throw new HandshakeException(
+                  'Connection terminated during handshake');
+            }
+          }
+          _closeHandler();
+        }
+        if (_status == closedStatus) {
+          return;
+        }
+        if (_filterStatus.progress) {
+          _filterPending = true;
+          if (_filterStatus.writeEncryptedNoLongerEmpty) {
+            _writeSocket();
+          }
+          if (_filterStatus.writePlaintextNoLongerFull) {
+            _sendWriteEvent();
+          }
+          if (_filterStatus.readEncryptedNoLongerFull) {
+            _readSocket();
+          }
+          if (_filterStatus.readPlaintextNoLongerEmpty) {
+            _scheduleReadEvent();
+          }
+          if (_status == handshakeStatus) {
+            _secureHandshake();
+          }
+        }
+        _tryFilter();
+      }).catchError(_reportError);
+    }
+  }
+
+  List<int> _readSocketOrBufferedData(int bytes) {
+    if (_bufferedData != null) {
+      if (bytes > _bufferedData.length - _bufferedDataIndex) {
+        bytes = _bufferedData.length - _bufferedDataIndex;
+      }
+      var result =
+          _bufferedData.sublist(_bufferedDataIndex, _bufferedDataIndex + bytes);
+      _bufferedDataIndex += bytes;
+      if (_bufferedData.length == _bufferedDataIndex) {
+        _bufferedData = null;
+      }
+      return result;
+    } else if (!_socketClosedRead) {
+      return _socket.read(bytes);
+    } else {
+      return null;
+    }
+  }
+
+  void _readSocket() {
+    if (_status == closedStatus) return;
+    var buffer = _secureFilter.buffers[readEncryptedId];
+    if (buffer.writeFromSource(_readSocketOrBufferedData) > 0) {
+      _filterStatus.readEmpty = false;
+    } else {
+      _socket.readEventsEnabled = false;
+    }
+  }
+
+  void _writeSocket() {
+    if (_socketClosedWrite) return;
+    var buffer = _secureFilter.buffers[writeEncryptedId];
+    if (buffer.readToSocket(_socket)) {
+      // Returns true if blocked
+      _socket.writeEventsEnabled = true;
+    }
+  }
+
+  // If a read event should be sent, add it to the controller.
+  _scheduleReadEvent() {
+    if (!_pendingReadEvent &&
+        _readEventsEnabled &&
+        _pauseCount == 0 &&
+        _secureFilter != null &&
+        !_secureFilter.buffers[readPlaintextId].isEmpty) {
+      _pendingReadEvent = true;
+      Timer.run(_sendReadEvent);
+    }
+  }
+
+  _sendReadEvent() {
+    _pendingReadEvent = false;
+    if (_status != closedStatus &&
+        _readEventsEnabled &&
+        _pauseCount == 0 &&
+        _secureFilter != null &&
+        !_secureFilter.buffers[readPlaintextId].isEmpty) {
+      _controller.add(RawSocketEvent.read);
+      _scheduleReadEvent();
+    }
+  }
+
+  // If a write event should be sent, add it to the controller.
+  _sendWriteEvent() {
+    if (!_closedWrite &&
+        _writeEventsEnabled &&
+        _pauseCount == 0 &&
+        _secureFilter != null &&
+        _secureFilter.buffers[writePlaintextId].free > 0) {
+      _writeEventsEnabled = false;
+      _controller.add(RawSocketEvent.write);
+    }
+  }
+
+  Future<_FilterStatus> _pushAllFilterStages() {
+    bool wasInHandshake = _status != connectedStatus;
+    List args = new List(2 + bufferCount * 2);
+    args[0] = _secureFilter._pointer();
+    args[1] = wasInHandshake;
+    var bufs = _secureFilter.buffers;
+    for (var i = 0; i < bufferCount; ++i) {
+      args[2 * i + 2] = bufs[i].start;
+      args[2 * i + 3] = bufs[i].end;
+    }
+
+    return _IOService._dispatch(_IOService.sslProcessFilter, args)
+        .then((response) {
+      if (response.length == 2) {
+        if (wasInHandshake) {
+          // If we're in handshake, throw a handshake error.
+          _reportError(
+              new HandshakeException('${response[1]} error ${response[0]}'),
+              null);
+        } else {
+          // If we're connected, throw a TLS error.
+          _reportError(
+              new TlsException('${response[1]} error ${response[0]}'), null);
+        }
+      }
+      int start(int index) => response[2 * index];
+      int end(int index) => response[2 * index + 1];
+
+      _FilterStatus status = new _FilterStatus();
+      // Compute writeEmpty as "write plaintext buffer and write encrypted
+      // buffer were empty when we started and are empty now".
+      status.writeEmpty = bufs[writePlaintextId].isEmpty &&
+          start(writeEncryptedId) == end(writeEncryptedId);
+      // If we were in handshake when this started, _writeEmpty may be false
+      // because the handshake wrote data after we checked.
+      if (wasInHandshake) status.writeEmpty = false;
+
+      // Compute readEmpty as "both read buffers were empty when we started
+      // and are empty now".
+      status.readEmpty = bufs[readEncryptedId].isEmpty &&
+          start(readPlaintextId) == end(readPlaintextId);
+
+      _ExternalBuffer buffer = bufs[writePlaintextId];
+      int new_start = start(writePlaintextId);
+      if (new_start != buffer.start) {
+        status.progress = true;
+        if (buffer.free == 0) {
+          status.writePlaintextNoLongerFull = true;
+        }
+        buffer.start = new_start;
+      }
+      buffer = bufs[readEncryptedId];
+      new_start = start(readEncryptedId);
+      if (new_start != buffer.start) {
+        status.progress = true;
+        if (buffer.free == 0) {
+          status.readEncryptedNoLongerFull = true;
+        }
+        buffer.start = new_start;
+      }
+      buffer = bufs[writeEncryptedId];
+      int new_end = end(writeEncryptedId);
+      if (new_end != buffer.end) {
+        status.progress = true;
+        if (buffer.length == 0) {
+          status.writeEncryptedNoLongerEmpty = true;
+        }
+        buffer.end = new_end;
+      }
+      buffer = bufs[readPlaintextId];
+      new_end = end(readPlaintextId);
+      if (new_end != buffer.end) {
+        status.progress = true;
+        if (buffer.length == 0) {
+          status.readPlaintextNoLongerEmpty = true;
+        }
+        buffer.end = new_end;
+      }
+      return status;
+    });
+  }
+}
+
+/**
+ * A circular buffer backed by an external byte array.  Accessed from
+ * both C++ and Dart code in an unsynchronized way, with one reading
+ * and one writing.  All updates to start and end are done by Dart code.
+ */
+class _ExternalBuffer {
+  // This will be an ExternalByteArray, backed by C allocated data.
+  @pragma("vm:entry-point", "set")
+  List<int> data;
+
+  @pragma("vm:entry-point")
+  int start;
+
+  @pragma("vm:entry-point")
+  int end;
+
+  final size;
+
+  _ExternalBuffer(this.size) {
+    start = end = size ~/ 2;
+  }
+
+  void advanceStart(int bytes) {
+    assert(start > end || start + bytes <= end);
+    start += bytes;
+    if (start >= size) {
+      start -= size;
+      assert(start <= end);
+      assert(start < size);
+    }
+  }
+
+  void advanceEnd(int bytes) {
+    assert(start <= end || start > end + bytes);
+    end += bytes;
+    if (end >= size) {
+      end -= size;
+      assert(end < start);
+      assert(end < size);
+    }
+  }
+
+  bool get isEmpty => end == start;
+
+  int get length => start > end ? size + end - start : end - start;
+
+  int get linearLength => start > end ? size - start : end - start;
+
+  int get free => start > end ? start - end - 1 : size + start - end - 1;
+
+  int get linearFree {
+    if (start > end) return start - end - 1;
+    if (start == 0) return size - end - 1;
+    return size - end;
+  }
+
+  Uint8List read(int bytes) {
+    if (bytes == null) {
+      bytes = length;
+    } else {
+      bytes = min(bytes, length);
+    }
+    if (bytes == 0) return null;
+    Uint8List result = new Uint8List(bytes);
+    int bytesRead = 0;
+    // Loop over zero, one, or two linear data ranges.
+    while (bytesRead < bytes) {
+      int toRead = min(bytes - bytesRead, linearLength);
+      result.setRange(bytesRead, bytesRead + toRead, data, start);
+      advanceStart(toRead);
+      bytesRead += toRead;
+    }
+    return result;
+  }
+
+  int write(List<int> inputData, int offset, int bytes) {
+    if (bytes > free) {
+      bytes = free;
+    }
+    int written = 0;
+    int toWrite = min(bytes, linearFree);
+    // Loop over zero, one, or two linear data ranges.
+    while (toWrite > 0) {
+      data.setRange(end, end + toWrite, inputData, offset);
+      advanceEnd(toWrite);
+      offset += toWrite;
+      written += toWrite;
+      toWrite = min(bytes - written, linearFree);
+    }
+    return written;
+  }
+
+  int writeFromSource(List<int> getData(int requested)) {
+    int written = 0;
+    int toWrite = linearFree;
+    // Loop over zero, one, or two linear data ranges.
+    while (toWrite > 0) {
+      // Source returns at most toWrite bytes, and it returns null when empty.
+      var inputData = getData(toWrite);
+      if (inputData == null || inputData.length == 0) break;
+      var len = inputData.length;
+      data.setRange(end, end + len, inputData);
+      advanceEnd(len);
+      written += len;
+      toWrite = linearFree;
+    }
+    return written;
+  }
+
+  bool readToSocket(RawSocket socket) {
+    // Loop over zero, one, or two linear data ranges.
+    while (true) {
+      var toWrite = linearLength;
+      if (toWrite == 0) return false;
+      int bytes = socket.write(data, start, toWrite);
+      advanceStart(bytes);
+      if (bytes < toWrite) {
+        // The socket has blocked while we have data to write.
+        return true;
+      }
+    }
+  }
+}
+
+abstract class _SecureFilter {
+  external factory _SecureFilter._();
+
+  void connect(
+      String hostName,
+      SecurityContext context,
+      bool is_server,
+      bool requestClientCertificate,
+      bool requireClientCertificate,
+      Uint8List protocols);
+  void destroy();
+  void handshake();
+  String selectedProtocol();
+  void rehandshake();
+  void renegotiate(bool useSessionCache, bool requestClientCertificate,
+      bool requireClientCertificate);
+  void init();
+  X509Certificate get peerCertificate;
+  int processBuffer(int bufferIndex);
+  void registerBadCertificateCallback(Function callback);
+  void registerHandshakeCompleteCallback(Function handshakeCompleteHandler);
+
+  // This call may cause a reference counted pointer in the native
+  // implementation to be retained. It should only be called when the resulting
+  // value is passed to the IO service through a call to dispatch().
+  int _pointer();
+
+  List<_ExternalBuffer> get buffers;
+}
+
+/** A secure networking exception caused by a failure in the
+ *  TLS/SSL protocol.
+ */
+class TlsException implements IOException {
+  final String type;
+  final String message;
+  final OSError osError;
+
+  @pragma("vm:entry-point")
+  const TlsException([String message = "", OSError osError])
+      : this._("TlsException", message, osError);
+
+  const TlsException._(this.type, this.message, this.osError);
+
+  String toString() {
+    StringBuffer sb = new StringBuffer();
+    sb.write(type);
+    if (message.isNotEmpty) {
+      sb.write(": $message");
+      if (osError != null) {
+        sb.write(" ($osError)");
+      }
+    } else if (osError != null) {
+      sb.write(": $osError");
+    }
+    return sb.toString();
+  }
+}
+
+/**
+ * An exception that happens in the handshake phase of establishing
+ * a secure network connection.
+ */
+@pragma("vm:entry-point")
+class HandshakeException extends TlsException {
+  @pragma("vm:entry-point")
+  const HandshakeException([String message = "", OSError osError])
+      : super._("HandshakeException", message, osError);
+}
+
+/**
+ * An exception that happens in the handshake phase of establishing
+ * a secure network connection, when looking up or verifying a
+ * certificate.
+ */
+class CertificateException extends TlsException {
+  @pragma("vm:entry-point")
+  const CertificateException([String message = "", OSError osError])
+      : super._("CertificateException", message, osError);
+}
diff --git a/sdk_nnbd/lib/io/security_context.dart b/sdk_nnbd/lib/io/security_context.dart
new file mode 100644
index 0000000..96da93b
--- /dev/null
+++ b/sdk_nnbd/lib/io/security_context.dart
@@ -0,0 +1,283 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.io;
+
+/**
+ * The object containing the certificates to trust when making
+ * a secure client connection, and the certificate chain and
+ * private key to serve from a secure server.
+ *
+ * The [SecureSocket]  and [SecureServerSocket] classes take a SecurityContext
+ * as an argument to their connect and bind methods.
+ *
+ * Certificates and keys can be added to a SecurityContext from either PEM
+ * or PKCS12 containers.
+ *
+ * iOS note: Some methods to add, remove, and inspect certificates are not yet
+ * implemented. However, the platform's built-in trusted certificates can
+ * be used, by way of [SecurityContext.defaultContext].
+ */
+abstract class SecurityContext {
+  /**
+   * Creates a new [SecurityContext].
+   *
+   * By default, the created [SecurityContext] contains no keys or certificates.
+   * These can be added by calling the methods of this class.
+   *
+   * If `withTrustedRoots` is passed as `true`, the [SecurityContext] will be
+   * seeded by the trusted root certificates provided as explained below. To
+   * obtain a [SecurityContext] containing trusted root certificates,
+   * [SecurityContext.defaultContext] is usually sufficient, and should
+   * be used instead. However, if the [SecurityContext] containing the trusted
+   * root certificates must be modified per-connection, then `withTrustedRoots`
+   * should be used.
+   */
+  external factory SecurityContext({bool withTrustedRoots: false});
+
+  /**
+   * Secure networking classes with an optional `context` parameter
+   * use the [defaultContext] object if the parameter is omitted.
+   * This object can also be accessed, and modified, directly.
+   * Each isolate has a different [defaultContext] object.
+   * The [defaultContext] object uses a list of well-known trusted
+   * certificate authorities as its trusted roots. On Linux and Windows, this
+   * list is taken from Mozilla, who maintains it as part of Firefox. On,
+   * MacOS, iOS, and Android, this list comes from the trusted certificates
+   * stores built in to the platforms.
+   */
+  external static SecurityContext get defaultContext;
+
+  /**
+   * Sets the private key for a server certificate or client certificate.
+   *
+   * A secure connection using this SecurityContext will use this key with
+   * the server or client certificate to sign and decrypt messages.
+   * [file] is the path to a PEM or PKCS12 file containing an encrypted
+   * private key, encrypted with [password]. Assuming it is well-formatted, all
+   * other contents of [file] are ignored. An unencrypted file can be used,
+   * but this is not usual.
+   *
+   * NB: This function calls [File.readAsBytesSync], and will block on file IO.
+   * Prefer using [usePrivateKeyBytes].
+   *
+   * iOS note: Only PKCS12 data is supported. It should contain both the private
+   * key and the certificate chain. On iOS one call to [usePrivateKey] with this
+   * data is used instead of two calls to [useCertificateChain] and
+   * [usePrivateKey].
+   */
+  void usePrivateKey(String file, {String password});
+
+  /**
+   * Sets the private key for a server certificate or client certificate.
+   *
+   * Like [usePrivateKey], but takes the contents of the file as a list
+   * of bytes.
+   */
+  void usePrivateKeyBytes(List<int> keyBytes, {String password});
+
+  /**
+   * Sets the set of trusted X509 certificates used by [SecureSocket]
+   * client connections, when connecting to a secure server.
+   *
+   * [file] is the path to a PEM or PKCS12 file containing X509 certificates,
+   * usually root certificates from certificate authorities. For PKCS12 files,
+   * [password] is the password for the file. For PEM files, [password] is
+   * ignored. Assuming it is well-formatted, all other contents of [file] are
+   * ignored.
+   *
+   * NB: This function calls [File.readAsBytesSync], and will block on file IO.
+   * Prefer using [setTrustedCertificatesBytes].
+   *
+   * iOS note: On iOS, this call takes only the bytes for a single DER
+   * encoded X509 certificate. It may be called multiple times to add
+   * multiple trusted certificates to the context. A DER encoded certificate
+   * can be obtained from a PEM encoded certificate by using the openssl tool:
+   *
+   *   $ openssl x509 -outform der -in cert.pem -out cert.der
+   */
+  void setTrustedCertificates(String file, {String password});
+
+  /**
+   * Sets the set of trusted X509 certificates used by [SecureSocket]
+   * client connections, when connecting to a secure server.
+   *
+   * Like [setTrustedCertificates] but takes the contents of the file.
+   */
+  void setTrustedCertificatesBytes(List<int> certBytes, {String password});
+
+  /**
+   * Sets the chain of X509 certificates served by [SecureServerSocket]
+   * when making secure connections, including the server certificate.
+   *
+   * [file] is a PEM or PKCS12 file containing X509 certificates, starting with
+   * the root authority and intermediate authorities forming the signed
+   * chain to the server certificate, and ending with the server certificate.
+   * The private key for the server certificate is set by [usePrivateKey]. For
+   * PKCS12 files, [password] is the password for the file. For PEM files,
+   * [password] is ignored. Assuming it is well-formatted, all
+   * other contents of [file] are ignored.
+   *
+   * NB: This function calls [File.readAsBytesSync], and will block on file IO.
+   * Prefer using [useCertificateChainBytes].
+   *
+   * iOS note: As noted above, [usePrivateKey] does the job of both
+   * that call and this one. On iOS, this call is a no-op.
+   */
+  void useCertificateChain(String file, {String password});
+
+  /**
+   * Sets the chain of X509 certificates served by [SecureServerSocket]
+   * when making secure connections, including the server certificate.
+   *
+   * Like [useCertificateChain] but takes the contents of the file.
+   */
+  void useCertificateChainBytes(List<int> chainBytes, {String password});
+
+  /**
+   * Sets the list of authority names that a [SecureServerSocket] will advertise
+   * as accepted when requesting a client certificate from a connecting
+   * client.
+   *
+   * [file] is a PEM or PKCS12 file containing the accepted signing
+   * authority certificates - the authority names are extracted from the
+   * certificates. For PKCS12 files, [password] is the password for the file.
+   * For PEM files, [password] is ignored. Assuming it is well-formatted, all
+   * other contents of [file] are ignored.
+   *
+   * NB: This function calls [File.readAsBytesSync], and will block on file IO.
+   * Prefer using [setClientAuthoritiesBytes].
+   *
+   * iOS note: This call is not supported.
+   */
+  void setClientAuthorities(String file, {String password});
+
+  /**
+   * Sets the list of authority names that a [SecureServerSocket] will advertise
+   * as accepted, when requesting a client certificate from a connecting
+   * client.
+   *
+   * Like [setClientAuthorities] but takes the contents of the file.
+   */
+  void setClientAuthoritiesBytes(List<int> authCertBytes, {String password});
+
+  /**
+   * Whether the platform supports ALPN. This always returns true and will be
+   * removed in a future release.
+   */
+  @deprecated
+  external static bool get alpnSupported;
+
+  /**
+   * Sets the list of application-level protocols supported by a client
+   * connection or server connection. The ALPN (application level protocol
+   * negotiation) extension to TLS allows a client to send a list of
+   * protocols in the TLS client hello message, and the server to pick
+   * one and send the selected one back in its server hello message.
+   *
+   * Separate lists of protocols can be sent for client connections and
+   * for server connections, using the same SecurityContext.  The [isServer]
+   * boolean argument specifies whether to set the list for server connections
+   * or client connections.
+   */
+  void setAlpnProtocols(List<String> protocols, bool isServer);
+
+  /// Encodes a set of supported protocols for ALPN/NPN usage.
+  ///
+  /// The `protocols` list is expected to contain protocols in descending order
+  /// of preference.
+  ///
+  /// See RFC 7301 (https://tools.ietf.org/html/rfc7301) for the encoding of
+  /// `List<String> protocols`:
+  ///     opaque ProtocolName<1..2^8-1>;
+  ///
+  ///     struct {
+  ///         ProtocolName protocol_name_list<2..2^16-1>
+  ///     } ProtocolNameList;
+  ///
+  /// The encoding of the opaque `ProtocolName<lower..upper>` vector is
+  /// described in RFC 2246: 4.3 Vectors.
+  ///
+  /// Note: Even though this encoding scheme would allow a total
+  /// `ProtocolNameList` length of 65535, this limit cannot be reached. Testing
+  /// showed that more than ~ 2^14  bytes will fail to negotiate a protocol.
+  /// We will be conservative and support only messages up to (1<<13)-1 bytes.
+  static Uint8List _protocolsToLengthEncoding(List<String> protocols) {
+    if (protocols == null || protocols.length == 0) {
+      return new Uint8List(0);
+    }
+    int protocolsLength = protocols.length;
+
+    // Calculate the number of bytes we will need if it is ASCII.
+    int expectedLength = protocolsLength;
+    for (int i = 0; i < protocolsLength; i++) {
+      int length = protocols[i].length;
+      if (length > 0 && length <= 255) {
+        expectedLength += length;
+      } else {
+        throw new ArgumentError(
+            'Length of protocol must be between 1 and 255 (was: $length).');
+      }
+    }
+
+    if (expectedLength >= (1 << 13)) {
+      throw new ArgumentError(
+          'The maximum message length supported is 2^13-1.');
+    }
+
+    // Try encoding the `List<String> protocols` array using fast ASCII path.
+    var bytes = new Uint8List(expectedLength);
+    int bytesOffset = 0;
+    for (int i = 0; i < protocolsLength; i++) {
+      String proto = protocols[i];
+
+      // Add length byte.
+      bytes[bytesOffset++] = proto.length;
+      int bits = 0;
+
+      // Add protocol bytes.
+      for (int j = 0; j < proto.length; j++) {
+        var char = proto.codeUnitAt(j);
+        bits |= char;
+        bytes[bytesOffset++] = char & 0xff;
+      }
+
+      // Go slow case if we have encountered anything non-ascii.
+      if (bits > 0x7f) {
+        return _protocolsToLengthEncodingNonAsciiBailout(protocols);
+      }
+    }
+    return bytes;
+  }
+
+  static Uint8List _protocolsToLengthEncodingNonAsciiBailout(
+      List<String> protocols) {
+    void addProtocol(List<int> outBytes, String protocol) {
+      var protocolBytes = utf8.encode(protocol);
+      var len = protocolBytes.length;
+
+      if (len > 255) {
+        throw new ArgumentError(
+            'Length of protocol must be between 1 and 255 (was: $len)');
+      }
+      // Add length byte.
+      outBytes.add(len);
+
+      // Add protocol bytes.
+      outBytes.addAll(protocolBytes);
+    }
+
+    List<int> bytes = [];
+    for (var i = 0; i < protocols.length; i++) {
+      addProtocol(bytes, protocols[i]);
+    }
+
+    if (bytes.length >= (1 << 13)) {
+      throw new ArgumentError(
+          'The maximum message length supported is 2^13-1.');
+    }
+
+    return new Uint8List.fromList(bytes);
+  }
+}
diff --git a/sdk_nnbd/lib/io/service_object.dart b/sdk_nnbd/lib/io/service_object.dart
new file mode 100644
index 0000000..e6b1851
--- /dev/null
+++ b/sdk_nnbd/lib/io/service_object.dart
@@ -0,0 +1,29 @@
+// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.io;
+
+int _nextServiceId = 1;
+
+// TODO(ajohnsen): Use other way of getting a unique id.
+abstract class _ServiceObject {
+  int __serviceId = 0;
+  int get _serviceId {
+    if (__serviceId == 0) __serviceId = _nextServiceId++;
+    return __serviceId;
+  }
+
+  Map _toJSON(bool ref);
+
+  String get _servicePath => "$_serviceTypePath/$_serviceId";
+
+  String get _serviceTypePath;
+
+  String get _serviceTypeName;
+
+  String _serviceType(bool ref) {
+    if (ref) return "@$_serviceTypeName";
+    return _serviceTypeName;
+  }
+}
diff --git a/sdk_nnbd/lib/io/socket.dart b/sdk_nnbd/lib/io/socket.dart
new file mode 100644
index 0000000..df60490
--- /dev/null
+++ b/sdk_nnbd/lib/io/socket.dart
@@ -0,0 +1,1013 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.io;
+
+/**
+ * [InternetAddressType] is the type an [InternetAddress]. Currently,
+ * IP version 4 (IPv4) and IP version 6 (IPv6) are supported.
+ */
+class InternetAddressType {
+  static const InternetAddressType IPv4 = const InternetAddressType._(0);
+  static const InternetAddressType IPv6 = const InternetAddressType._(1);
+  static const InternetAddressType any = const InternetAddressType._(-1);
+
+  @Deprecated("Use IPv4 instead")
+  static const InternetAddressType IP_V4 = IPv4;
+  @Deprecated("Use IPv6 instead")
+  static const InternetAddressType IP_V6 = IPv6;
+  @Deprecated("Use any instead")
+  static const InternetAddressType ANY = any;
+
+  final int _value;
+
+  const InternetAddressType._(this._value);
+
+  factory InternetAddressType._from(int value) {
+    if (value == 0) return IPv4;
+    if (value == 1) return IPv6;
+    throw new ArgumentError("Invalid type: $value");
+  }
+
+  /**
+   * Get the name of the type, e.g. "IPv4" or "IPv6".
+   */
+  String get name {
+    switch (_value) {
+      case -1:
+        return "ANY";
+      case 0:
+        return "IPv4";
+      case 1:
+        return "IPv6";
+      default:
+        throw new ArgumentError("Invalid InternetAddress");
+    }
+  }
+
+  String toString() => "InternetAddressType: $name";
+}
+
+/**
+ * An internet address.
+ *
+ * This object holds an internet address. If this internet address
+ * is the result of a DNS lookup, the address also holds the hostname
+ * used to make the lookup.
+ * An Internet address combined with a port number represents an
+ * endpoint to which a socket can connect or a listening socket can
+ * bind.
+ */
+abstract class InternetAddress {
+  /**
+   * IP version 4 loopback address. Use this address when listening on
+   * or connecting to the loopback adapter using IP version 4 (IPv4).
+   */
+  static InternetAddress get loopbackIPv4 => LOOPBACK_IP_V4;
+  @Deprecated("Use loopbackIPv4 instead")
+  external static InternetAddress get LOOPBACK_IP_V4;
+
+  /**
+   * IP version 6 loopback address. Use this address when listening on
+   * or connecting to the loopback adapter using IP version 6 (IPv6).
+   */
+  static InternetAddress get loopbackIPv6 => LOOPBACK_IP_V6;
+  @Deprecated("Use loopbackIPv6 instead")
+  external static InternetAddress get LOOPBACK_IP_V6;
+
+  /**
+   * IP version 4 any address. Use this address when listening on
+   * all adapters IP addresses using IP version 4 (IPv4).
+   */
+  static InternetAddress get anyIPv4 => ANY_IP_V4;
+  @Deprecated("Use anyIPv4 instead")
+  external static InternetAddress get ANY_IP_V4;
+
+  /**
+   * IP version 6 any address. Use this address when listening on
+   * all adapters IP addresses using IP version 6 (IPv6).
+   */
+  static InternetAddress get anyIPv6 => ANY_IP_V6;
+  @Deprecated("Use anyIPv6 instead")
+  external static InternetAddress get ANY_IP_V6;
+
+  /**
+   * The [type] of the [InternetAddress] specified what IP protocol.
+   */
+  InternetAddressType get type;
+
+  /**
+   * The numeric address of the host. For IPv4 addresses this is using
+   * the dotted-decimal notation. For IPv6 it is using the
+   * hexadecimal representation.
+   */
+  String get address;
+
+  /**
+   * The host used to lookup the address. If there is no host
+   * associated with the address this returns the numeric address.
+   */
+  String get host;
+
+  /**
+   * Get the raw address of this [InternetAddress]. The result is either a
+   * 4 or 16 byte long list. The returned list is a copy, making it possible
+   * to change the list without modifying the [InternetAddress].
+   */
+  Uint8List get rawAddress;
+
+  /**
+   * Returns true if the [InternetAddress] is a loopback address.
+   */
+  bool get isLoopback;
+
+  /**
+   * Returns true if the [InternetAddress]s scope is a link-local.
+   */
+  bool get isLinkLocal;
+
+  /**
+   * Returns true if the [InternetAddress]s scope is multicast.
+   */
+  bool get isMulticast;
+
+  /**
+   * Creates a new [InternetAddress] from a numeric address.
+   *
+   * If the address in [address] is not a numeric IPv4
+   * (dotted-decimal notation) or IPv6 (hexadecimal representation).
+   * address [ArgumentError] is thrown.
+   */
+  external factory InternetAddress(String address);
+
+  /**
+   * Perform a reverse dns lookup on the [address], creating a new
+   * [InternetAddress] where the host field set to the result.
+   */
+  Future<InternetAddress> reverse();
+
+  /**
+   * Lookup a host, returning a Future of a list of
+   * [InternetAddress]s. If [type] is [InternetAddressType.ANY], it
+   * will lookup both IP version 4 (IPv4) and IP version 6 (IPv6)
+   * addresses. If [type] is either [InternetAddressType.IPv4] or
+   * [InternetAddressType.IPv6] it will only lookup addresses of the
+   * specified type. The order of the list can, and most likely will,
+   * change over time.
+   */
+  external static Future<List<InternetAddress>> lookup(String host,
+      {InternetAddressType type: InternetAddressType.any});
+
+  /**
+   * Clones the given [address] with the new [host].
+   *
+   * The [address] must be an [InternetAddress] that was created with one
+   * of the static methods of this class.
+   */
+  external static InternetAddress _cloneWithNewHost(
+      InternetAddress address, String host);
+}
+
+/**
+ * A [NetworkInterface] represents an active network interface on the current
+ * system. It contains a list of [InternetAddress]es that are bound to the
+ * interface.
+ */
+abstract class NetworkInterface {
+  /**
+   * Get the name of the [NetworkInterface].
+   */
+  String get name;
+
+  /**
+   * Get the index of the [NetworkInterface].
+   */
+  int get index;
+
+  /**
+   * Get a list of [InternetAddress]es currently bound to this
+   * [NetworkInterface].
+   */
+  List<InternetAddress> get addresses;
+
+  /**
+   * Whether [list] is supported.
+   *
+   * [list] is currently unsupported on Android.
+   */
+  external static bool get listSupported;
+
+  /**
+   * Query the system for [NetworkInterface]s.
+   *
+   * If [includeLoopback] is `true`, the returned list will include the
+   * loopback device. Default is `false`.
+   *
+   * If [includeLinkLocal] is `true`, the list of addresses of the returned
+   * [NetworkInterface]s, may include link local addresses. Default is `false`.
+   *
+   * If [type] is either [InternetAddressType.IPv4] or
+   * [InternetAddressType.IPv6] it will only lookup addresses of the
+   * specified type. Default is [InternetAddressType.any].
+   */
+  external static Future<List<NetworkInterface>> list(
+      {bool includeLoopback: false,
+      bool includeLinkLocal: false,
+      InternetAddressType type: InternetAddressType.any});
+}
+
+/**
+ * A [RawServerSocket] represents a listening socket, and provides a
+ * stream of low-level [RawSocket] objects, one for each connection
+ * made to the listening socket.
+ *
+ * See [RawSocket] for more info.
+ */
+abstract class RawServerSocket implements Stream<RawSocket> {
+  /**
+   * Returns a future for a [:RawServerSocket:]. When the future
+   * completes the server socket is bound to the given [address] and
+   * [port] and has started listening on it.
+   *
+   * The [address] can either be a [String] or an
+   * [InternetAddress]. If [address] is a [String], [bind] will
+   * perform a [InternetAddress.lookup] and use the first value in the
+   * list. To listen on the loopback adapter, which will allow only
+   * incoming connections from the local host, use the value
+   * [InternetAddress.loopbackIPv4] or
+   * [InternetAddress.loopbackIPv6]. To allow for incoming
+   * connection from the network use either one of the values
+   * [InternetAddress.anyIPv4] or [InternetAddress.anyIPv6] to
+   * bind to all interfaces or the IP address of a specific interface.
+   *
+   * If an IP version 6 (IPv6) address is used, both IP version 6
+   * (IPv6) and version 4 (IPv4) connections will be accepted. To
+   * restrict this to version 6 (IPv6) only, use [v6Only] to set
+   * version 6 only.
+   *
+   * If [port] has the value [:0:] an ephemeral port will
+   * be chosen by the system. The actual port used can be retrieved
+   * using the [:port:] getter.
+   *
+   * The optional argument [backlog] can be used to specify the listen
+   * backlog for the underlying OS listen setup. If [backlog] has the
+   * value of [:0:] (the default) a reasonable value will be chosen by
+   * the system.
+   *
+   * The optional argument [shared] specifies whether additional RawServerSocket
+   * objects can bind to the same combination of `address`, `port` and `v6Only`.
+   * If `shared` is `true` and more `RawServerSocket`s from this isolate or
+   * other isolates are bound to the port, then the incoming connections will be
+   * distributed among all the bound `RawServerSocket`s. Connections can be
+   * distributed over multiple isolates this way.
+   */
+  external static Future<RawServerSocket> bind(address, int port,
+      {int backlog: 0, bool v6Only: false, bool shared: false});
+
+  /**
+   * Returns the port used by this socket.
+   */
+  int get port;
+
+  /**
+   * Returns the address used by this socket.
+   */
+  InternetAddress get address;
+
+  /**
+   * Closes the socket. The returned future completes when the socket
+   * is fully closed and is no longer bound.
+   */
+  Future<RawServerSocket> close();
+}
+
+/**
+ * A [ServerSocket] represents a listening socket, and provides a
+ * stream of [Socket] objects, one for each connection made to the
+ * listening socket.
+ *
+ * See [Socket] for more info.
+ */
+abstract class ServerSocket implements Stream<Socket> {
+  /**
+   * Returns a future for a [:ServerSocket:]. When the future
+   * completes the server socket is bound to the given [address] and
+   * [port] and has started listening on it.
+   *
+   * The [address] can either be a [String] or an
+   * [InternetAddress]. If [address] is a [String], [bind] will
+   * perform a [InternetAddress.lookup] and use the first value in the
+   * list. To listen on the loopback adapter, which will allow only
+   * incoming connections from the local host, use the value
+   * [InternetAddress.loopbackIPv4] or
+   * [InternetAddress.loopbackIPv6]. To allow for incoming
+   * connection from the network use either one of the values
+   * [InternetAddress.anyIPv4] or [InternetAddress.anyIPv6] to
+   * bind to all interfaces or the IP address of a specific interface.
+   *
+   * If an IP version 6 (IPv6) address is used, both IP version 6
+   * (IPv6) and version 4 (IPv4) connections will be accepted. To
+   * restrict this to version 6 (IPv6) only, use [v6Only] to set
+   * version 6 only.
+   *
+   * If [port] has the value [:0:] an ephemeral port will be chosen by
+   * the system. The actual port used can be retrieved using the
+   * [port] getter.
+   *
+   * The optional argument [backlog] can be used to specify the listen
+   * backlog for the underlying OS listen setup. If [backlog] has the
+   * value of [:0:] (the default) a reasonable value will be chosen by
+   * the system.
+   *
+   * The optional argument [shared] specifies whether additional ServerSocket
+   * objects can bind to the same combination of `address`, `port` and `v6Only`.
+   * If `shared` is `true` and more `ServerSocket`s from this isolate or other
+   * isolates are bound to the port, then the incoming connections will be
+   * distributed among all the bound `ServerSocket`s. Connections can be
+   * distributed over multiple isolates this way.
+   */
+  external static Future<ServerSocket> bind(address, int port,
+      {int backlog: 0, bool v6Only: false, bool shared: false});
+
+  /**
+   * Returns the port used by this socket.
+   */
+  int get port;
+
+  /**
+   * Returns the address used by this socket.
+   */
+  InternetAddress get address;
+
+  /**
+   * Closes the socket. The returned future completes when the socket
+   * is fully closed and is no longer bound.
+   */
+  Future<ServerSocket> close();
+}
+
+/**
+ * The [SocketDirection] is used as a parameter to [Socket.close] and
+ * [RawSocket.close] to close a socket in the specified direction(s).
+ */
+class SocketDirection {
+  static const SocketDirection receive = const SocketDirection._(0);
+  static const SocketDirection send = const SocketDirection._(1);
+  static const SocketDirection both = const SocketDirection._(2);
+
+  @Deprecated("Use receive instead")
+  static const SocketDirection RECEIVE = receive;
+  @Deprecated("Use send instead")
+  static const SocketDirection SEND = send;
+  @Deprecated("Use both instead")
+  static const SocketDirection BOTH = both;
+
+  final _value;
+
+  const SocketDirection._(this._value);
+}
+
+/**
+ * The [SocketOption] is used as a parameter to [Socket.setOption] and
+ * [RawSocket.setOption] to set customize the behaviour of the underlying
+ * socket.
+ */
+class SocketOption {
+  /**
+   * Enable or disable no-delay on the socket. If tcpNoDelay is enabled, the
+   * socket will not buffer data internally, but instead write each data chunk
+   * as an individual TCP packet.
+   *
+   * tcpNoDelay is disabled by default.
+   */
+  static const SocketOption tcpNoDelay = const SocketOption._(0);
+  @Deprecated("Use tcpNoDelay instead")
+  static const SocketOption TCP_NODELAY = tcpNoDelay;
+
+  static const SocketOption _ipMulticastLoop = const SocketOption._(1);
+  static const SocketOption _ipMulticastHops = const SocketOption._(2);
+  static const SocketOption _ipMulticastIf = const SocketOption._(3);
+  static const SocketOption _ipBroadcast = const SocketOption._(4);
+
+  final _value;
+
+  const SocketOption._(this._value);
+}
+
+// Must be kept in sync with enum in socket.cc
+enum _RawSocketOptions {
+  SOL_SOCKET, // 0
+  IPPROTO_IP, // 1
+  IP_MULTICAST_IF, // 2
+  IPPROTO_IPV6, // 3
+  IPV6_MULTICAST_IF, // 4
+  IPPROTO_TCP, // 5
+  IPPROTO_UDP, // 6
+}
+
+/// The [RawSocketOption] is used as a parameter to [Socket.setRawOption] and
+/// [RawSocket.setRawOption] to set customize the behaviour of the underlying
+/// socket.
+///
+/// It allows for fine grained control of the socket options, and its values will
+/// be passed to the underlying platform's implementation of setsockopt and
+/// getsockopt.
+@Since("2.2")
+class RawSocketOption {
+  /// Creates a RawSocketOption for getRawOption andSetRawOption.
+  ///
+  /// All arguments are required and must not be null.
+  ///
+  /// The level and option arguments correspond to level and optname arguments
+  /// on the get/setsockopt native calls.
+  ///
+  /// The value argument and its length correspond to the optval and length
+  /// arguments on the native call.
+  ///
+  /// For a [getRawOption] call, the value parameter will be updated after a
+  /// successful call (although its length will not be changed).
+  ///
+  /// For a [setRawOption] call, the value parameter will be used set the
+  /// option.
+  const RawSocketOption(this.level, this.option, this.value);
+
+  /// Convenience constructor for creating an int based RawSocketOption.
+  factory RawSocketOption.fromInt(int level, int option, int value) {
+    if (value == null) {
+      value = 0;
+    }
+    final Uint8List list = Uint8List(4);
+    final buffer = ByteData.view(list.buffer);
+    buffer.setInt32(0, value);
+    return RawSocketOption(level, option, list);
+  }
+
+  /// Convenience constructor for creating a bool based RawSocketOption.
+  factory RawSocketOption.fromBool(int level, int option, bool value) =>
+      RawSocketOption.fromInt(level, option, value == true ? 1 : 0);
+
+  /// The level for the option to set or get.
+  ///
+  /// See also:
+  ///   * [RawSocketOption.levelSocket]
+  ///   * [RawSocketOption.levelIPv4]
+  ///   * [RawSocketOption.levelIPv6]
+  ///   * [RawSocketOption.levelTcp]
+  ///   * [RawSocketOption.levelUdp]
+  final int level;
+
+  /// The option to set or get.
+  final int option;
+
+  /// The raw data to set, or the array to write the current option value into.
+  ///
+  /// This list must be the correct length for the expected option. For most
+  /// options that take int or bool values, the length should be 4. For options
+  /// that expect a struct (such as an in_addr_t), the length should be the
+  /// correct length for that struct.
+  final Uint8List value;
+
+  /// Socket level option for SOL_SOCKET.
+  static int get levelSocket =>
+      _getOptionValue(_RawSocketOptions.SOL_SOCKET.index);
+
+  /// Socket level option for IPPROTO_IP.
+  static int get levelIPv4 =>
+      _getOptionValue(_RawSocketOptions.IPPROTO_IP.index);
+
+  /// Socket option for IP_MULTICAST_IF.
+  static int get IPv4MulticastInterface =>
+      _getOptionValue(_RawSocketOptions.IP_MULTICAST_IF.index);
+
+  /// Socket level option for IPPROTO_IPV6.
+  static int get levelIPv6 =>
+      _getOptionValue(_RawSocketOptions.IPPROTO_IPV6.index);
+
+  /// Socket option for IPV6_MULTICAST_IF.
+  static int get IPv6MulticastInterface =>
+      _getOptionValue(_RawSocketOptions.IPV6_MULTICAST_IF.index);
+
+  /// Socket level option for IPPROTO_TCP.
+  static int get levelTcp =>
+      _getOptionValue(_RawSocketOptions.IPPROTO_TCP.index);
+
+  /// Socket level option for IPPROTO_UDP.
+  static int get levelUdp =>
+      _getOptionValue(_RawSocketOptions.IPPROTO_UDP.index);
+
+  external static int _getOptionValue(int key);
+}
+
+/**
+ * Events for the [RawSocket].
+ */
+class RawSocketEvent {
+  static const RawSocketEvent read = const RawSocketEvent._(0);
+  static const RawSocketEvent write = const RawSocketEvent._(1);
+  static const RawSocketEvent readClosed = const RawSocketEvent._(2);
+  static const RawSocketEvent closed = const RawSocketEvent._(3);
+
+  @Deprecated("Use read instead")
+  static const RawSocketEvent READ = read;
+  @Deprecated("Use write instead")
+  static const RawSocketEvent WRITE = write;
+  @Deprecated("Use readClosed instead")
+  static const RawSocketEvent READ_CLOSED = readClosed;
+  @Deprecated("Use closed instead")
+  static const RawSocketEvent CLOSED = closed;
+
+  final int _value;
+
+  const RawSocketEvent._(this._value);
+  String toString() {
+    return const [
+      'RawSocketEvent.read',
+      'RawSocketEvent.write',
+      'RawSocketEvent.readClosed',
+      'RawSocketEvent.closed'
+    ][_value];
+  }
+}
+
+/// Returned by the `startConnect` methods on client-side socket types `S`,
+/// `ConnectionTask<S>` allows cancelling an attempt to connect to a host.
+class ConnectionTask<S> {
+  /// A `Future` that completes with value that `S.connect()` would return
+  /// unless [cancel] is called on this [ConnectionTask].
+  ///
+  /// If [cancel] is called, the `Future` completes with a [SocketException]
+  /// error whose message indicates that the connection attempt was cancelled.
+  final Future<S> socket;
+  final void Function() _onCancel;
+
+  ConnectionTask._({Future<S> socket, void Function() onCancel})
+      : assert(socket != null),
+        assert(onCancel != null),
+        this.socket = socket,
+        this._onCancel = onCancel;
+
+  /// Cancels the connection attempt.
+  ///
+  /// This also causes the [socket] `Future` to complete with a
+  /// [SocketException] error.
+  void cancel() {
+    _onCancel();
+  }
+}
+
+/**
+ * A [RawSocket] is an unbuffered interface to a TCP socket.
+ *
+ * The raw socket delivers the data stream in the same chunks as the underlying
+ * operating system.
+ *
+ * It is not the same as a
+ * [POSIX raw socket](http://man7.org/linux/man-pages/man7/raw.7.html).
+ */
+abstract class RawSocket implements Stream<RawSocketEvent> {
+  /**
+   * Set or get, if the [RawSocket] should listen for [RawSocketEvent.read]
+   * events. Default is [:true:].
+   */
+  bool readEventsEnabled;
+
+  /**
+   * Set or get, if the [RawSocket] should listen for [RawSocketEvent.write]
+   * events. Default is [:true:].
+   * This is a one-shot listener, and writeEventsEnabled must be set
+   * to true again to receive another write event.
+   */
+  bool writeEventsEnabled;
+
+  /**
+   * Creates a new socket connection to the host and port and returns a [Future]
+   * that will complete with either a [RawSocket] once connected or an error
+   * if the host-lookup or connection failed.
+   *
+   * [host] can either be a [String] or an [InternetAddress]. If [host] is a
+   * [String], [connect] will perform a [InternetAddress.lookup] and try
+   * all returned [InternetAddress]es, until connected. Unless a
+   * connection was established, the error from the first failing connection is
+   * returned.
+   *
+   * The argument [sourceAddress] can be used to specify the local
+   * address to bind when making the connection. `sourceAddress` can either
+   * be a `String` or an `InternetAddress`. If a `String` is passed it must
+   * hold a numeric IP address.
+   *
+   * The argument [timeout] is used to specify the maximum allowed time to wait
+   * for a connection to be established. If [timeout] is longer than the system
+   * level timeout duration, a timeout may occur sooner than specified in
+   * [timeout]. On timeout, a [SocketException] is thrown and all ongoing
+   * connection attempts to [host] are cancelled.
+   */
+  external static Future<RawSocket> connect(host, int port,
+      {sourceAddress, Duration timeout});
+
+  /// Like [connect], but returns a [Future] that completes with a
+  /// [ConnectionTask] that can be cancelled if the [RawSocket] is no
+  /// longer needed.
+  external static Future<ConnectionTask<RawSocket>> startConnect(host, int port,
+      {sourceAddress});
+
+  /**
+   * Returns the number of received and non-read bytes in the socket that
+   * can be read.
+   */
+  int available();
+
+  /**
+   * Read up to [len] bytes from the socket. This function is
+   * non-blocking and will only return data if data is available. The
+   * number of bytes read can be less then [len] if fewer bytes are
+   * available for immediate reading. If no data is available [:null:]
+   * is returned.
+   */
+  Uint8List read([int len]);
+
+  /**
+   * Writes up to [count] bytes of the buffer from [offset] buffer offset to
+   * the socket. The number of successfully written bytes is returned. This
+   * function is non-blocking and will only write data if buffer space is
+   * available in the socket.
+   *
+   * The default value for [offset] is 0, and the default value for [count] is
+   * [:buffer.length - offset:].
+   */
+  int write(List<int> buffer, [int offset, int count]);
+
+  /**
+   * Returns the port used by this socket.
+   */
+  int get port;
+
+  /**
+   * Returns the remote port connected to by this socket.
+   */
+  int get remotePort;
+
+  /**
+   * Returns the [InternetAddress] used to connect this socket.
+   */
+  InternetAddress get address;
+
+  /**
+   * Returns the remote [InternetAddress] connected to by this socket.
+   */
+  InternetAddress get remoteAddress;
+
+  /**
+   * Closes the socket. Returns a Future that completes with [this] when the
+   * underlying connection is completely destroyed.
+   *
+   * Calling [close] will never throw an exception
+   * and calling it several times is supported. Calling [close] can result in
+   * a [RawSocketEvent.readClosed] event.
+   */
+  Future<RawSocket> close();
+
+  /**
+   * Shutdown the socket in the [direction]. Calling [shutdown] will never
+   * throw an exception and calling it several times is supported. Calling
+   * shutdown with either [SocketDirection.both] or [SocketDirection.receive]
+   * can result in a [RawSocketEvent.readClosed] event.
+   */
+  void shutdown(SocketDirection direction);
+
+  /**
+   * Use [setOption] to customize the [RawSocket]. See [SocketOption] for
+   * available options.
+   *
+   * Returns [:true:] if the option was set successfully, false otherwise.
+   */
+  bool setOption(SocketOption option, bool enabled);
+
+  /**
+   * Use [getRawOption] to get low level information about the [RawSocket]. See
+   * [RawSocketOption] for available options.
+   *
+   * Returns the [RawSocketOption.value] on success.
+   *
+   * Throws an [OSError] on failure.
+   */
+  @Since("2.2")
+  Uint8List getRawOption(RawSocketOption option);
+
+  /**
+   * Use [setRawOption] to customize the [RawSocket]. See [RawSocketOption] for
+   * available options.
+   *
+   * Throws an [OSError] on failure.
+   */
+  @Since("2.2")
+  void setRawOption(RawSocketOption option);
+}
+
+/**
+ * A high-level class for communicating over a TCP socket.
+ *
+ * The [Socket] exposes both a [Stream] and a [IOSink] interface, making it
+ * ideal for using together with other [Stream]s.
+ */
+abstract class Socket implements Stream<Uint8List>, IOSink {
+  /**
+   * Creates a new socket connection to the host and port and returns a [Future]
+   * that will complete with either a [Socket] once connected or an error
+   * if the host-lookup or connection failed.
+   *
+   * [host] can either be a [String] or an [InternetAddress]. If [host] is a
+   * [String], [connect] will perform a [InternetAddress.lookup] and try
+   * all returned [InternetAddress]es, until connected. Unless a
+   * connection was established, the error from the first failing connection is
+   * returned.
+   *
+   * The argument [sourceAddress] can be used to specify the local
+   * address to bind when making the connection. `sourceAddress` can either
+   * be a `String` or an `InternetAddress`. If a `String` is passed it must
+   * hold a numeric IP address.
+   *
+   * The argument [timeout] is used to specify the maximum allowed time to wait
+   * for a connection to be established. If [timeout] is longer than the system
+   * level timeout duration, a timeout may occur sooner than specified in
+   * [timeout]. On timeout, a [SocketException] is thrown and all ongoing
+   * connection attempts to [host] are cancelled.
+   */
+  static Future<Socket> connect(host, int port,
+      {sourceAddress, Duration timeout}) {
+    final IOOverrides overrides = IOOverrides.current;
+    if (overrides == null) {
+      return Socket._connect(host, port,
+          sourceAddress: sourceAddress, timeout: timeout);
+    }
+    return overrides.socketConnect(host, port,
+        sourceAddress: sourceAddress, timeout: timeout);
+  }
+
+  /// Like [connect], but returns a [Future] that completes with a
+  /// [ConnectionTask] that can be cancelled if the [Socket] is no
+  /// longer needed.
+  static Future<ConnectionTask<Socket>> startConnect(host, int port,
+      {sourceAddress}) {
+    final IOOverrides overrides = IOOverrides.current;
+    if (overrides == null) {
+      return Socket._startConnect(host, port, sourceAddress: sourceAddress);
+    }
+    return overrides.socketStartConnect(host, port,
+        sourceAddress: sourceAddress);
+  }
+
+  external static Future<Socket> _connect(host, int port,
+      {sourceAddress, Duration timeout});
+
+  external static Future<ConnectionTask<Socket>> _startConnect(host, int port,
+      {sourceAddress});
+
+  /**
+   * Destroy the socket in both directions. Calling [destroy] will make the
+   * send a close event on the stream and will no longer react on data being
+   * piped to it.
+   *
+   * Call [close](inherited from [IOSink]) to only close the [Socket]
+   * for sending data.
+   */
+  void destroy();
+
+  /**
+   * Use [setOption] to customize the [RawSocket]. See [SocketOption] for
+   * available options.
+   *
+   * Returns [:true:] if the option was set successfully, false otherwise.
+   */
+  bool setOption(SocketOption option, bool enabled);
+
+  /**
+   * Use [getRawOption] to get low level information about the [RawSocket]. See
+   * [RawSocketOption] for available options.
+   *
+   * Returns the [RawSocketOption.value] on success.
+   *
+   * Throws an [OSError] on failure.
+   */
+  Uint8List getRawOption(RawSocketOption option);
+
+  /**
+   * Use [setRawOption] to customize the [RawSocket]. See [RawSocketOption] for
+   * available options.
+   *
+   * Throws an [OSError] on failure.
+   */
+  void setRawOption(RawSocketOption option);
+
+  /**
+   * Returns the port used by this socket.
+   */
+  int get port;
+
+  /**
+   * Returns the remote port connected to by this socket.
+   */
+  int get remotePort;
+
+  /**
+   * Returns the [InternetAddress] used to connect this socket.
+   */
+  InternetAddress get address;
+
+  /**
+   * Returns the remote [InternetAddress] connected to by this socket.
+   */
+  InternetAddress get remoteAddress;
+
+  Future close();
+
+  Future get done;
+}
+
+/**
+ * Datagram package. Data sent to and received from datagram sockets
+ * contains the internet address and port of the destination or source
+ * togeter with the data.
+ */
+class Datagram {
+  Uint8List data;
+  InternetAddress address;
+  int port;
+
+  Datagram(this.data, this.address, this.port);
+}
+
+/**
+ * A [RawDatagramSocket] is an unbuffered interface to a UDP socket.
+ *
+ * The raw datagram socket delivers the datagrams in the same chunks as the
+ * underlying operating system. It's a [Stream] of [RawSocketEvent]s.
+ *
+ * Note that the event [RawSocketEvent.readClosed] will never be
+ * received as an UDP socket cannot be closed by a remote peer.
+ *
+ * It is not the same as a
+ * [POSIX raw socket](http://man7.org/linux/man-pages/man7/raw.7.html).
+ */
+abstract class RawDatagramSocket extends Stream<RawSocketEvent> {
+  /**
+   * Set or get, if the [RawDatagramSocket] should listen for
+   * [RawSocketEvent.read] events. Default is [:true:].
+   */
+  bool readEventsEnabled;
+
+  /**
+   * Set or get, if the [RawDatagramSocket] should listen for
+   * [RawSocketEvent.write] events. Default is [:true:].  This is a
+   * one-shot listener, and writeEventsEnabled must be set to true
+   * again to receive another write event.
+   */
+  bool writeEventsEnabled;
+
+  /**
+   * Set or get, whether multicast traffic is looped back to the host.
+   *
+   * By default multicast loopback is enabled.
+   */
+  bool multicastLoopback;
+
+  /**
+   * Set or get, the maximum network hops for multicast packages
+   * originating from this socket.
+   *
+   * For IPv4 this is referred to as TTL (time to live).
+   *
+   * By default this value is 1 causing multicast traffic to stay on
+   * the local network.
+   */
+  int multicastHops;
+
+  /**
+   * Set or get, the network interface used for outgoing multicast packages.
+   *
+   * A value of `null`indicate that the system chooses the network
+   * interface to use.
+   *
+   * By default this value is `null`
+   */
+  @Deprecated("This property is not implemented. Use getRawOption and "
+      "setRawOption instead.")
+  NetworkInterface multicastInterface;
+
+  /**
+   * Set or get, whether IPv4 broadcast is enabled.
+   *
+   * IPv4 broadcast needs to be enabled by the sender for sending IPv4
+   * broadcast packages. By default IPv4 broadcast is disabled.
+   *
+   * For IPv6 there is no general broadcast mechanism. Use multicast
+   * instead.
+   */
+  bool broadcastEnabled;
+
+  /**
+   * Creates a new raw datagram socket binding it to an address and
+   * port.
+   */
+  external static Future<RawDatagramSocket> bind(host, int port,
+      {bool reuseAddress: true, bool reusePort: false, int ttl: 1});
+
+  /**
+   * Returns the port used by this socket.
+   */
+  int get port;
+
+  /**
+   * Returns the address used by this socket.
+   */
+  InternetAddress get address;
+
+  /**
+   * Close the datagram socket.
+   */
+  void close();
+
+  /**
+   * Send a datagram.
+   *
+   * Returns the number of bytes written. This will always be either
+   * the size of [buffer] or `0`.
+   */
+  int send(List<int> buffer, InternetAddress address, int port);
+
+  /**
+   * Receive a datagram. If there are no datagrams available `null` is
+   * returned.
+   *
+   * The maximum length of the datagram that can be received is 65503 bytes.
+   */
+  Datagram receive();
+
+  /**
+   * Join a multicast group.
+   *
+   * If an error occur when trying to join the multicast group an
+   * exception is thrown.
+   */
+  void joinMulticast(InternetAddress group, [NetworkInterface interface]);
+
+  /**
+   * Leave a multicast group.
+   *
+   * If an error occur when trying to join the multicase group an
+   * exception is thrown.
+   */
+  void leaveMulticast(InternetAddress group, [NetworkInterface interface]);
+
+  /**
+   * Use [getRawOption] to get low level information about the [RawSocket]. See
+   * [RawSocketOption] for available options.
+   *
+   * Returns [RawSocketOption.value] on success.
+   *
+   * Throws an [OSError] on failure.
+   */
+  Uint8List getRawOption(RawSocketOption option);
+
+  /**
+   * Use [setRawOption] to customize the [RawSocket]. See [RawSocketOption] for
+   * available options.
+   *
+   * Throws an [OSError] on failure.
+   */
+  void setRawOption(RawSocketOption option);
+}
+
+class SocketException implements IOException {
+  final String message;
+  final OSError osError;
+  final InternetAddress address;
+  final int port;
+
+  const SocketException(this.message, {this.osError, this.address, this.port});
+  const SocketException.closed()
+      : message = 'Socket has been closed',
+        osError = null,
+        address = null,
+        port = null;
+
+  String toString() {
+    StringBuffer sb = new StringBuffer();
+    sb.write("SocketException");
+    if (message.isNotEmpty) {
+      sb.write(": $message");
+      if (osError != null) {
+        sb.write(" ($osError)");
+      }
+    } else if (osError != null) {
+      sb.write(": $osError");
+    }
+    if (address != null) {
+      sb.write(", address = ${address.host}");
+    }
+    if (port != null) {
+      sb.write(", port = $port");
+    }
+    return sb.toString();
+  }
+}
diff --git a/sdk_nnbd/lib/io/stdio.dart b/sdk_nnbd/lib/io/stdio.dart
new file mode 100644
index 0000000..4086f08
--- /dev/null
+++ b/sdk_nnbd/lib/io/stdio.dart
@@ -0,0 +1,480 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.io;
+
+const int _stdioHandleTypeTerminal = 0;
+const int _stdioHandleTypePipe = 1;
+const int _stdioHandleTypeFile = 2;
+const int _stdioHandleTypeSocket = 3;
+const int _stdioHandleTypeOther = 4;
+
+class _StdStream extends Stream<List<int>> {
+  final Stream<List<int>> _stream;
+
+  _StdStream(this._stream);
+
+  StreamSubscription<List<int>> listen(void onData(List<int> event),
+      {Function onError, void onDone(), bool cancelOnError}) {
+    return _stream.listen(onData,
+        onError: onError, onDone: onDone, cancelOnError: cancelOnError);
+  }
+}
+
+/**
+ * [Stdin] allows both synchronous and asynchronous reads from the standard
+ * input stream.
+ *
+ * Mixing synchronous and asynchronous reads is undefined.
+ */
+class Stdin extends _StdStream implements Stream<List<int>> {
+  int _fd;
+
+  Stdin._(Stream<List<int>> stream, this._fd) : super(stream);
+
+  /**
+   * Read a line from stdin.
+   *
+   * Blocks until a full line is available.
+   *
+   * Lines my be terminated by either `<CR><LF>` or `<LF>`. On Windows in cases
+   * where the [stdioType] of stdin is [StdioType.termimal] the terminator may
+   * also be a single `<CR>`.
+   *
+   * Input bytes are converted to a string by [encoding].
+   * If [encoding] is omitted, it defaults to [systemEncoding].
+   *
+   * If [retainNewlines] is `false`, the returned String will not include the
+   * final line terminator. If `true`, the returned String will include the line
+   * terminator. Default is `false`.
+   *
+   * If end-of-file is reached after any bytes have been read from stdin,
+   * that data is returned without a line terminator.
+   * Returns `null` if no bytes preceded the end of input.
+   */
+  String readLineSync(
+      {Encoding encoding: systemEncoding, bool retainNewlines: false}) {
+    const CR = 13;
+    const LF = 10;
+    final List<int> line = <int>[];
+    // On Windows, if lineMode is disabled, only CR is received.
+    bool crIsNewline = Platform.isWindows &&
+        (stdioType(stdin) == StdioType.terminal) &&
+        !lineMode;
+    if (retainNewlines) {
+      int byte;
+      do {
+        byte = readByteSync();
+        if (byte < 0) {
+          break;
+        }
+        line.add(byte);
+      } while (byte != LF && !(byte == CR && crIsNewline));
+      if (line.isEmpty) {
+        return null;
+      }
+    } else if (crIsNewline) {
+      // CR and LF are both line terminators, neither is retained.
+      while (true) {
+        int byte = readByteSync();
+        if (byte < 0) {
+          if (line.isEmpty) return null;
+          break;
+        }
+        if (byte == LF || byte == CR) break;
+        line.add(byte);
+      }
+    } else {
+      // Case having to handle CR LF as a single unretained line terminator.
+      outer:
+      while (true) {
+        int byte = readByteSync();
+        if (byte == LF) break;
+        if (byte == CR) {
+          do {
+            byte = readByteSync();
+            if (byte == LF) break outer;
+
+            line.add(CR);
+          } while (byte == CR);
+          // Fall through and handle non-CR character.
+        }
+        if (byte < 0) {
+          if (line.isEmpty) return null;
+          break;
+        }
+        line.add(byte);
+      }
+    }
+    return encoding.decode(line);
+  }
+
+  /**
+   * Check if echo mode is enabled on [stdin].
+   */
+  external bool get echoMode;
+
+  /**
+   * Enable or disable echo mode on [stdin].
+   *
+   * If disabled, input from to console will not be echoed.
+   *
+   * Default depends on the parent process, but usually enabled.
+   *
+   * On Windows this mode can only be enabled if [lineMode] is enabled as well.
+   */
+  external void set echoMode(bool enabled);
+
+  /**
+   * Check if line mode is enabled on [stdin].
+   */
+  external bool get lineMode;
+
+  /**
+   * Enable or disable line mode on [stdin].
+   *
+   * If enabled, characters are delayed until a new-line character is entered.
+   * If disabled, characters will be available as typed.
+   *
+   * Default depends on the parent process, but usually enabled.
+   *
+   * On Windows this mode can only be disabled if [echoMode] is disabled as well.
+   */
+  external void set lineMode(bool enabled);
+
+  /**
+    * Whether connected to a terminal that supports ANSI escape sequences.
+    *
+    * Not all terminals are recognized, and not all recognized terminals can
+    * report whether they support ANSI escape sequences, so this value is a
+    * best-effort attempt at detecting the support.
+    *
+    * The actual escape sequence support may differ between terminals,
+    * with some terminals supporting more escape sequences than others,
+    * and some terminals even differing in behavior for the same escape
+    * sequence.
+    *
+    * The ANSI color selection is generally supported.
+    *
+    * Currently, a `TERM` environment variable containing the string `xterm`
+    * will be taken as evidence that ANSI escape sequences are supported.
+    * On Windows, only versions of Windows 10 after v.1511
+    * ("TH2", OS build 10586) will be detected as supporting the output of
+    * ANSI escape sequences, and only versions after v.1607 ("Anniversary
+    * Update", OS build 14393) will be detected as supporting the input of
+    * ANSI escape sequences.
+    */
+  external bool get supportsAnsiEscapes;
+
+  /**
+   * Synchronously read a byte from stdin. This call will block until a byte is
+   * available.
+   *
+   * If at end of file, -1 is returned.
+   */
+  external int readByteSync();
+
+  /**
+   * Returns true if there is a terminal attached to stdin.
+   */
+  bool get hasTerminal {
+    try {
+      return stdioType(this) == StdioType.terminal;
+    } on FileSystemException catch (_) {
+      // If stdioType throws a FileSystemException, then it is not hooked up to
+      // a terminal, probably because it is closed, but let other exception
+      // types bubble up.
+      return false;
+    }
+  }
+}
+
+/**
+ * [Stdout] represents the [IOSink] for either `stdout` or `stderr`.
+ *
+ * It provides a *blocking* `IOSink`, so using this to write will block until
+ * the output is written.
+ *
+ * In some situations this blocking behavior is undesirable as it does not
+ * provide the same non-blocking behavior as dart:io in general exposes.
+ * Use the property [nonBlocking] to get an `IOSink` which has the non-blocking
+ * behavior.
+ *
+ * This class can also be used to check whether `stdout` or `stderr` is
+ * connected to a terminal and query some terminal properties.
+ *
+ * The [addError] API is inherited from  [StreamSink] and calling it will result
+ * in an unhandled asynchronous error unless there is an error handler on
+ * [done].
+ */
+class Stdout extends _StdSink implements IOSink {
+  final int _fd;
+  IOSink _nonBlocking;
+
+  Stdout._(IOSink sink, this._fd) : super(sink);
+
+  /**
+   * Returns true if there is a terminal attached to stdout.
+   */
+  bool get hasTerminal => _hasTerminal(_fd);
+
+  /**
+   * Get the number of columns of the terminal.
+   *
+   * If no terminal is attached to stdout, a [StdoutException] is thrown. See
+   * [hasTerminal] for more info.
+   */
+  int get terminalColumns => _terminalColumns(_fd);
+
+  /**
+   * Get the number of lines of the terminal.
+   *
+   * If no terminal is attached to stdout, a [StdoutException] is thrown. See
+   * [hasTerminal] for more info.
+   */
+  int get terminalLines => _terminalLines(_fd);
+
+  /**
+    * Whether connected to a terminal that supports ANSI escape sequences.
+    *
+    * Not all terminals are recognized, and not all recognized terminals can
+    * report whether they support ANSI escape sequences, so this value is a
+    * best-effort attempt at detecting the support.
+    *
+    * The actual escape sequence support may differ between terminals,
+    * with some terminals supporting more escape sequences than others,
+    * and some terminals even differing in behavior for the same escape
+    * sequence.
+    *
+    * The ANSI color selection is generally supported.
+    *
+    * Currently, a `TERM` environment variable containing the string `xterm`
+    * will be taken as evidence that ANSI escape sequences are supported.
+    * On Windows, only versions of Windows 10 after v.1511
+    * ("TH2", OS build 10586) will be detected as supporting the output of
+    * ANSI escape sequences, and only versions after v.1607 ("Anniversary
+    * Update", OS build 14393) will be detected as supporting the input of
+    * ANSI escape sequences.
+    */
+  bool get supportsAnsiEscapes => _supportsAnsiEscapes(_fd);
+
+  external bool _hasTerminal(int fd);
+  external int _terminalColumns(int fd);
+  external int _terminalLines(int fd);
+  external static bool _supportsAnsiEscapes(int fd);
+
+  /**
+   * Get a non-blocking `IOSink`.
+   */
+  IOSink get nonBlocking {
+    _nonBlocking ??= new IOSink(new _FileStreamConsumer.fromStdio(_fd));
+    return _nonBlocking;
+  }
+}
+
+class StdoutException implements IOException {
+  final String message;
+  final OSError osError;
+
+  const StdoutException(this.message, [this.osError]);
+
+  String toString() {
+    return "StdoutException: $message${osError == null ? "" : ", $osError"}";
+  }
+}
+
+class StdinException implements IOException {
+  final String message;
+  final OSError osError;
+
+  const StdinException(this.message, [this.osError]);
+
+  String toString() {
+    return "StdinException: $message${osError == null ? "" : ", $osError"}";
+  }
+}
+
+class _StdConsumer implements StreamConsumer<List<int>> {
+  final _file;
+
+  _StdConsumer(int fd) : _file = _File._openStdioSync(fd);
+
+  Future addStream(Stream<List<int>> stream) {
+    var completer = new Completer();
+    var sub;
+    sub = stream.listen((data) {
+      try {
+        _file.writeFromSync(data);
+      } catch (e, s) {
+        sub.cancel();
+        completer.completeError(e, s);
+      }
+    },
+        onError: completer.completeError,
+        onDone: completer.complete,
+        cancelOnError: true);
+    return completer.future;
+  }
+
+  Future close() {
+    _file.closeSync();
+    return new Future.value();
+  }
+}
+
+class _StdSink implements IOSink {
+  final IOSink _sink;
+
+  _StdSink(this._sink);
+
+  Encoding get encoding => _sink.encoding;
+  void set encoding(Encoding encoding) {
+    _sink.encoding = encoding;
+  }
+
+  void write(object) {
+    _sink.write(object);
+  }
+
+  void writeln([object = ""]) {
+    _sink.writeln(object);
+  }
+
+  void writeAll(objects, [sep = ""]) {
+    _sink.writeAll(objects, sep);
+  }
+
+  void add(List<int> data) {
+    _sink.add(data);
+  }
+
+  void addError(error, [StackTrace stackTrace]) {
+    _sink.addError(error, stackTrace);
+  }
+
+  void writeCharCode(int charCode) {
+    _sink.writeCharCode(charCode);
+  }
+
+  Future addStream(Stream<List<int>> stream) => _sink.addStream(stream);
+  Future flush() => _sink.flush();
+  Future close() => _sink.close();
+  Future get done => _sink.done;
+}
+
+/// The type of object a standard IO stream is attached to.
+class StdioType {
+  static const StdioType terminal = const StdioType._("terminal");
+  static const StdioType pipe = const StdioType._("pipe");
+  static const StdioType file = const StdioType._("file");
+  static const StdioType other = const StdioType._("other");
+
+  @Deprecated("Use terminal instead")
+  static const StdioType TERMINAL = terminal;
+  @Deprecated("Use pipe instead")
+  static const StdioType PIPE = pipe;
+  @Deprecated("Use file instead")
+  static const StdioType FILE = file;
+  @Deprecated("Use other instead")
+  static const StdioType OTHER = other;
+
+  final String name;
+  const StdioType._(this.name);
+  String toString() => "StdioType: $name";
+}
+
+Stdin _stdin;
+Stdout _stdout;
+Stdout _stderr;
+
+// These may be set to different values by the embedder by calling
+// _setStdioFDs when initializing dart:io.
+int _stdinFD = 0;
+int _stdoutFD = 1;
+int _stderrFD = 2;
+
+@pragma('vm:entry-point', 'call')
+void _setStdioFDs(int stdin, int stdout, int stderr) {
+  _stdinFD = stdin;
+  _stdoutFD = stdout;
+  _stderrFD = stderr;
+}
+
+/// The standard input stream of data read by this program.
+Stdin get stdin {
+  _stdin ??= _StdIOUtils._getStdioInputStream(_stdinFD);
+  return _stdin;
+}
+
+/// The standard output stream of data written by this program.
+///
+/// The `addError` API is inherited from  `StreamSink` and calling it will
+/// result in an unhandled asynchronous error unless there is an error handler
+/// on `done`.
+Stdout get stdout {
+  _stdout ??= _StdIOUtils._getStdioOutputStream(_stdoutFD);
+  return _stdout;
+}
+
+/// The standard output stream of errors written by this program.
+///
+/// The `addError` API is inherited from  `StreamSink` and calling it will
+/// result in an unhandled asynchronous error unless there is an error handler
+/// on `done`.
+Stdout get stderr {
+  _stderr ??= _StdIOUtils._getStdioOutputStream(_stderrFD);
+  return _stderr;
+}
+
+/// For a stream, returns whether it is attached to a file, pipe, terminal, or
+/// something else.
+StdioType stdioType(object) {
+  if (object is _StdStream) {
+    object = object._stream;
+  } else if (object == stdout || object == stderr) {
+    int stdiofd = object == stdout ? _stdoutFD : _stderrFD;
+    switch (_StdIOUtils._getStdioHandleType(stdiofd)) {
+      case _stdioHandleTypeTerminal:
+        return StdioType.terminal;
+      case _stdioHandleTypePipe:
+        return StdioType.pipe;
+      case _stdioHandleTypeFile:
+        return StdioType.file;
+    }
+  }
+  if (object is _FileStream) {
+    return StdioType.file;
+  }
+  if (object is Socket) {
+    int socketType = _StdIOUtils._socketType(object);
+    if (socketType == null) return StdioType.other;
+    switch (socketType) {
+      case _stdioHandleTypeTerminal:
+        return StdioType.terminal;
+      case _stdioHandleTypePipe:
+        return StdioType.pipe;
+      case _stdioHandleTypeFile:
+        return StdioType.file;
+    }
+  }
+  if (object is _IOSinkImpl) {
+    try {
+      if (object._target is _FileStreamConsumer) {
+        return StdioType.file;
+      }
+    } catch (e) {
+      // Only the interface implemented, _sink not available.
+    }
+  }
+  return StdioType.other;
+}
+
+class _StdIOUtils {
+  external static _getStdioOutputStream(int fd);
+  external static Stdin _getStdioInputStream(int fd);
+
+  /// Returns the socket type or `null` if [socket] is not a builtin socket.
+  external static int _socketType(Socket socket);
+  external static _getStdioHandleType(int fd);
+}
diff --git a/sdk_nnbd/lib/io/string_transformer.dart b/sdk_nnbd/lib/io/string_transformer.dart
new file mode 100644
index 0000000..f31c41e
--- /dev/null
+++ b/sdk_nnbd/lib/io/string_transformer.dart
@@ -0,0 +1,130 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.io;
+
+/// The current system encoding.
+///
+/// This is used for converting from bytes to and from Strings when
+/// communicating on stdin, stdout and stderr.
+///
+/// On Windows this will use the currently active code page for the conversion.
+/// On all other systems it will always use UTF-8.
+const SystemEncoding systemEncoding = const SystemEncoding();
+@Deprecated("Use systemEncoding instead")
+const SystemEncoding SYSTEM_ENCODING = const SystemEncoding();
+
+/// The system encoding is the current code page on Windows and UTF-8 on Linux
+/// and Mac.
+class SystemEncoding extends Encoding {
+  /// Creates a const SystemEncoding.
+  ///
+  /// Users should use the top-level constant, [systemEncoding].
+  const SystemEncoding();
+
+  String get name => 'system';
+
+  List<int> encode(String input) => encoder.convert(input);
+  String decode(List<int> encoded) => decoder.convert(encoded);
+
+  Converter<String, List<int>> get encoder {
+    if (Platform.operatingSystem == "windows") {
+      return const _WindowsCodePageEncoder();
+    } else {
+      return const Utf8Encoder();
+    }
+  }
+
+  Converter<List<int>, String> get decoder {
+    if (Platform.operatingSystem == "windows") {
+      return const _WindowsCodePageDecoder();
+    } else {
+      return const Utf8Decoder();
+    }
+  }
+}
+
+class _WindowsCodePageEncoder extends Converter<String, List<int>> {
+  const _WindowsCodePageEncoder();
+
+  List<int> convert(String input) {
+    List<int> encoded = _encodeString(input);
+    if (encoded == null) {
+      throw new FormatException("Invalid character for encoding");
+    }
+    return encoded;
+  }
+
+  /**
+   * Starts a chunked conversion.
+   */
+  StringConversionSink startChunkedConversion(Sink<List<int>> sink) {
+    return new _WindowsCodePageEncoderSink(sink);
+  }
+
+  external static List<int> _encodeString(String string);
+}
+
+class _WindowsCodePageEncoderSink extends StringConversionSinkBase {
+  // TODO(floitsch): provide more efficient conversions when the input is
+  // not a String.
+
+  final Sink<List<int>> _sink;
+
+  _WindowsCodePageEncoderSink(this._sink);
+
+  void close() {
+    _sink.close();
+  }
+
+  void add(String string) {
+    List<int> encoded = _WindowsCodePageEncoder._encodeString(string);
+    if (encoded == null) {
+      throw new FormatException("Invalid character for encoding");
+    }
+    _sink.add(encoded);
+  }
+
+  void addSlice(String source, int start, int end, bool isLast) {
+    if (start != 0 || end != source.length) {
+      source = source.substring(start, end);
+    }
+    add(source);
+    if (isLast) close();
+  }
+}
+
+class _WindowsCodePageDecoder extends Converter<List<int>, String> {
+  const _WindowsCodePageDecoder();
+
+  String convert(List<int> input) {
+    return _decodeBytes(input);
+  }
+
+  /**
+   * Starts a chunked conversion.
+   */
+  ByteConversionSink startChunkedConversion(Sink<String> sink) {
+    return new _WindowsCodePageDecoderSink(sink);
+  }
+
+  external static String _decodeBytes(List<int> bytes);
+}
+
+class _WindowsCodePageDecoderSink extends ByteConversionSinkBase {
+  // TODO(floitsch): provide more efficient conversions when the input is
+  // a slice.
+
+  final Sink<String> _sink;
+
+  _WindowsCodePageDecoderSink(this._sink);
+
+  void close() {
+    _sink.close();
+  }
+
+  void add(List<int> bytes) {
+    _sink.add(_WindowsCodePageDecoder._decodeBytes(bytes));
+  }
+}
diff --git a/sdk_nnbd/lib/io/sync_socket.dart b/sdk_nnbd/lib/io/sync_socket.dart
new file mode 100644
index 0000000..fee259d
--- /dev/null
+++ b/sdk_nnbd/lib/io/sync_socket.dart
@@ -0,0 +1,109 @@
+// 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.
+
+part of dart.io;
+
+/**
+ * A low-level class for communicating synchronously over a TCP socket.
+ *
+ * Warning: [RawSynchronousSocket] should probably only be used to connect to
+ * 'localhost'. The operations below will block the calling thread to wait for
+ * a response from the network. The thread can process no other events while
+ * waiting for these operations to complete. [RawSynchronousSocket] is not
+ * suitable for applications that require high performance or asynchronous I/O
+ * such as a server. Instead such applications should use the non-blocking
+ * sockets and asynchronous operations in the Socket or RawSocket classes.
+ */
+abstract class RawSynchronousSocket {
+  /**
+   * Creates a new socket connection and returns a [RawSynchronousSocket].
+   *
+   * [host] can either be a [String] or an [InternetAddress]. If [host] is a
+   * [String], [connectSync] will perform a [InternetAddress.lookup] and try
+   * all returned [InternetAddress]es, until connected. Unless a
+   * connection was established, the error from the first failing connection is
+   * returned.
+   */
+  external static RawSynchronousSocket connectSync(host, int port);
+
+  /**
+   * Returns the number of received and unread bytes in the socket that can be
+   * read.
+   */
+  int available();
+
+  /**
+   * Closes the [RawSynchronousSocket].
+   *
+   * Once [closeSync] has been called, attempting to call [readSync],
+   * [readIntoSync], [writeFromSync], [remoteAddress], and [remotePort] will
+   * cause a [SocketException] to be thrown.
+   */
+  void closeSync();
+
+  /**
+   * Reads into an existing [List<int>] from the socket into the range:
+   * [[start],[end]).
+   *
+   * Reads into an existing [List<int>] from the socket. If [start] is present,
+   * the bytes will be filled into [buffer] from index [start], otherwise index
+   * 0. If [end] is present, [end] - [start] bytes will be read into [buffer],
+   * otherwise up to [buffer.length]. If [end] == [start], no bytes are read.
+   * Returns the number of bytes read.
+   */
+  int readIntoSync(List<int> buffer, [int start = 0, int end]);
+
+  /**
+   * Reads up to [bytes] bytes from the socket.
+   *
+   * Blocks and waits for a response of up to a specified number of bytes
+   * sent by the socket. [bytes] specifies the maximum number of bytes to
+   * be read. Returns the list of bytes read, which could be less than the
+   * value specified by [bytes].
+   */
+  List<int> readSync(int bytes);
+
+  /**
+   * Shutdown a socket in the provided direction.
+   *
+   * Calling shutdown will never throw an exception and calling it several times
+   * is supported. If both [SocketDirection.RECEIVE] and [SocketDirection.SEND]
+   * directions are closed, the socket is closed completely, the same as if
+   * [closeSync] has been called.
+   */
+  void shutdown(SocketDirection direction);
+
+  /**
+   * Writes data from a specified range in a [List<int>] to the socket.
+   *
+   * Writes into the socket from a [List<int>]. If [start] is present, the bytes
+   * will be written to the socket starting from index [start]. If [start] is
+   * not present, the bytes will be written starting from index 0. If [end] is
+   * present, the [end] - [start] bytes will be written into the socket starting
+   * at index [start]. If [end] is not provided, [buffer.length] elements will
+   * be written to the socket starting from index [start]. If [end] == [start],
+   * nothing happens.
+   */
+  void writeFromSync(List<int> buffer, [int start = 0, int end]);
+
+  /**
+   * The port used by this socket.
+   */
+  int get port;
+
+  /**
+   * The remote port connected to by this socket.
+   */
+  int get remotePort;
+
+  /**
+   * The [InternetAddress] used to connect this socket.
+   */
+  InternetAddress get address;
+
+  /**
+   * The remote [InternetAddress] connected to by this socket.
+   */
+  InternetAddress get remoteAddress;
+}
diff --git a/sdk_nnbd/lib/isolate/capability.dart b/sdk_nnbd/lib/isolate/capability.dart
new file mode 100644
index 0000000..a51eec2
--- /dev/null
+++ b/sdk_nnbd/lib/isolate/capability.dart
@@ -0,0 +1,34 @@
+// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.isolate;
+
+/**
+ * An unforgeable object that comes back as equal when passed through other
+ * isolates.
+ *
+ * Sending a capability object to another isolate, and getting it back,
+ * will produce an object that is equal to the original.
+ * There is no other way to create objects equal to a capability object.
+ *
+ * Capabilities can be used as access guards: A remote isolate can send
+ * a request for an operation, but it is only allowed if the request contains
+ * the correct capability object.
+ *
+ * This allows exposing the same interface to multiple clients,
+ * but restricting some operations to only those clients
+ * that have also been given the corresponding capability.
+ *
+ * Capabilities can be used inside a single isolate,
+ * but they have no advantage over
+ * just using `new Object` to create a unique object,
+ * and it offers no real security against other code
+ * running in the same isolate.
+ */
+class Capability {
+  /**
+   * Create a new unforgeable capability object.
+   */
+  external factory Capability();
+}
diff --git a/sdk_nnbd/lib/isolate/isolate.dart b/sdk_nnbd/lib/isolate/isolate.dart
new file mode 100644
index 0000000..a697db4
--- /dev/null
+++ b/sdk_nnbd/lib/isolate/isolate.dart
@@ -0,0 +1,789 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/**
+ * Concurrent programming using _isolates_:
+ * independent workers that are similar to threads
+ * but don't share memory,
+ * communicating only via messages.
+ *
+ * To use this library in your code:
+ *
+ *     import 'dart:isolate';
+ *
+ * {@category VM}
+ */
+library dart.isolate;
+
+import "dart:async";
+import "dart:_internal" show Since;
+import "dart:typed_data" show ByteBuffer, TypedData, Uint8List;
+
+part "capability.dart";
+
+/**
+ * Thrown when an isolate cannot be created.
+ */
+class IsolateSpawnException implements Exception {
+  /** Error message reported by the spawn operation. */
+  final String message;
+  @pragma("vm:entry-point")
+  IsolateSpawnException(this.message);
+  String toString() => "IsolateSpawnException: $message";
+}
+
+/**
+ * An isolated Dart execution context.
+ *
+ * All Dart code runs in an isolate, and code can access classes and values
+ * only from the same isolate. Different isolates can communicate by sending
+ * values through ports (see [ReceivePort], [SendPort]).
+ *
+ * An `Isolate` object is a reference to an isolate, usually different from
+ * the current isolate.
+ * It represents, and can be used to control, the other isolate.
+ *
+ * When spawning a new isolate, the spawning isolate receives an `Isolate`
+ * object representing the new isolate when the spawn operation succeeds.
+ *
+ * Isolates run code in its own event loop, and each event may run smaller tasks
+ * in a nested microtask queue.
+ *
+ * An `Isolate` object allows other isolates to control the event loop
+ * of the isolate that it represents, and to inspect the isolate,
+ * for example by pausing the isolate or by getting events when the isolate
+ * has an uncaught error.
+ *
+ * The [controlPort] identifies and gives access to controlling the isolate,
+ * and the [pauseCapability] and [terminateCapability] guard access
+ * to some control operations.
+ * For example, calling [pause] on an `Isolate` object created without a
+ * [pauseCapability], has no effect.
+ *
+ * The `Isolate` object provided by a spawn operation will have the
+ * control port and capabilities needed to control the isolate.
+ * New isolate objects can be created without some of these capabilities
+ * if necessary, using the [Isolate.Isolate] constructor.
+ *
+ * An `Isolate` object cannot be sent over a `SendPort`, but the control port
+ * and capabilities can be sent, and can be used to create a new functioning
+ * `Isolate` object in the receiving port's isolate.
+ */
+class Isolate {
+  /** Argument to `ping` and `kill`: Ask for immediate action. */
+  static const int immediate = 0;
+  /** Argument to `ping` and `kill`: Ask for action before the next event. */
+  static const int beforeNextEvent = 1;
+
+  /**
+   * Control port used to send control messages to the isolate.
+   *
+   * The control port identifies the isolate.
+   *
+   * An `Isolate` object allows sending control messages
+   * through the control port.
+   *
+   * Some control messages require a specific capability to be passed along
+   * with the message (see [pauseCapability] and [terminateCapability]),
+   * otherwise the message is ignored by the isolate.
+   */
+  final SendPort controlPort;
+
+  /**
+   * Capability granting the ability to pause the isolate.
+   *
+   * This capability is required by [pause].
+   * If the capability is `null`, or if it is not the correct pause capability
+   * of the isolate identified by [controlPort],
+   * then calls to [pause] will have no effect.
+   *
+   * If the isolate is spawned in a paused state, use this capability as
+   * argument to the [resume] method in order to resume the paused isolate.
+   */
+  final Capability pauseCapability;
+
+  /**
+   * Capability granting the ability to terminate the isolate.
+   *
+   * This capability is required by [kill] and [setErrorsFatal].
+   * If the capability is `null`, or if it is not the correct termination
+   * capability of the isolate identified by [controlPort],
+   * then calls to those methods will have no effect.
+   */
+  final Capability terminateCapability;
+
+  /**
+   * The name of the [Isolate] displayed for debug purposes.
+   *
+   * This can be set using the `debugName` parameter in [spawn] and [spawnUri].
+   *
+   * This name does not uniquely identify an isolate. Multiple isolates in the
+   * same process may have the same `debugName`.
+   *
+   * For a given isolate, this value will be the same as the values returned by
+   * `Dart_DebugName` in the C embedding API and the `debugName` property in
+   * [IsolateMirror].
+   */
+  @Since("2.3")
+  external String get debugName;
+
+  /**
+   * Create a new [Isolate] object with a restricted set of capabilities.
+   *
+   * The port should be a control port for an isolate, as taken from
+   * another `Isolate` object.
+   *
+   * The capabilities should be the subset of the capabilities that are
+   * available to the original isolate.
+   * Capabilities of an isolate are locked to that isolate, and have no effect
+   * anywhere else, so the capabilities should come from the same isolate as
+   * the control port.
+   *
+   * Can also be used to create an [Isolate] object from a control port, and
+   * any available capabilities, that have been sent through a [SendPort].
+   *
+   * Example:
+   * ```dart
+   * Isolate isolate = findSomeIsolate();
+   * Isolate restrictedIsolate = new Isolate(isolate.controlPort);
+   * untrustedCode(restrictedIsolate);
+   * ```
+   * This example creates a new `Isolate` object that cannot be used to
+   * pause or terminate the isolate. All the untrusted code can do is to
+   * inspect the isolate and see uncaught errors or when it terminates.
+   */
+  Isolate(this.controlPort, {this.pauseCapability, this.terminateCapability});
+
+  /**
+   * Return an [Isolate] object representing the current isolate.
+   *
+   * The current isolate for code using [current]
+   * is the isolate running the code.
+   *
+   * The isolate object provides the capabilities required to inspect,
+   * pause or kill the isolate, and allows granting these capabilities
+   * to others.
+   *
+   * It is possible to pause the current isolate, but doing so *without*
+   * first passing the ability to resume it again to another isolate,
+   * is a sure way to hang your program.
+   */
+  external static Isolate get current;
+
+  /**
+   * The location of the package configuration of the current isolate, if any.
+   *
+   * This getter returns `null`, as the `packages/` directory is not supported
+   * in Dart 2.
+   */
+  @Deprecated('packages/ directory resolution is not supported in Dart 2.')
+  external static Future<Uri> get packageRoot;
+
+  /**
+   * The package root of the current isolate, if any.
+   *
+   * If the isolate is using a [packageRoot] or the isolate has not been
+   * setup for package resolution, this getter returns `null`, otherwise it
+   * returns the package config URI.
+   */
+  external static Future<Uri> get packageConfig;
+
+  /**
+   * Maps a package: URI to a non-package Uri.
+   *
+   * If there is no valid mapping from the package: URI in the current
+   * isolate, then this call returns `null`. Non-package: URIs are
+   * returned unmodified.
+   */
+  external static Future<Uri> resolvePackageUri(Uri packageUri);
+
+  /**
+   * Creates and spawns an isolate that shares the same code as the current
+   * isolate.
+   *
+   * The argument [entryPoint] specifies the initial function to call
+   * in the spawned isolate.
+   * The entry-point function is invoked in the new isolate with [message]
+   * as the only argument.
+   *
+   * The function must be a top-level function or a static method
+   * that can be called with a single argument,
+   * that is, a compile-time constant function value
+   * which accepts at least one positional parameter
+   * and has at most one required positional parameter.
+   * The function may accept any number of optional parameters,
+   * as long as it *can* be called with just a single argument.
+   * The function must not be the value of a function expression
+   * or an instance method tear-off.
+   *
+   * Usually the initial [message] contains a [SendPort] so
+   * that the spawner and spawnee can communicate with each other.
+   *
+   * If the [paused] parameter is set to `true`,
+   * the isolate will start up in a paused state,
+   * just before calling the [entryPoint] function with the [message],
+   * as if by an initial call of `isolate.pause(isolate.pauseCapability)`.
+   * To resume the isolate, call `isolate.resume(isolate.pauseCapability)`.
+   *
+   * If the [errorsAreFatal], [onExit] and/or [onError] parameters are provided,
+   * the isolate will act as if, respectively, [setErrorsFatal],
+   * [addOnExitListener] and [addErrorListener] were called with the
+   * corresponding parameter and was processed before the isolate starts
+   * running.
+   *
+   * If [debugName] is provided, the spawned [Isolate] will be identifiable by
+   * this name in debuggers and logging.
+   *
+   * If [errorsAreFatal] is omitted, the platform may choose a default behavior
+   * or inherit the current isolate's behavior.
+   *
+   * You can also call the [setErrorsFatal], [addOnExitListener] and
+   * [addErrorListener] methods on the returned isolate, but unless the
+   * isolate was started as [paused], it may already have terminated
+   * before those methods can complete.
+   *
+   * Returns a future which will complete with an [Isolate] instance if the
+   * spawning succeeded. It will complete with an error otherwise.
+   */
+  external static Future<Isolate> spawn<T>(
+      void entryPoint(T message), T message,
+      {bool paused: false,
+      bool errorsAreFatal,
+      SendPort onExit,
+      SendPort onError,
+      @Since("2.3") String debugName});
+
+  /**
+   * Creates and spawns an isolate that runs the code from the library with
+   * the specified URI.
+   *
+   * The isolate starts executing the top-level `main` function of the library
+   * with the given URI.
+   *
+   * The target `main` must be callable with zero, one or two arguments.
+   * Examples:
+   *
+   * * `main()`
+   * * `main(args)`
+   * * `main(args, message)`
+   *
+   * When present, the parameter `args` is set to the provided [args] list.
+   * When present, the parameter `message` is set to the initial [message].
+   *
+   * If the [paused] parameter is set to `true`,
+   * the isolate will start up in a paused state,
+   * as if by an initial call of `isolate.pause(isolate.pauseCapability)`.
+   * To resume the isolate, call `isolate.resume(isolate.pauseCapability)`.
+   *
+   * If the [errorsAreFatal], [onExit] and/or [onError] parameters are provided,
+   * the isolate will act as if, respectively, [setErrorsFatal],
+   * [addOnExitListener] and [addErrorListener] were called with the
+   * corresponding parameter and was processed before the isolate starts
+   * running.
+   *
+   * You can also call the [setErrorsFatal], [addOnExitListener] and
+   * [addErrorListener] methods on the returned isolate, but unless the
+   * isolate was started as [paused], it may already have terminated
+   * before those methods can complete.
+   *
+   * If the [checked] parameter is set to `true` or `false`,
+   * the new isolate will run code in checked mode (enabling asserts and type
+   * checks), respectively in production mode (disabling asserts and type
+   * checks), if possible. If the parameter is omitted, the new isolate will
+   * inherit the value from the current isolate.
+   *
+   * In Dart2 strong mode, the `checked` parameter only controls asserts, but
+   * not type checks.
+   *
+   * It may not always be possible to honor the `checked` parameter.
+   * If the isolate code was pre-compiled, it may not be possible to change
+   * the checked mode setting dynamically.
+   * In that case, the `checked` parameter is ignored.
+   *
+   * WARNING: The [checked] parameter is not implemented on all platforms yet.
+   *
+   * If the [packageConfig] parameter is provided, then it is used to find the
+   * location of a package resolution configuration file for the spawned
+   * isolate.
+   *
+   * If the [automaticPackageResolution] parameter is provided, then the
+   * location of the package sources in the spawned isolate is automatically
+   * determined.
+   *
+   * The [environment] is a mapping from strings to strings which the
+   * spawned isolate uses when looking up [String.fromEnvironment] values.
+   * The system may add its own entries to environment as well.
+   * If `environment` is omitted, the spawned isolate has the same environment
+   * declarations as the spawning isolate.
+   *
+   * WARNING: The [environment] parameter is not implemented on all
+   * platforms yet.
+   *
+   * If [debugName] is provided, the spawned [Isolate] will be identifiable by
+   * this name in debuggers and logging.
+   *
+   * Returns a future that will complete with an [Isolate] instance if the
+   * spawning succeeded. It will complete with an error otherwise.
+   */
+  external static Future<Isolate> spawnUri(
+      Uri uri,
+      List<String> args,
+      var message,
+      {bool paused: false,
+      SendPort onExit,
+      SendPort onError,
+      bool errorsAreFatal,
+      bool checked,
+      Map<String, String> environment,
+      @Deprecated('The packages/ dir is not supported in Dart 2')
+          Uri packageRoot,
+      Uri packageConfig,
+      bool automaticPackageResolution: false,
+      @Since("2.3")
+          String debugName});
+
+  /**
+   * Requests the isolate to pause.
+   *
+   * When the isolate receives the pause command, it stops
+   * processing events from the event loop queue.
+   * It may still add new events to the queue in response to, e.g., timers
+   * or receive-port messages. When the isolate is resumed,
+   * it starts handling the already enqueued events.
+   *
+   * The pause request is sent through the isolate's command port,
+   * which bypasses the receiving isolate's event loop.
+   * The pause takes effect when it is received, pausing the event loop
+   * as it is at that time.
+   *
+   * The [resumeCapability] is used to identity the pause,
+   * and must be used again to end the pause using [resume].
+   * If [resumeCapability] is omitted, a new capability object is created
+   * and used instead.
+   *
+   * If an isolate is paused more than once using the same capability,
+   * only one resume with that capability is needed to end the pause.
+   *
+   * If an isolate is paused using more than one capability,
+   * each pause must be individually ended before the isolate resumes.
+   *
+   * Returns the capability that must be used to end the pause.
+   * This is either [resumeCapability], or a new capability when
+   * [resumeCapability] is omitted.
+   *
+   * If [pauseCapability] is `null`, or it's not the pause capability
+   * of the isolate identified by [controlPort],
+   * the pause request is ignored by the receiving isolate.
+   */
+  Capability pause([Capability resumeCapability]) {
+    resumeCapability ??= new Capability();
+    _pause(resumeCapability);
+    return resumeCapability;
+  }
+
+  /** Internal implementation of [pause]. */
+  external void _pause(Capability resumeCapability);
+
+  /**
+   * Resumes a paused isolate.
+   *
+   * Sends a message to an isolate requesting that it ends a pause
+   * that was previously requested.
+   *
+   * When all active pause requests have been cancelled, the isolate
+   * will continue processing events and handling normal messages.
+   *
+   * If the [resumeCapability] is not one that has previously been used
+   * to pause the isolate, or it has already been used to resume from
+   * that pause, the resume call has no effect.
+   */
+  external void resume(Capability resumeCapability);
+
+  /**
+   * Requests an exit message on [responsePort] when the isolate terminates.
+   *
+   * The isolate will send [response] as a message on [responsePort] as the last
+   * thing before it terminates. It will run no further code after the message
+   * has been sent.
+   *
+   * Adding the same port more than once will only cause it to receive one exit
+   * message, using the last response value that was added,
+   * and it only needs to be removed once using [removeOnExitListener].
+   *
+   * If the isolate has terminated before it can receive this request,
+   * no exit message will be sent.
+   *
+   * The [response] object must follow the same restrictions as enforced by
+   * [SendPort.send].
+   * It is recommended to only use simple values that can be sent to all
+   * isolates, like `null`, booleans, numbers or strings.
+   *
+   * Since isolates run concurrently, it's possible for it to exit before the
+   * exit listener is established, and in that case no response will be
+   * sent on [responsePort].
+   * To avoid this, either use the corresponding parameter to the spawn
+   * function, or start the isolate paused, add the listener and
+   * then resume the isolate.
+   */
+  /* TODO(lrn): Can we do better? Can the system recognize this message and
+   * send a reply if the receiving isolate is dead?
+   */
+  external void addOnExitListener(SendPort responsePort, {Object response});
+
+  /**
+   * Stops listening for exit messages from the isolate.
+   *
+   * Requests for the isolate to not send exit messages on [responsePort].
+   * If the isolate isn't expecting to send exit messages on [responsePort],
+   * because the port hasn't been added using [addOnExitListener],
+   * or because it has already been removed, the request is ignored.
+   *
+   * If the same port has been passed via [addOnExitListener] more than once,
+   * only one call to `removeOnExitListener` is needed to stop it from receiving
+   * exit messages.
+   *
+   * Closing the receive port that is associated with the [responsePort] does
+   * not stop the isolate from sending uncaught errors, they are just going to
+   * be lost.
+   *
+   * An exit message may still be sent if the isolate terminates
+   * before this request is received and processed.
+   */
+  external void removeOnExitListener(SendPort responsePort);
+
+  /**
+   * Sets whether uncaught errors will terminate the isolate.
+   *
+   * If errors are fatal, any uncaught error will terminate the isolate
+   * event loop and shut down the isolate.
+   *
+   * This call requires the [terminateCapability] for the isolate.
+   * If the capability is absent or incorrect, no change is made.
+   *
+   * Since isolates run concurrently, it's possible for the receiving isolate
+   * to exit due to an error, before a request, using this method, has been
+   * received and processed.
+   * To avoid this, either use the corresponding parameter to the spawn
+   * function, or start the isolate paused, set errors non-fatal and
+   * then resume the isolate.
+   */
+  external void setErrorsFatal(bool errorsAreFatal);
+
+  /**
+   * Requests the isolate to shut down.
+   *
+   * The isolate is requested to terminate itself.
+   * The [priority] argument specifies when this must happen.
+   *
+   * The [priority], when provided, must be one of [immediate] or
+   * [beforeNextEvent] (the default).
+   * The shutdown is performed at different times depending on the priority:
+   *
+   * * `immediate`: The isolate shuts down as soon as possible.
+   *     Control messages are handled in order, so all previously sent control
+   *     events from this isolate will all have been processed.
+   *     The shutdown should happen no later than if sent with
+   *     `beforeNextEvent`.
+   *     It may happen earlier if the system has a way to shut down cleanly
+   *     at an earlier time, even during the execution of another event.
+   * * `beforeNextEvent`: The shutdown is scheduled for the next time
+   *     control returns to the event loop of the receiving isolate,
+   *     after the current event, and any already scheduled control events,
+   *     are completed.
+   *
+   * If [terminateCapability] is `null`, or it's not the terminate capability
+   * of the isolate identified by [controlPort],
+   * the kill request is ignored by the receiving isolate.
+   */
+  external void kill({int priority: beforeNextEvent});
+
+  /**
+   * Requests that the isolate send [response] on the [responsePort].
+   *
+   * The [response] object must follow the same restrictions as enforced by
+   * [SendPort.send].
+   * It is recommended to only use simple values that can be sent to all
+   * isolates, like `null`, booleans, numbers or strings.
+   *
+   * If the isolate is alive, it will eventually send `response`
+   * (defaulting to `null`) on the response port.
+   *
+   * The [priority] must be one of [immediate] or [beforeNextEvent].
+   * The response is sent at different times depending on the ping type:
+   *
+   * * `immediate`: The isolate responds as soon as it receives the
+   *     control message. This is after any previous control message
+   *     from the same isolate has been received and processed,
+   *     but may be during execution of another event.
+   * * `beforeNextEvent`: The response is scheduled for the next time
+   *     control returns to the event loop of the receiving isolate,
+   *     after the current event, and any already scheduled control events,
+   *     are completed.
+   */
+  external void ping(SendPort responsePort,
+      {Object response, int priority: immediate});
+
+  /**
+   * Requests that uncaught errors of the isolate are sent back to [port].
+   *
+   * The errors are sent back as two elements lists.
+   * The first element is a `String` representation of the error, usually
+   * created by calling `toString` on the error.
+   * The second element is a `String` representation of an accompanying
+   * stack trace, or `null` if no stack trace was provided.
+   * To convert this back to a [StackTrace] object, use [StackTrace.fromString].
+   *
+   * Listening using the same port more than once does nothing.
+   * A port will only receive each error once,
+   * and will only need to be removed once using [removeErrorListener].
+
+   * Closing the receive port that is associated with the port does not stop
+   * the isolate from sending uncaught errors, they are just going to be lost.
+   * Instead use [removeErrorListener] to stop receiving errors on [port].
+   *
+   * Since isolates run concurrently, it's possible for it to exit before the
+   * error listener is established. To avoid this, start the isolate paused,
+   * add the listener and then resume the isolate.
+   */
+  external void addErrorListener(SendPort port);
+
+  /**
+   * Stops listening for uncaught errors from the isolate.
+   *
+   * Requests for the isolate to not send uncaught errors on [port].
+   * If the isolate isn't expecting to send uncaught errors on [port],
+   * because the port hasn't been added using [addErrorListener],
+   * or because it has already been removed, the request is ignored.
+   *
+   * If the same port has been passed via [addErrorListener] more than once,
+   * only one call to `removeErrorListener` is needed to stop it from receiving
+   * uncaught errors.
+   *
+   * Uncaught errors message may still be sent by the isolate
+   * until this request is received and processed.
+   */
+  external void removeErrorListener(SendPort port);
+
+  /**
+   * Returns a broadcast stream of uncaught errors from the isolate.
+   *
+   * Each error is provided as an error event on the stream.
+   *
+   * The actual error object and stackTraces will not necessarily
+   * be the same object types as in the actual isolate, but they will
+   * always have the same [Object.toString] result.
+   *
+   * This stream is based on [addErrorListener] and [removeErrorListener].
+   */
+  Stream get errors {
+    StreamController controller;
+    RawReceivePort port;
+    void handleError(message) {
+      List listMessage = message;
+      String errorDescription = listMessage[0];
+      String stackDescription = listMessage[1];
+      var error = new RemoteError(errorDescription, stackDescription);
+      controller.addError(error, error.stackTrace);
+    }
+
+    controller = new StreamController.broadcast(
+        sync: true,
+        onListen: () {
+          port = new RawReceivePort(handleError);
+          this.addErrorListener(port.sendPort);
+        },
+        onCancel: () {
+          this.removeErrorListener(port.sendPort);
+          port.close();
+          port = null;
+        });
+    return controller.stream;
+  }
+}
+
+/**
+ * Sends messages to its [ReceivePort]s.
+ *
+ * [SendPort]s are created from [ReceivePort]s. Any message sent through
+ * a [SendPort] is delivered to its corresponding [ReceivePort]. There might be
+ * many [SendPort]s for the same [ReceivePort].
+ *
+ * [SendPort]s can be transmitted to other isolates, and they preserve equality
+ * when sent.
+ */
+abstract class SendPort implements Capability {
+  /**
+   * Sends an asynchronous [message] through this send port, to its
+   * corresponding `ReceivePort`.
+   *
+   * The content of [message] can be: primitive values (null, num, bool, double,
+   * String), instances of [SendPort], and lists and maps whose elements are any
+   * of these. List and maps are also allowed to be cyclic.
+   *
+   * In the special circumstances when two isolates share the same code and are
+   * running in the same process (e.g. isolates created via [Isolate.spawn]), it
+   * is also possible to send object instances (which would be copied in the
+   * process). This is currently only supported by the dartvm.  For now, the
+   * dart2js compiler only supports the restricted messages described above.
+   *
+   * The send happens immediately and doesn't block.  The corresponding receive
+   * port can receive the message as soon as its isolate's event loop is ready
+   * to deliver it, independently of what the sending isolate is doing.
+   */
+  void send(var message);
+
+  /**
+   * Tests whether [other] is a [SendPort] pointing to the same
+   * [ReceivePort] as this one.
+   */
+  bool operator ==(var other);
+
+  /**
+   * Returns an immutable hash code for this send port that is
+   * consistent with the == operator.
+   */
+  int get hashCode;
+}
+
+/**
+ * Together with [SendPort], the only means of communication between isolates.
+ *
+ * [ReceivePort]s have a `sendPort` getter which returns a [SendPort].
+ * Any message that is sent through this [SendPort]
+ * is delivered to the [ReceivePort] it has been created from. There, the
+ * message is dispatched to the `ReceivePort`'s listener.
+ *
+ * A [ReceivePort] is a non-broadcast stream. This means that it buffers
+ * incoming messages until a listener is registered. Only one listener can
+ * receive messages. See [Stream.asBroadcastStream] for transforming the port
+ * to a broadcast stream.
+ *
+ * A [ReceivePort] may have many [SendPort]s.
+ */
+abstract class ReceivePort implements Stream {
+  /**
+   * Opens a long-lived port for receiving messages.
+   *
+   * A [ReceivePort] is a non-broadcast stream. This means that it buffers
+   * incoming messages until a listener is registered. Only one listener can
+   * receive messages. See [Stream.asBroadcastStream] for transforming the port
+   * to a broadcast stream.
+   *
+   * A receive port is closed by canceling its subscription.
+   */
+  external factory ReceivePort();
+
+  /**
+   * Creates a [ReceivePort] from a [RawReceivePort].
+   *
+   * The handler of the given [rawPort] is overwritten during the construction
+   * of the result.
+   */
+  external factory ReceivePort.fromRawReceivePort(RawReceivePort rawPort);
+
+  /**
+   * Inherited from [Stream].
+   *
+   * Note that [onError] and [cancelOnError] are ignored since a ReceivePort
+   * will never receive an error.
+   *
+   * The [onDone] handler will be called when the stream closes.
+   * The stream closes when [close] is called.
+   */
+  StreamSubscription listen(void onData(var message),
+      {Function onError, void onDone(), bool cancelOnError});
+
+  /**
+   * Closes `this`.
+   *
+   * If the stream has not been canceled yet, adds a close-event to the event
+   * queue and discards any further incoming messages.
+   *
+   * If the stream has already been canceled this method has no effect.
+   */
+  void close();
+
+  /**
+   * Returns a [SendPort] that sends to this receive port.
+   */
+  SendPort get sendPort;
+}
+
+abstract class RawReceivePort {
+  /**
+   * Opens a long-lived port for receiving messages.
+   *
+   * A [RawReceivePort] is low level and does not work with [Zone]s. It
+   * can not be paused. The data-handler must be set before the first
+   * event is received.
+   */
+  external factory RawReceivePort([Function handler]);
+
+  /**
+   * Sets the handler that is invoked for every incoming message.
+   *
+   * The handler is invoked in the root-zone ([Zone.root]).
+   */
+  void set handler(Function newHandler);
+
+  /**
+   * Closes the port.
+   *
+   * After a call to this method any incoming message is silently dropped.
+   */
+  void close();
+
+  /**
+   * Returns a [SendPort] that sends to this raw receive port.
+   */
+  SendPort get sendPort;
+}
+
+/**
+ * Description of an error from another isolate.
+ *
+ * This error has the same `toString()` and `stackTrace.toString()` behavior
+ * as the original error, but has no other features of the original error.
+ */
+class RemoteError implements Error {
+  final String _description;
+  final StackTrace stackTrace;
+  RemoteError(String description, String stackDescription)
+      : _description = description,
+        stackTrace = new StackTrace.fromString(stackDescription);
+  String toString() => _description;
+}
+
+/**
+ * An efficiently transferable sequence of byte values.
+ *
+ * A [TransferableTypedData] is created from a number of bytes.
+ * This will take time proportional to the number of bytes.
+ *
+ * The [TransferableTypedData] can be moved between isolates, so
+ * sending it through a send port will only take constant time.
+ *
+ * When sent this way, the local transferable can no longer be materialized,
+ * and the received object is now the only way to materialize the data.
+ */
+@Since("2.3.2")
+abstract class TransferableTypedData {
+  /**
+   * Creates a new [TransferableTypedData] containing the bytes of [list].
+   *
+   * It must be possible to create a single [Uint8List] containing the
+   * bytes, so if there are more bytes than what the platform allows in
+   * a single [Uint8List], then creation fails.
+   */
+  external factory TransferableTypedData.fromList(List<TypedData> list);
+
+  /**
+   * Creates a new [ByteBuffer] containing the bytes stored in this [TransferableTypedData].
+   *
+   * The [TransferableTypedData] is a cross-isolate single-use resource.
+   * This method must not be called more than once on the same underlying
+   * transferable bytes, even if the calls occur in different isolates.
+   */
+  ByteBuffer materialize();
+}
diff --git a/sdk_nnbd/lib/isolate/isolate_sources.gni b/sdk_nnbd/lib/isolate/isolate_sources.gni
new file mode 100644
index 0000000..8af8ba1
--- /dev/null
+++ b/sdk_nnbd/lib/isolate/isolate_sources.gni
@@ -0,0 +1,10 @@
+# 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.
+
+isolate_sdk_sources = [
+  "isolate.dart",
+
+  # The above file needs to be first as it lists the parts below.
+  "capability.dart",
+]
diff --git a/sdk_nnbd/lib/js/_js.dart b/sdk_nnbd/lib/js/_js.dart
new file mode 100644
index 0000000..aef7ef9
--- /dev/null
+++ b/sdk_nnbd/lib/js/_js.dart
@@ -0,0 +1,21 @@
+// 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.
+
+/// Helper library used by `dart:js`.
+///
+/// This library hides any logic that is specific to the web, and allows us to
+/// support `dart:js` for compiling to javascript on the server (e.g. to target
+/// nodejs).
+library dart._js;
+
+/// Whether `o` is a browser object such as `Blob`, `Event`, `KeyRange`,
+/// `ImageData`, `Node`, and `Window`.
+///
+/// On non-web targets, this function always returns false.
+external bool isBrowserObject(dynamic o);
+
+/// Convert a browser object to it's Dart counterpart. None of these types are
+/// wrapped, but this function is needed to inform dart2js about the possible
+/// types that are used and that therefore cannot be tree-shaken.
+external Object convertFromBrowserObject(dynamic o);
diff --git a/sdk_nnbd/lib/js/_js_client.dart b/sdk_nnbd/lib/js/_js_client.dart
new file mode 100644
index 0000000..de25540
--- /dev/null
+++ b/sdk_nnbd/lib/js/_js_client.dart
@@ -0,0 +1,22 @@
+// 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 'dart:html' show Blob, Event, ImageData, Node, Window, WorkerGlobalScope;
+import 'dart:indexed_db' show KeyRange;
+import 'dart:_js_helper' show patch;
+import 'dart:_foreign_helper' show JS;
+
+@patch
+bool isBrowserObject(dynamic o) =>
+    o is Blob ||
+    o is Event ||
+    o is KeyRange ||
+    o is ImageData ||
+    o is Node ||
+    o is Window ||
+    o is WorkerGlobalScope;
+
+@patch
+Object convertFromBrowserObject(dynamic o) =>
+    JS('Blob|Event|KeyRange|ImageData|Node|Window|WorkerGlobalScope', '#', o);
diff --git a/sdk_nnbd/lib/js/_js_server.dart b/sdk_nnbd/lib/js/_js_server.dart
new file mode 100644
index 0000000..b941d77
--- /dev/null
+++ b/sdk_nnbd/lib/js/_js_server.dart
@@ -0,0 +1,11 @@
+// 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 'dart:_js_helper' show patch;
+
+@patch
+bool isBrowserObject(dynamic o) => false;
+
+@patch
+Object convertFromBrowserObject(dynamic o) => o;
diff --git a/sdk_nnbd/lib/js/dart2js/js_dart2js.dart b/sdk_nnbd/lib/js/dart2js/js_dart2js.dart
new file mode 100644
index 0000000..535227b
--- /dev/null
+++ b/sdk_nnbd/lib/js/dart2js/js_dart2js.dart
@@ -0,0 +1,719 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/**
+ * Support for interoperating with JavaScript.
+ *
+ * This library provides access to JavaScript objects from Dart, allowing
+ * Dart code to get and set properties, and call methods of JavaScript objects
+ * and invoke JavaScript functions. The library takes care of converting
+ * between Dart and JavaScript objects where possible, or providing proxies if
+ * conversion isn't possible.
+ *
+ * This library does not yet make Dart objects usable from JavaScript, their
+ * methods and proeprties are not accessible, though it does allow Dart
+ * functions to be passed into and called from JavaScript.
+ *
+ * [JsObject] is the core type and represents a proxy of a JavaScript object.
+ * JsObject gives access to the underlying JavaScript objects properties and
+ * methods. `JsObject`s can be acquired by calls to JavaScript, or they can be
+ * created from proxies to JavaScript constructors.
+ *
+ * The top-level getter [context] provides a [JsObject] that represents the
+ * global object in JavaScript, usually `window`.
+ *
+ * The following example shows an alert dialog via a JavaScript call to the
+ * global function `alert()`:
+ *
+ *     import 'dart:js';
+ *
+ *     main() => context.callMethod('alert', ['Hello from Dart!']);
+ *
+ * This example shows how to create a [JsObject] from a JavaScript constructor
+ * and access its properties:
+ *
+ *     import 'dart:js';
+ *
+ *     main() {
+ *       var object = new JsObject(context['Object']);
+ *       object['greeting'] = 'Hello';
+ *       object['greet'] = (name) => "${object['greeting']} $name";
+ *       var message = object.callMethod('greet', ['JavaScript']);
+ *       context['console'].callMethod('log', [message]);
+ *     }
+ *
+ * ## Proxying and automatic conversion
+ *
+ * When setting properties on a JsObject or passing arguments to a Javascript
+ * method or function, Dart objects are automatically converted or proxied to
+ * JavaScript objects. When accessing JavaScript properties, or when a Dart
+ * closure is invoked from JavaScript, the JavaScript objects are also
+ * converted to Dart.
+ *
+ * Functions and closures are proxied in such a way that they are callable. A
+ * Dart closure assigned to a JavaScript property is proxied by a function in
+ * JavaScript. A JavaScript function accessed from Dart is proxied by a
+ * [JsFunction], which has a [apply] method to invoke it.
+ *
+ * The following types are transferred directly and not proxied:
+ *
+ *   * Basic types: `null`, `bool`, `num`, `String`, `DateTime`
+ *   * `TypedData`, including its subclasses like `Int32List`, but _not_
+ *     `ByteBuffer`
+ *   * When compiling for the web, also: `Blob`, `Event`, `ImageData`,
+ *     `KeyRange`, `Node`, and `Window`.
+ *
+ * ## Converting collections with JsObject.jsify()
+ *
+ * To create a JavaScript collection from a Dart collection use the
+ * [JsObject.jsify] constructor, which converts Dart [Map]s and [Iterable]s
+ * into JavaScript Objects and Arrays.
+ *
+ * The following expression creates a new JavaScript object with the properties
+ * `a` and `b` defined:
+ *
+ *     var jsMap = new JsObject.jsify({'a': 1, 'b': 2});
+ *
+ * This expression creates a JavaScript array:
+ *
+ *     var jsArray = new JsObject.jsify([1, 2, 3]);
+ *
+ * {@category Web}
+ */
+library dart.js;
+
+import 'dart:collection' show HashMap, ListMixin;
+import 'dart:typed_data' show TypedData;
+
+import 'dart:_foreign_helper' show JS, JS_CONST, DART_CLOSURE_TO_JS;
+import 'dart:_interceptors'
+    show
+        JavaScriptFunction,
+        JavaScriptObject,
+        UnknownJavaScriptObject,
+        DART_CLOSURE_PROPERTY_NAME;
+import 'dart:_js_helper'
+    show Primitives, convertDartClosureToJS, getIsolateAffinityTag;
+import 'dart:_js' show isBrowserObject, convertFromBrowserObject;
+
+export 'dart:_interceptors' show JavaScriptObject;
+
+final JsObject context = _wrapToDart(JS('', 'self'));
+
+_convertDartFunction(Function f, {bool captureThis: false}) {
+  return JS(
+      'JavaScriptFunction',
+      '''
+        function(_call, f, captureThis) {
+          return function() {
+            return _call(f, captureThis, this,
+                Array.prototype.slice.apply(arguments));
+          }
+        }(#, #, #)
+      ''',
+      DART_CLOSURE_TO_JS(_callDartFunction),
+      f,
+      captureThis);
+}
+
+_callDartFunction(callback, bool captureThis, self, List arguments) {
+  if (captureThis) {
+    arguments = [self]..addAll(arguments);
+  }
+  var dartArgs = new List.from(arguments.map(_convertToDart));
+  return _convertToJS(Function.apply(callback, dartArgs));
+}
+
+/**
+ * Proxies a JavaScript object to Dart.
+ *
+ * The properties of the JavaScript object are accessible via the `[]` and
+ * `[]=` operators. Methods are callable via [callMethod].
+ */
+class JsObject {
+  // The wrapped JS object.
+  final dynamic _jsObject;
+
+  // This shoud only be called from _wrapToDart
+  JsObject._fromJs(this._jsObject) {
+    assert(_jsObject != null);
+  }
+
+  /**
+   * Constructs a new JavaScript object from [constructor] and returns a proxy
+   * to it.
+   */
+  factory JsObject(JsFunction constructor, [List arguments]) {
+    var constr = _convertToJS(constructor);
+    if (arguments == null) {
+      return _wrapToDart(JS('', 'new #()', constr));
+    }
+
+    if (JS('bool', '# instanceof Array', arguments)) {
+      int argumentCount = JS('int', '#.length', arguments);
+      switch (argumentCount) {
+        case 0:
+          return _wrapToDart(JS('', 'new #()', constr));
+
+        case 1:
+          var arg0 = _convertToJS(JS('', '#[0]', arguments));
+          return _wrapToDart(JS('', 'new #(#)', constr, arg0));
+
+        case 2:
+          var arg0 = _convertToJS(JS('', '#[0]', arguments));
+          var arg1 = _convertToJS(JS('', '#[1]', arguments));
+          return _wrapToDart(JS('', 'new #(#, #)', constr, arg0, arg1));
+
+        case 3:
+          var arg0 = _convertToJS(JS('', '#[0]', arguments));
+          var arg1 = _convertToJS(JS('', '#[1]', arguments));
+          var arg2 = _convertToJS(JS('', '#[2]', arguments));
+          return _wrapToDart(
+              JS('', 'new #(#, #, #)', constr, arg0, arg1, arg2));
+
+        case 4:
+          var arg0 = _convertToJS(JS('', '#[0]', arguments));
+          var arg1 = _convertToJS(JS('', '#[1]', arguments));
+          var arg2 = _convertToJS(JS('', '#[2]', arguments));
+          var arg3 = _convertToJS(JS('', '#[3]', arguments));
+          return _wrapToDart(
+              JS('', 'new #(#, #, #, #)', constr, arg0, arg1, arg2, arg3));
+      }
+    }
+
+    // The following code solves the problem of invoking a JavaScript
+    // constructor with an unknown number arguments.
+    // First bind the constructor to the argument list using bind.apply().
+    // The first argument to bind() is the binding of 'this', so add 'null' to
+    // the arguments list passed to apply().
+    // After that, use the JavaScript 'new' operator which overrides any binding
+    // of 'this' with the new instance.
+    var args = <dynamic>[null]..addAll(arguments.map(_convertToJS));
+    var factoryFunction = JS('', '#.bind.apply(#, #)', constr, constr, args);
+    // Without this line, calling factoryFunction as a constructor throws
+    JS('String', 'String(#)', factoryFunction);
+    // This could return an UnknownJavaScriptObject, or a native
+    // object for which there is an interceptor
+    var jsObj = JS('', 'new #()', factoryFunction);
+
+    return _wrapToDart(jsObj);
+
+    // TODO(sra): Investigate:
+    //
+    //     var jsObj = JS('', 'Object.create(#.prototype)', constr);
+    //     JS('', '#.apply(#, #)', constr, jsObj,
+    //         []..addAll(arguments.map(_convertToJS)));
+    //     return _wrapToDart(jsObj);
+  }
+
+  /**
+   * Constructs a [JsObject] that proxies a native Dart object; _for expert use
+   * only_.
+   *
+   * Use this constructor only if you wish to get access to JavaScript
+   * properties attached to a browser host object, such as a Node or Blob, that
+   * is normally automatically converted into a native Dart object.
+   *
+   * An exception will be thrown if [object] either is `null` or has the type
+   * `bool`, `num`, or `String`.
+   */
+  factory JsObject.fromBrowserObject(object) {
+    if (object is num || object is String || object is bool || object == null) {
+      throw new ArgumentError("object cannot be a num, string, bool, or null");
+    }
+    return _wrapToDart(_convertToJS(object));
+  }
+
+  /**
+   * Recursively converts a JSON-like collection of Dart objects to a
+   * collection of JavaScript objects and returns a [JsObject] proxy to it.
+   *
+   * [object] must be a [Map] or [Iterable], the contents of which are also
+   * converted. Maps and Iterables are copied to a new JavaScript object.
+   * Primitives and other transferrable values are directly converted to their
+   * JavaScript type, and all other objects are proxied.
+   */
+  factory JsObject.jsify(object) {
+    if ((object is! Map) && (object is! Iterable)) {
+      throw new ArgumentError("object must be a Map or Iterable");
+    }
+    return _wrapToDart(_convertDataTree(object));
+  }
+
+  static _convertDataTree(data) {
+    var _convertedObjects = new HashMap.identity();
+
+    _convert(o) {
+      if (_convertedObjects.containsKey(o)) {
+        return _convertedObjects[o];
+      }
+      if (o is Map) {
+        final convertedMap = JS('=Object', '{}');
+        _convertedObjects[o] = convertedMap;
+        for (var key in o.keys) {
+          JS('=Object', '#[#]=#', convertedMap, key, _convert(o[key]));
+        }
+        return convertedMap;
+      } else if (o is Iterable) {
+        var convertedList = [];
+        _convertedObjects[o] = convertedList;
+        convertedList.addAll(o.map(_convert));
+        return convertedList;
+      } else {
+        return _convertToJS(o);
+      }
+    }
+
+    return _convert(data);
+  }
+
+  /**
+   * Returns the value associated with [property] from the proxied JavaScript
+   * object.
+   *
+   * The type of [property] must be either [String] or [num].
+   */
+  dynamic operator [](property) {
+    if (property is! String && property is! num) {
+      throw new ArgumentError("property is not a String or num");
+    }
+    return _convertToDart(JS('', '#[#]', _jsObject, property));
+  }
+
+  /**
+   * Sets the value associated with [property] on the proxied JavaScript
+   * object.
+   *
+   * The type of [property] must be either [String] or [num].
+   */
+  operator []=(property, value) {
+    if (property is! String && property is! num) {
+      throw new ArgumentError("property is not a String or num");
+    }
+    JS('', '#[#]=#', _jsObject, property, _convertToJS(value));
+  }
+
+  int get hashCode => 0;
+
+  bool operator ==(other) =>
+      other is JsObject && JS('bool', '# === #', _jsObject, other._jsObject);
+
+  /**
+   * Returns `true` if the JavaScript object contains the specified property
+   * either directly or though its prototype chain.
+   *
+   * This is the equivalent of the `in` operator in JavaScript.
+   */
+  bool hasProperty(property) {
+    if (property is! String && property is! num) {
+      throw new ArgumentError("property is not a String or num");
+    }
+    return JS('bool', '# in #', property, _jsObject);
+  }
+
+  /**
+   * Removes [property] from the JavaScript object.
+   *
+   * This is the equivalent of the `delete` operator in JavaScript.
+   */
+  void deleteProperty(property) {
+    if (property is! String && property is! num) {
+      throw new ArgumentError("property is not a String or num");
+    }
+    JS('bool', 'delete #[#]', _jsObject, property);
+  }
+
+  /**
+   * Returns `true` if the JavaScript object has [type] in its prototype chain.
+   *
+   * This is the equivalent of the `instanceof` operator in JavaScript.
+   */
+  bool instanceof(JsFunction type) {
+    return JS('bool', '# instanceof #', _jsObject, _convertToJS(type));
+  }
+
+  /**
+   * Returns the result of the JavaScript objects `toString` method.
+   */
+  String toString() {
+    try {
+      return JS('String', 'String(#)', _jsObject);
+    } catch (e) {
+      return super.toString();
+    }
+  }
+
+  /**
+   * Calls [method] on the JavaScript object with the arguments [args] and
+   * returns the result.
+   *
+   * The type of [method] must be either [String] or [num].
+   */
+  dynamic callMethod(method, [List args]) {
+    if (method is! String && method is! num) {
+      throw new ArgumentError("method is not a String or num");
+    }
+    return _convertToDart(JS(
+        '',
+        '#[#].apply(#, #)',
+        _jsObject,
+        method,
+        _jsObject,
+        args == null ? null : new List.from(args.map(_convertToJS))));
+  }
+}
+
+/**
+ * Proxies a JavaScript Function object.
+ */
+class JsFunction extends JsObject {
+  /**
+   * Returns a [JsFunction] that captures its 'this' binding and calls [f]
+   * with the value of this passed as the first argument.
+   */
+  factory JsFunction.withThis(Function f) {
+    var jsFunc = _convertDartFunction(f, captureThis: true);
+    return new JsFunction._fromJs(jsFunc);
+  }
+
+  JsFunction._fromJs(jsObject) : super._fromJs(jsObject);
+
+  /**
+   * Invokes the JavaScript function with arguments [args]. If [thisArg] is
+   * supplied it is the value of `this` for the invocation.
+   */
+  dynamic apply(List args, {thisArg}) => _convertToDart(JS(
+      '',
+      '#.apply(#, #)',
+      _jsObject,
+      _convertToJS(thisArg),
+      args == null ? null : new List.from(args.map(_convertToJS))));
+}
+
+/**
+ * A [List] that proxies a JavaScript array.
+ */
+class JsArray<E> extends JsObject with ListMixin<E> {
+  /**
+   * Creates a new JavaScript array.
+   */
+  JsArray() : super._fromJs([]);
+
+  /**
+   * Creates a new JavaScript array and initializes it to the contents of
+   * [other].
+   */
+  JsArray.from(Iterable<E> other)
+      : super._fromJs([]..addAll(other.map(_convertToJS)));
+
+  JsArray._fromJs(jsObject) : super._fromJs(jsObject);
+
+  _checkIndex(int index) {
+    if (index is int && (index < 0 || index >= length)) {
+      throw new RangeError.range(index, 0, length);
+    }
+  }
+
+  _checkInsertIndex(int index) {
+    if (index is int && (index < 0 || index >= length + 1)) {
+      throw new RangeError.range(index, 0, length);
+    }
+  }
+
+  static _checkRange(int start, int end, int length) {
+    if (start < 0 || start > length) {
+      throw new RangeError.range(start, 0, length);
+    }
+    if (end < start || end > length) {
+      throw new RangeError.range(end, start, length);
+    }
+  }
+
+  // Methods required by ListMixin
+
+  E operator [](dynamic index) {
+    // TODO(justinfagnani): fix the semantics for non-ints
+    // dartbug.com/14605
+    if (index is num && index == index.toInt()) {
+      _checkIndex(index);
+    }
+    return super[index];
+  }
+
+  void operator []=(dynamic index, E value) {
+    // TODO(justinfagnani): fix the semantics for non-ints
+    // dartbug.com/14605
+    if (index is num && index == index.toInt()) {
+      _checkIndex(index);
+    }
+    super[index] = value;
+  }
+
+  int get length {
+    // Check the length honours the List contract.
+    var len = JS('', '#.length', _jsObject);
+    // JavaScript arrays have lengths which are unsigned 32-bit integers.
+    if (JS('bool', 'typeof # === "number" && (# >>> 0) === #', len, len, len)) {
+      return JS('int', '#', len);
+    }
+    throw new StateError('Bad JsArray length');
+  }
+
+  void set length(int length) {
+    super['length'] = length;
+  }
+
+  // Methods overridden for better performance
+
+  void add(E value) {
+    callMethod('push', [value]);
+  }
+
+  void addAll(Iterable<E> iterable) {
+    var list = (JS('bool', '# instanceof Array', iterable))
+        ? iterable
+        : new List.from(iterable);
+    callMethod('push', list);
+  }
+
+  void insert(int index, E element) {
+    _checkInsertIndex(index);
+    callMethod('splice', [index, 0, element]);
+  }
+
+  E removeAt(int index) {
+    _checkIndex(index);
+    return callMethod('splice', [index, 1])[0];
+  }
+
+  E removeLast() {
+    if (length == 0) throw new RangeError(-1);
+    return callMethod('pop');
+  }
+
+  void removeRange(int start, int end) {
+    _checkRange(start, end, length);
+    callMethod('splice', [start, end - start]);
+  }
+
+  void setRange(int start, int end, Iterable<E> iterable, [int skipCount = 0]) {
+    _checkRange(start, end, this.length);
+    int length = end - start;
+    if (length == 0) return;
+    if (skipCount < 0) throw new ArgumentError(skipCount);
+    var args = <dynamic>[start, length]
+      ..addAll(iterable.skip(skipCount).take(length));
+    callMethod('splice', args);
+  }
+
+  void sort([int compare(E a, E b)]) {
+    // Note: arr.sort(null) is a type error in FF
+    callMethod('sort', compare == null ? [] : [compare]);
+  }
+}
+
+// property added to a Dart object referencing its JS-side DartObject proxy
+final String _DART_OBJECT_PROPERTY_NAME =
+    getIsolateAffinityTag(r'_$dart_dartObject');
+
+// property added to a JS object referencing its Dart-side JsObject proxy
+const _JS_OBJECT_PROPERTY_NAME = r'_$dart_jsObject';
+const _JS_FUNCTION_PROPERTY_NAME = r'$dart_jsFunction';
+const _JS_FUNCTION_PROPERTY_NAME_CAPTURE_THIS = r'_$dart_jsFunctionCaptureThis';
+
+bool _defineProperty(o, String name, value) {
+  try {
+    if (_isExtensible(o) &&
+        // TODO(ahe): Calling _hasOwnProperty to work around
+        // https://code.google.com/p/dart/issues/detail?id=21331.
+        !_hasOwnProperty(o, name)) {
+      JS('void', 'Object.defineProperty(#, #, { value: #})', o, name, value);
+      return true;
+    }
+  } catch (e) {
+    // object is native and lies about being extensible
+    // see https://bugzilla.mozilla.org/show_bug.cgi?id=775185
+    // Or, isExtensible throws for this object.
+  }
+  return false;
+}
+
+bool _hasOwnProperty(o, String name) {
+  return JS('bool', 'Object.prototype.hasOwnProperty.call(#, #)', o, name);
+}
+
+bool _isExtensible(o) => JS('bool', 'Object.isExtensible(#)', o);
+
+Object _getOwnProperty(o, String name) {
+  if (_hasOwnProperty(o, name)) {
+    return JS('', '#[#]', o, name);
+  }
+  return null;
+}
+
+bool _isLocalObject(o) => JS('bool', '# instanceof Object', o);
+
+// The shared constructor function for proxies to Dart objects in JavaScript.
+final _dartProxyCtor = JS('', 'function DartObject(o) { this.o = o; }');
+
+dynamic _convertToJS(dynamic o) {
+  // Note: we don't write `if (o == null) return null;` to make sure dart2js
+  // doesn't convert `return null;` into `return;` (which would make `null` be
+  // `undefined` in Javascprit). See dartbug.com/20305 for details.
+  if (o == null || o is String || o is num || o is bool) {
+    return o;
+  }
+  if (o is JsObject) {
+    return o._jsObject;
+  }
+  if (isBrowserObject(o)) {
+    return o;
+  }
+  if (o is TypedData) {
+    return o;
+  }
+  if (o is DateTime) {
+    return Primitives.lazyAsJsDate(o);
+  }
+  if (o is Function) {
+    return _getJsProxy(o, _JS_FUNCTION_PROPERTY_NAME, (o) {
+      var jsFunction = _convertDartFunction(o);
+      // set a property on the JS closure referencing the Dart closure
+      _defineProperty(jsFunction, DART_CLOSURE_PROPERTY_NAME, o);
+      return jsFunction;
+    });
+  }
+  var ctor = _dartProxyCtor;
+  return _getJsProxy(
+      o, _JS_OBJECT_PROPERTY_NAME, (o) => JS('', 'new #(#)', ctor, o));
+}
+
+Object _getJsProxy(o, String propertyName, createProxy(o)) {
+  var jsProxy = _getOwnProperty(o, propertyName);
+  if (jsProxy == null) {
+    jsProxy = createProxy(o);
+    _defineProperty(o, propertyName, jsProxy);
+  }
+  return jsProxy;
+}
+
+// converts a Dart object to a reference to a native JS object
+// which might be a DartObject JS->Dart proxy
+Object _convertToDart(o) {
+  if (JS('bool', '# == null', o) ||
+      JS('bool', 'typeof # == "string"', o) ||
+      JS('bool', 'typeof # == "number"', o) ||
+      JS('bool', 'typeof # == "boolean"', o)) {
+    return o;
+  } else if (_isLocalObject(o) && isBrowserObject(o)) {
+    return convertFromBrowserObject(o);
+  } else if (_isLocalObject(o) && o is TypedData) {
+    return JS('TypedData', '#', o);
+  } else if (JS('bool', '# instanceof Date', o)) {
+    var ms = JS('num', '#.getTime()', o);
+    return new DateTime.fromMillisecondsSinceEpoch(ms);
+  } else if (JS('bool', '#.constructor === #', o, _dartProxyCtor)) {
+    return JS('', '#.o', o);
+  } else {
+    return _wrapToDart(o);
+  }
+}
+
+Object _wrapToDart(o) {
+  if (JS('bool', 'typeof # == "function"', o)) {
+    return _getDartProxy(
+        o, DART_CLOSURE_PROPERTY_NAME, (o) => new JsFunction._fromJs(o));
+  }
+  if (JS('bool', '# instanceof Array', o)) {
+    return _getDartProxy(
+        o, _DART_OBJECT_PROPERTY_NAME, (o) => new JsArray._fromJs(o));
+  }
+  return _getDartProxy(
+      o, _DART_OBJECT_PROPERTY_NAME, (o) => new JsObject._fromJs(o));
+}
+
+Object _getDartProxy(o, String propertyName, createProxy(o)) {
+  var dartProxy = _getOwnProperty(o, propertyName);
+  // Temporary fix for dartbug.com/15193
+  // In some cases it's possible to see a JavaScript object that
+  // came from a different context and was previously proxied to
+  // Dart in that context. The JS object will have a cached proxy
+  // but it won't be a valid Dart object in this context.
+  // For now we throw away the cached proxy, but we should be able
+  // to cache proxies from multiple JS contexts and Dart isolates.
+  if (dartProxy == null || !_isLocalObject(o)) {
+    dartProxy = createProxy(o);
+    _defineProperty(o, propertyName, dartProxy);
+  }
+  return dartProxy;
+}
+
+// ---------------------------------------------------------------------------
+// Start of methods for new style Dart-JS interop.
+
+_convertDartFunctionFast(Function f) {
+  var existing = JS('', '#.#', f, _JS_FUNCTION_PROPERTY_NAME);
+  if (existing != null) return existing;
+  var ret = JS(
+      'JavaScriptFunction',
+      '''
+        function(_call, f) {
+          return function() {
+            return _call(f, Array.prototype.slice.apply(arguments));
+          }
+        }(#, #)
+      ''',
+      DART_CLOSURE_TO_JS(_callDartFunctionFast),
+      f);
+  JS('', '#.# = #', ret, DART_CLOSURE_PROPERTY_NAME, f);
+  JS('', '#.# = #', f, _JS_FUNCTION_PROPERTY_NAME, ret);
+  return ret;
+}
+
+_convertDartFunctionFastCaptureThis(Function f) {
+  var existing = JS('', '#.#', f, _JS_FUNCTION_PROPERTY_NAME_CAPTURE_THIS);
+  if (existing != null) return existing;
+  var ret = JS(
+      'JavaScriptFunction',
+      '''
+        function(_call, f) {
+          return function() {
+            return _call(f, this,Array.prototype.slice.apply(arguments));
+          }
+        }(#, #)
+      ''',
+      DART_CLOSURE_TO_JS(_callDartFunctionFastCaptureThis),
+      f);
+  JS('', '#.# = #', ret, DART_CLOSURE_PROPERTY_NAME, f);
+  JS('', '#.# = #', f, _JS_FUNCTION_PROPERTY_NAME_CAPTURE_THIS, ret);
+  return ret;
+}
+
+_callDartFunctionFast(callback, List arguments) {
+  return Function.apply(callback, arguments);
+}
+
+_callDartFunctionFastCaptureThis(callback, self, List arguments) {
+  return Function.apply(callback, [self]..addAll(arguments));
+}
+
+F allowInterop<F extends Function>(F f) {
+  if (JS('bool', 'typeof(#) == "function"', f)) {
+    // Already supports interop, just use the existing function.
+    return f;
+  } else {
+    return _convertDartFunctionFast(f);
+  }
+}
+
+Function allowInteropCaptureThis(Function f) {
+  if (JS('bool', 'typeof(#) == "function"', f)) {
+    // Behavior when the function is already a JS function is unspecified.
+    throw new ArgumentError(
+        "Function is already a JS function so cannot capture this.");
+    return f;
+  } else {
+    return _convertDartFunctionFastCaptureThis(f);
+  }
+}
diff --git a/sdk_nnbd/lib/js_util/dart2js/js_util_dart2js.dart b/sdk_nnbd/lib/js_util/dart2js/js_util_dart2js.dart
new file mode 100644
index 0000000..6b605fb
--- /dev/null
+++ b/sdk_nnbd/lib/js_util/dart2js/js_util_dart2js.dart
@@ -0,0 +1,128 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// Utility methods to efficiently manipulate typed JSInterop objects in cases
+/// where the name to call is not known at runtime. You should only use these
+/// methods when the same effect cannot be achieved with @JS annotations.
+/// These methods would be extension methods on JSObject if Dart supported
+/// extension methods.
+///
+/// {@category Web}
+library dart.js_util;
+
+import 'dart:_foreign_helper' show JS;
+import 'dart:collection' show HashMap;
+
+/// WARNING: performance of this method is much worse than other util
+/// methods in this library. Only use this method as a last resort.
+///
+/// Recursively converts a JSON-like collection of Dart objects to a
+/// collection of JavaScript objects and returns a [JsObject] proxy to it.
+///
+/// [object] must be a [Map] or [Iterable], the contents of which are also
+/// converted. Maps and Iterables are copied to a new JavaScript object.
+/// Primitives and other transferable values are directly converted to their
+/// JavaScript type, and all other objects are proxied.
+jsify(object) {
+  if ((object is! Map) && (object is! Iterable)) {
+    throw new ArgumentError("object must be a Map or Iterable");
+  }
+  return _convertDataTree(object);
+}
+
+_convertDataTree(data) {
+  var _convertedObjects = new HashMap.identity();
+
+  _convert(o) {
+    if (_convertedObjects.containsKey(o)) {
+      return _convertedObjects[o];
+    }
+    if (o is Map) {
+      final convertedMap = JS('=Object', '{}');
+      _convertedObjects[o] = convertedMap;
+      for (var key in o.keys) {
+        JS('=Object', '#[#]=#', convertedMap, key, _convert(o[key]));
+      }
+      return convertedMap;
+    } else if (o is Iterable) {
+      var convertedList = [];
+      _convertedObjects[o] = convertedList;
+      convertedList.addAll(o.map(_convert));
+      return convertedList;
+    } else {
+      return o;
+    }
+  }
+
+  return _convert(data);
+}
+
+newObject() => JS('=Object', '{}');
+
+bool hasProperty(o, name) => JS('bool', '# in #', name, o);
+getProperty(o, name) => JS('Object|Null', '#[#]', o, name);
+setProperty(o, name, value) => JS('', '#[#]=#', o, name, value);
+
+callMethod(o, String method, List args) =>
+    JS('Object|Null', '#[#].apply(#, #)', o, method, o, args);
+
+bool instanceof(o, Function type) => JS('bool', '# instanceof #', o, type);
+callConstructor(Function constr, List arguments) {
+  if (arguments == null) {
+    return JS('Object', 'new #()', constr);
+  }
+
+  if (JS('bool', '# instanceof Array', arguments)) {
+    int argumentCount = JS('int', '#.length', arguments);
+    switch (argumentCount) {
+      case 0:
+        return JS('Object', 'new #()', constr);
+
+      case 1:
+        var arg0 = JS('', '#[0]', arguments);
+        return JS('Object', 'new #(#)', constr, arg0);
+
+      case 2:
+        var arg0 = JS('', '#[0]', arguments);
+        var arg1 = JS('', '#[1]', arguments);
+        return JS('Object', 'new #(#, #)', constr, arg0, arg1);
+
+      case 3:
+        var arg0 = JS('', '#[0]', arguments);
+        var arg1 = JS('', '#[1]', arguments);
+        var arg2 = JS('', '#[2]', arguments);
+        return JS('Object', 'new #(#, #, #)', constr, arg0, arg1, arg2);
+
+      case 4:
+        var arg0 = JS('', '#[0]', arguments);
+        var arg1 = JS('', '#[1]', arguments);
+        var arg2 = JS('', '#[2]', arguments);
+        var arg3 = JS('', '#[3]', arguments);
+        return JS(
+            'Object', 'new #(#, #, #, #)', constr, arg0, arg1, arg2, arg3);
+    }
+  }
+
+  // The following code solves the problem of invoking a JavaScript
+  // constructor with an unknown number arguments.
+  // First bind the constructor to the argument list using bind.apply().
+  // The first argument to bind() is the binding of 't', so add 'null' to
+  // the arguments list passed to apply().
+  // After that, use the JavaScript 'new' operator which overrides any binding
+  // of 'this' with the new instance.
+  var args = <dynamic>[null]..addAll(arguments);
+  var factoryFunction = JS('', '#.bind.apply(#, #)', constr, constr, args);
+  // Without this line, calling factoryFunction as a constructor throws
+  JS('String', 'String(#)', factoryFunction);
+  // This could return an UnknownJavaScriptObject, or a native
+  // object for which there is an interceptor
+  return JS('Object', 'new #()', factoryFunction);
+
+  // TODO(sra): Investigate:
+  //
+  //     var jsObj = JS('', 'Object.create(#.prototype)', constr);
+  //     JS('', '#.apply(#, #)', constr, jsObj,
+  //         []..addAll(arguments.map(_convertToJS)));
+  //     return _wrapToDart(jsObj);
+}
diff --git a/sdk_nnbd/lib/libraries.json b/sdk_nnbd/lib/libraries.json
new file mode 100644
index 0000000..663991f
--- /dev/null
+++ b/sdk_nnbd/lib/libraries.json
@@ -0,0 +1,490 @@
+{
+  "comment:0": "NOTE: THIS FILE IS GENERATED. DO NOT EDIT.",
+  "comment:1": "Instead modify 'sdk/lib/libraries.yaml' and follow the instructions therein.",
+  "vm": {
+    "libraries": {
+      "_builtin": {
+        "uri": "../../runtime/bin/builtin.dart"
+      },
+      "cli": {
+        "patches": [
+          "../../runtime/bin/cli_patch.dart"
+        ],
+        "uri": "cli/cli.dart"
+      },
+      "core": {
+        "patches": [
+          "../../runtime/lib/core_patch.dart",
+          "../../runtime/lib/array.dart",
+          "../../runtime/lib/array_patch.dart",
+          "../../runtime/lib/bigint_patch.dart",
+          "../../runtime/lib/bool_patch.dart",
+          "../../runtime/lib/date_patch.dart",
+          "../../runtime/lib/double.dart",
+          "../../runtime/lib/double_patch.dart",
+          "../../runtime/lib/errors_patch.dart",
+          "../../runtime/lib/expando_patch.dart",
+          "../../runtime/lib/function.dart",
+          "../../runtime/lib/function_patch.dart",
+          "../../runtime/lib/growable_array.dart",
+          "../../runtime/lib/identical_patch.dart",
+          "../../runtime/lib/immutable_map.dart",
+          "../../runtime/lib/integers.dart",
+          "../../runtime/lib/integers_patch.dart",
+          "../../runtime/lib/invocation_mirror_patch.dart",
+          "../../runtime/lib/lib_prefix.dart",
+          "../../runtime/lib/map_patch.dart",
+          "../../runtime/lib/null_patch.dart",
+          "../../runtime/lib/object_patch.dart",
+          "../../runtime/lib/regexp_patch.dart",
+          "../../runtime/lib/stacktrace.dart",
+          "../../runtime/lib/stopwatch_patch.dart",
+          "../../runtime/lib/string_buffer_patch.dart",
+          "../../runtime/lib/string_patch.dart",
+          "../../runtime/lib/type_patch.dart",
+          "../../runtime/lib/uri_patch.dart",
+          "../../runtime/lib/weak_property.dart"
+        ],
+        "uri": "core/core.dart"
+      },
+      "async": {
+        "patches": [
+          "../../runtime/lib/async_patch.dart",
+          "../../runtime/lib/deferred_load_patch.dart",
+          "../../runtime/lib/schedule_microtask_patch.dart",
+          "../../runtime/lib/timer_patch.dart"
+        ],
+        "uri": "async/async.dart"
+      },
+      "collection": {
+        "patches": [
+          "../../runtime/lib/collection_patch.dart",
+          "../../runtime/lib/compact_hash.dart"
+        ],
+        "uri": "collection/collection.dart"
+      },
+      "ffi": {
+        "patches": [
+          "../../runtime/lib/ffi_patch.dart",
+          "../../runtime/lib/ffi_dynamic_library_patch.dart",
+          "../../runtime/lib/ffi_native_type_patch.dart"
+        ],
+        "uri": "ffi/ffi.dart"
+      },
+      "wasm": {
+        "patches": [
+          "../../runtime/lib/wasm_patch.dart"
+        ],
+        "uri": "wasm/wasm.dart"
+      },
+      "typed_data": {
+        "patches": "../../runtime/lib/typed_data_patch.dart",
+        "uri": "typed_data/typed_data.dart"
+      },
+      "nativewrappers": {
+        "uri": "html/dartium/nativewrappers.dart"
+      },
+      "developer": {
+        "patches": [
+          "../../runtime/lib/developer.dart",
+          "../../runtime/lib/profiler.dart",
+          "../../runtime/lib/timeline.dart"
+        ],
+        "uri": "developer/developer.dart"
+      },
+      "isolate": {
+        "patches": [
+          "../../runtime/lib/isolate_patch.dart",
+          "../../runtime/lib/timer_impl.dart"
+        ],
+        "uri": "isolate/isolate.dart"
+      },
+      "mirrors": {
+        "patches": [
+          "../../runtime/lib/mirrors_patch.dart",
+          "../../runtime/lib/mirrors_impl.dart",
+          "../../runtime/lib/mirror_reference.dart"
+        ],
+        "uri": "mirrors/mirrors.dart"
+      },
+      "_vmservice": {
+        "uri": "vmservice/vmservice.dart"
+      },
+      "io": {
+        "patches": [
+          "../../runtime/bin/common_patch.dart",
+          "../../runtime/bin/directory_patch.dart",
+          "../../runtime/bin/eventhandler_patch.dart",
+          "../../runtime/bin/file_patch.dart",
+          "../../runtime/bin/file_system_entity_patch.dart",
+          "../../runtime/bin/filter_patch.dart",
+          "../../runtime/bin/io_service_patch.dart",
+          "../../runtime/bin/namespace_patch.dart",
+          "../../runtime/bin/platform_patch.dart",
+          "../../runtime/bin/process_patch.dart",
+          "../../runtime/bin/socket_patch.dart",
+          "../../runtime/bin/stdio_patch.dart",
+          "../../runtime/bin/secure_socket_patch.dart",
+          "../../runtime/bin/sync_socket_patch.dart"
+        ],
+        "uri": "io/io.dart"
+      },
+      "_internal": {
+        "patches": [
+          "../../runtime/lib/internal_patch.dart",
+          "../../runtime/lib/class_id_fasta.dart",
+          "../../runtime/lib/print_patch.dart",
+          "../../runtime/lib/symbol_patch.dart",
+          "internal/patch.dart"
+        ],
+        "uri": "internal/internal.dart"
+      },
+      "convert": {
+        "patches": "../../runtime/lib/convert_patch.dart",
+        "uri": "convert/convert.dart"
+      },
+      "profiler": {
+        "uri": "profiler/profiler.dart"
+      },
+      "math": {
+        "patches": "../../runtime/lib/math_patch.dart",
+        "uri": "math/math.dart"
+      },
+      "_http": {
+        "uri": "_http/http.dart"
+      },
+      "vmservice_io": {
+        "uri": "../../runtime/bin/vmservice/vmservice_io.dart"
+      }
+    }
+  },
+  "none": {
+    "libraries": {}
+  },
+  "dart2js": {
+    "libraries": {
+      "async": {
+        "patches": "_internal/js_runtime/lib/async_patch.dart",
+        "uri": "async/async.dart"
+      },
+      "_interceptors": {
+        "uri": "_internal/js_runtime/lib/interceptors.dart"
+      },
+      "mirrors": {
+        "patches": "_internal/js_runtime/lib/mirrors_patch_cfe.dart",
+        "supported": false,
+        "uri": "mirrors/mirrors.dart"
+      },
+      "_js_embedded_names": {
+        "uri": "_internal/js_runtime/lib/shared/embedded_names.dart"
+      },
+      "io": {
+        "patches": "_internal/js_runtime/lib/io_patch.dart",
+        "supported": false,
+        "uri": "io/io.dart"
+      },
+      "_internal": {
+        "patches": "_internal/js_runtime/lib/internal_patch.dart",
+        "uri": "internal/internal.dart"
+      },
+      "_metadata": {
+        "uri": "html/html_common/metadata.dart"
+      },
+      "_async_await_error_codes": {
+        "uri": "_internal/js_runtime/lib/shared/async_await_error_codes.dart"
+      },
+      "_http": {
+        "uri": "_http/http.dart"
+      },
+      "_js_primitives": {
+        "uri": "_internal/js_runtime/lib/js_primitives.dart"
+      },
+      "_js_helper": {
+        "uri": "_internal/js_runtime/lib/js_helper.dart"
+      },
+      "_chrome": {
+        "uri": "_chrome/dart2js/chrome_dart2js.dart"
+      },
+      "js": {
+        "uri": "js/dart2js/js_dart2js.dart"
+      },
+      "html_common": {
+        "uri": "html/html_common/html_common_dart2js.dart"
+      },
+      "_recipe_syntax": {
+        "uri": "_internal/js_runtime/lib/shared/recipe_syntax.dart"
+      },
+      "_native_typed_data": {
+        "uri": "_internal/js_runtime/lib/native_typed_data.dart"
+      },
+      "_js_names": {
+        "uri": "_internal/js_runtime/lib/js_names.dart"
+      },
+      "core": {
+        "patches": "_internal/js_runtime/lib/core_patch.dart",
+        "uri": "core/core.dart"
+      },
+      "collection": {
+        "patches": "_internal/js_runtime/lib/collection_patch.dart",
+        "uri": "collection/collection.dart"
+      },
+      "js_util": {
+        "uri": "js_util/dart2js/js_util_dart2js.dart"
+      },
+      "typed_data": {
+        "patches": "_internal/js_runtime/lib/typed_data_patch.dart",
+        "uri": "typed_data/typed_data.dart"
+      },
+      "web_audio": {
+        "uri": "web_audio/dart2js/web_audio_dart2js.dart"
+      },
+      "html": {
+        "uri": "html/dart2js/html_dart2js.dart"
+      },
+      "isolate": {
+        "patches": "_internal/js_runtime/lib/isolate_patch.dart",
+        "supported": false,
+        "uri": "isolate/isolate.dart"
+      },
+      "developer": {
+        "patches": "_internal/js_runtime/lib/developer_patch.dart",
+        "uri": "developer/developer.dart"
+      },
+      "web_gl": {
+        "uri": "web_gl/dart2js/web_gl_dart2js.dart"
+      },
+      "indexed_db": {
+        "uri": "indexed_db/dart2js/indexed_db_dart2js.dart"
+      },
+      "_js": {
+        "patches": "js/_js_client.dart",
+        "uri": "js/_js.dart"
+      },
+      "convert": {
+        "patches": "_internal/js_runtime/lib/convert_patch.dart",
+        "uri": "convert/convert.dart"
+      },
+      "math": {
+        "patches": "_internal/js_runtime/lib/math_patch.dart",
+        "uri": "math/math.dart"
+      },
+      "_foreign_helper": {
+        "uri": "_internal/js_runtime/lib/foreign_helper.dart"
+      },
+      "web_sql": {
+        "uri": "web_sql/dart2js/web_sql_dart2js.dart"
+      },
+      "_rti": {
+        "uri": "_internal/js_runtime/lib/rti.dart"
+      },
+      "svg": {
+        "uri": "svg/dart2js/svg_dart2js.dart"
+      }
+    }
+  },
+  "dartdevc": {
+    "libraries": {
+      "async": {
+        "patches": "_internal/js_dev_runtime/patch/async_patch.dart",
+        "uri": "async/async.dart"
+      },
+      "_runtime": {
+        "uri": "_internal/js_dev_runtime/private/ddc_runtime/runtime.dart"
+      },
+      "_interceptors": {
+        "uri": "_internal/js_dev_runtime/private/interceptors.dart"
+      },
+      "mirrors": {
+        "patches": "_internal/js_dev_runtime/patch/mirrors_patch.dart",
+        "supported": false,
+        "uri": "mirrors/mirrors.dart"
+      },
+      "_debugger": {
+        "uri": "_internal/js_dev_runtime/private/debugger.dart"
+      },
+      "io": {
+        "patches": "_internal/js_dev_runtime/patch/io_patch.dart",
+        "supported": false,
+        "uri": "io/io.dart"
+      },
+      "_internal": {
+        "patches": "_internal/js_dev_runtime/patch/internal_patch.dart",
+        "uri": "internal/internal.dart"
+      },
+      "_metadata": {
+        "uri": "html/html_common/metadata.dart"
+      },
+      "_http": {
+        "uri": "_http/http.dart"
+      },
+      "_js_primitives": {
+        "uri": "_internal/js_dev_runtime/private/js_primitives.dart"
+      },
+      "_js_helper": {
+        "uri": "_internal/js_dev_runtime/private/js_helper.dart"
+      },
+      "js": {
+        "uri": "_internal/js_dev_runtime/lib/js/dart2js/js_dart2js.dart"
+      },
+      "_js_mirrors": {
+        "uri": "_internal/js_dev_runtime/private/js_mirrors.dart"
+      },
+      "html_common": {
+        "uri": "html/html_common/html_common_dart2js.dart"
+      },
+      "_native_typed_data": {
+        "uri": "_internal/js_dev_runtime/private/native_typed_data.dart"
+      },
+      "core": {
+        "patches": "_internal/js_dev_runtime/patch/core_patch.dart",
+        "uri": "core/core.dart"
+      },
+      "js_util": {
+        "uri": "_internal/js_dev_runtime/lib/js_util/dart2js/js_util_dart2js.dart"
+      },
+      "collection": {
+        "patches": "_internal/js_dev_runtime/patch/collection_patch.dart",
+        "uri": "collection/collection.dart"
+      },
+      "typed_data": {
+        "patches": "_internal/js_dev_runtime/patch/typed_data_patch.dart",
+        "uri": "typed_data/typed_data.dart"
+      },
+      "web_audio": {
+        "uri": "web_audio/dart2js/web_audio_dart2js.dart"
+      },
+      "html": {
+        "uri": "html/dart2js/html_dart2js.dart"
+      },
+      "developer": {
+        "patches": "_internal/js_dev_runtime/patch/developer_patch.dart",
+        "uri": "developer/developer.dart"
+      },
+      "isolate": {
+        "patches": "_internal/js_dev_runtime/patch/isolate_patch.dart",
+        "supported": false,
+        "uri": "isolate/isolate.dart"
+      },
+      "web_gl": {
+        "uri": "web_gl/dart2js/web_gl_dart2js.dart"
+      },
+      "indexed_db": {
+        "uri": "indexed_db/dart2js/indexed_db_dart2js.dart"
+      },
+      "convert": {
+        "patches": "_internal/js_dev_runtime/patch/convert_patch.dart",
+        "uri": "convert/convert.dart"
+      },
+      "_isolate_helper": {
+        "uri": "_internal/js_dev_runtime/private/isolate_helper.dart"
+      },
+      "math": {
+        "patches": "_internal/js_dev_runtime/patch/math_patch.dart",
+        "uri": "math/math.dart"
+      },
+      "_foreign_helper": {
+        "uri": "_internal/js_dev_runtime/private/foreign_helper.dart"
+      },
+      "web_sql": {
+        "uri": "web_sql/dart2js/web_sql_dart2js.dart"
+      },
+      "svg": {
+        "uri": "svg/dart2js/svg_dart2js.dart"
+      }
+    }
+  },
+  "dart2js_server": {
+    "libraries": {
+      "async": {
+        "patches": "_internal/js_runtime/lib/async_patch.dart",
+        "uri": "async/async.dart"
+      },
+      "mirrors": {
+        "patches": "_internal/js_runtime/lib/mirrors_patch_cfe.dart",
+        "supported": false,
+        "uri": "mirrors/mirrors.dart"
+      },
+      "_interceptors": {
+        "uri": "_internal/js_runtime/lib/interceptors.dart"
+      },
+      "_js_embedded_names": {
+        "uri": "_internal/js_runtime/lib/shared/embedded_names.dart"
+      },
+      "io": {
+        "patches": "_internal/js_runtime/lib/io_patch.dart",
+        "supported": false,
+        "uri": "io/io.dart"
+      },
+      "_internal": {
+        "patches": "_internal/js_runtime/lib/internal_patch.dart",
+        "uri": "internal/internal.dart"
+      },
+      "_async_await_error_codes": {
+        "uri": "_internal/js_runtime/lib/shared/async_await_error_codes.dart"
+      },
+      "_http": {
+        "uri": "_http/http.dart"
+      },
+      "_js_helper": {
+        "uri": "_internal/js_runtime/lib/js_helper.dart"
+      },
+      "_js_primitives": {
+        "uri": "_internal/js_runtime/lib/js_primitives.dart"
+      },
+      "js": {
+        "uri": "js/dart2js/js_dart2js.dart"
+      },
+      "_recipe_syntax": {
+        "uri": "_internal/js_runtime/lib/shared/recipe_syntax.dart"
+      },
+      "_native_typed_data": {
+        "uri": "_internal/js_runtime/lib/native_typed_data.dart"
+      },
+      "core": {
+        "patches": "_internal/js_runtime/lib/core_patch.dart",
+        "uri": "core/core.dart"
+      },
+      "_js_names": {
+        "uri": "_internal/js_runtime/lib/js_names.dart"
+      },
+      "js_util": {
+        "uri": "js_util/dart2js/js_util_dart2js.dart"
+      },
+      "collection": {
+        "patches": "_internal/js_runtime/lib/collection_patch.dart",
+        "uri": "collection/collection.dart"
+      },
+      "typed_data": {
+        "patches": "_internal/js_runtime/lib/typed_data_patch.dart",
+        "uri": "typed_data/typed_data.dart"
+      },
+      "isolate": {
+        "patches": "_internal/js_runtime/lib/isolate_patch.dart",
+        "supported": false,
+        "uri": "isolate/isolate.dart"
+      },
+      "developer": {
+        "patches": "_internal/js_runtime/lib/developer_patch.dart",
+        "uri": "developer/developer.dart"
+      },
+      "_js": {
+        "patches": "js/_js_server.dart",
+        "uri": "js/_js.dart"
+      },
+      "convert": {
+        "patches": "_internal/js_runtime/lib/convert_patch.dart",
+        "uri": "convert/convert.dart"
+      },
+      "math": {
+        "patches": "_internal/js_runtime/lib/math_patch.dart",
+        "uri": "math/math.dart"
+      },
+      "_foreign_helper": {
+        "uri": "_internal/js_runtime/lib/foreign_helper.dart"
+      },
+      "_rti": {
+        "uri": "_internal/js_runtime/lib/rti.dart"
+      }
+    }
+  }
+}
diff --git a/sdk_nnbd/lib/libraries.yaml b/sdk_nnbd/lib/libraries.yaml
new file mode 100644
index 0000000..f33a42b
--- /dev/null
+++ b/sdk_nnbd/lib/libraries.yaml
@@ -0,0 +1,479 @@
+# 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.
+
+# Note: if you edit this file, you must also edit libraries.json in this
+# directory:
+#
+#     python ./tools/yaml2json.py sdk/lib/libraries.yaml sdk/lib/libraries.json
+#
+# We currently have several different files that needs to be updated when
+# changing libraries, sources, and patch files.  See
+# https://github.com/dart-lang/sdk/issues/28836.
+
+none:
+  libraries: {}
+
+vm:
+  libraries:
+    _builtin:
+      uri: "../../runtime/bin/builtin.dart"
+
+    _internal:
+      uri: "internal/internal.dart"
+      patches:
+        - "../../runtime/lib/internal_patch.dart"
+        - "../../runtime/lib/class_id_fasta.dart"
+        - "../../runtime/lib/print_patch.dart"
+        - "../../runtime/lib/symbol_patch.dart"
+        - "internal/patch.dart"
+
+    async:
+      uri: "async/async.dart"
+      patches:
+        - "../../runtime/lib/async_patch.dart"
+        - "../../runtime/lib/deferred_load_patch.dart"
+        - "../../runtime/lib/schedule_microtask_patch.dart"
+        - "../../runtime/lib/timer_patch.dart"
+
+    collection:
+      uri: "collection/collection.dart"
+      patches:
+        - "../../runtime/lib/collection_patch.dart"
+        - "../../runtime/lib/compact_hash.dart"
+
+    convert:
+      uri: "convert/convert.dart"
+      patches: "../../runtime/lib/convert_patch.dart"
+
+    core:
+      uri: "core/core.dart"
+      patches:
+        - "../../runtime/lib/core_patch.dart"
+        - "../../runtime/lib/array.dart"
+        - "../../runtime/lib/array_patch.dart"
+        - "../../runtime/lib/bigint_patch.dart"
+        - "../../runtime/lib/bool_patch.dart"
+        - "../../runtime/lib/date_patch.dart"
+        - "../../runtime/lib/double.dart"
+        - "../../runtime/lib/double_patch.dart"
+        - "../../runtime/lib/errors_patch.dart"
+        - "../../runtime/lib/expando_patch.dart"
+        - "../../runtime/lib/function.dart"
+        - "../../runtime/lib/function_patch.dart"
+        - "../../runtime/lib/growable_array.dart"
+        - "../../runtime/lib/identical_patch.dart"
+        - "../../runtime/lib/immutable_map.dart"
+        - "../../runtime/lib/integers.dart"
+        - "../../runtime/lib/integers_patch.dart"
+        - "../../runtime/lib/invocation_mirror_patch.dart"
+        - "../../runtime/lib/lib_prefix.dart"
+        - "../../runtime/lib/map_patch.dart"
+        - "../../runtime/lib/null_patch.dart"
+        - "../../runtime/lib/object_patch.dart"
+        - "../../runtime/lib/regexp_patch.dart"
+        - "../../runtime/lib/stacktrace.dart"
+        - "../../runtime/lib/stopwatch_patch.dart"
+        - "../../runtime/lib/string_buffer_patch.dart"
+        - "../../runtime/lib/string_patch.dart"
+        - "../../runtime/lib/type_patch.dart"
+        - "../../runtime/lib/uri_patch.dart"
+        - "../../runtime/lib/weak_property.dart"
+
+    developer:
+      uri: "developer/developer.dart"
+      patches:
+        - "../../runtime/lib/developer.dart"
+        - "../../runtime/lib/profiler.dart"
+        - "../../runtime/lib/timeline.dart"
+
+    ffi:
+      uri: "ffi/ffi.dart"
+      patches:
+        - "../../runtime/lib/ffi_patch.dart"
+        - "../../runtime/lib/ffi_dynamic_library_patch.dart"
+        - "../../runtime/lib/ffi_native_type_patch.dart"
+
+    wasm:
+      uri: "wasm/wasm.dart"
+      patches:
+        - "../../runtime/lib/wasm_patch.dart"
+
+    _http:
+      uri: "_http/http.dart"
+
+    io:
+      uri: "io/io.dart"
+      patches:
+        - "../../runtime/bin/common_patch.dart"
+        - "../../runtime/bin/directory_patch.dart"
+        - "../../runtime/bin/eventhandler_patch.dart"
+        - "../../runtime/bin/file_patch.dart"
+        - "../../runtime/bin/file_system_entity_patch.dart"
+        - "../../runtime/bin/filter_patch.dart"
+        - "../../runtime/bin/io_service_patch.dart"
+        - "../../runtime/bin/namespace_patch.dart"
+        - "../../runtime/bin/platform_patch.dart"
+        - "../../runtime/bin/process_patch.dart"
+        - "../../runtime/bin/socket_patch.dart"
+        - "../../runtime/bin/stdio_patch.dart"
+        - "../../runtime/bin/secure_socket_patch.dart"
+        - "../../runtime/bin/sync_socket_patch.dart"
+
+    isolate:
+      uri: "isolate/isolate.dart"
+      patches:
+        - "../../runtime/lib/isolate_patch.dart"
+        - "../../runtime/lib/timer_impl.dart"
+
+    math:
+      uri: "math/math.dart"
+      patches: "../../runtime/lib/math_patch.dart"
+
+    mirrors:
+      uri: "mirrors/mirrors.dart"
+      patches:
+        - "../../runtime/lib/mirrors_patch.dart"
+        - "../../runtime/lib/mirrors_impl.dart"
+        - "../../runtime/lib/mirror_reference.dart"
+
+    nativewrappers:
+      uri: "html/dartium/nativewrappers.dart"
+
+    profiler:
+      uri: "profiler/profiler.dart"
+
+    cli:
+      uri: "cli/cli.dart"
+      patches:
+        - "../../runtime/bin/cli_patch.dart"
+
+    typed_data:
+      uri: "typed_data/typed_data.dart"
+      patches: "../../runtime/lib/typed_data_patch.dart"
+
+    _vmservice:
+      uri: "vmservice/vmservice.dart"
+
+    vmservice_io:
+      uri: "../../runtime/bin/vmservice/vmservice_io.dart"
+
+dart2js:
+  libraries:
+    async:
+      uri: "async/async.dart"
+      patches: "_internal/js_runtime/lib/async_patch.dart"
+
+    _chrome:
+      uri: "_chrome/dart2js/chrome_dart2js.dart"
+
+    collection:
+      uri: "collection/collection.dart"
+      patches: "_internal/js_runtime/lib/collection_patch.dart"
+
+    convert:
+      uri: "convert/convert.dart"
+      patches: "_internal/js_runtime/lib/convert_patch.dart"
+
+    core:
+      uri: "core/core.dart"
+      patches: "_internal/js_runtime/lib/core_patch.dart"
+
+    developer:
+      uri: "developer/developer.dart"
+      patches: "_internal/js_runtime/lib/developer_patch.dart"
+
+    html:
+      uri: "html/dart2js/html_dart2js.dart"
+
+    html_common:
+      uri: "html/html_common/html_common_dart2js.dart"
+
+    indexed_db:
+      uri: "indexed_db/dart2js/indexed_db_dart2js.dart"
+
+    _http:
+      uri: "_http/http.dart"
+
+    io:
+      uri: "io/io.dart"
+      patches: "_internal/js_runtime/lib/io_patch.dart"
+      supported: false
+
+    isolate:
+      uri: "isolate/isolate.dart"
+      patches: "_internal/js_runtime/lib/isolate_patch.dart"
+      supported: false
+
+    js:
+      uri: "js/dart2js/js_dart2js.dart"
+
+    _js:
+      uri: "js/_js.dart"
+      patches: "js/_js_client.dart"
+
+    js_util:
+      uri: "js_util/dart2js/js_util_dart2js.dart"
+
+    math:
+      uri: "math/math.dart"
+      patches: "_internal/js_runtime/lib/math_patch.dart"
+
+    mirrors:
+      uri: "mirrors/mirrors.dart"
+      patches: "_internal/js_runtime/lib/mirrors_patch_cfe.dart"
+      supported: false
+
+    typed_data:
+      uri: "typed_data/typed_data.dart"
+      patches: "_internal/js_runtime/lib/typed_data_patch.dart"
+
+    _native_typed_data:
+      uri: "_internal/js_runtime/lib/native_typed_data.dart"
+
+    svg:
+      uri: "svg/dart2js/svg_dart2js.dart"
+
+    web_audio:
+      uri: "web_audio/dart2js/web_audio_dart2js.dart"
+
+    web_gl:
+      uri: "web_gl/dart2js/web_gl_dart2js.dart"
+
+    web_sql:
+      uri: "web_sql/dart2js/web_sql_dart2js.dart"
+
+    _internal:
+      uri: "internal/internal.dart"
+      patches: "_internal/js_runtime/lib/internal_patch.dart"
+
+    _js_helper:
+      uri: "_internal/js_runtime/lib/js_helper.dart"
+
+    _rti:
+      uri: "_internal/js_runtime/lib/rti.dart"
+
+    _interceptors:
+      uri: "_internal/js_runtime/lib/interceptors.dart"
+
+    _foreign_helper:
+      uri: "_internal/js_runtime/lib/foreign_helper.dart"
+
+    _js_names:
+      uri: "_internal/js_runtime/lib/js_names.dart"
+
+    _js_primitives:
+      uri: "_internal/js_runtime/lib/js_primitives.dart"
+
+    _js_embedded_names:
+      uri: "_internal/js_runtime/lib/shared/embedded_names.dart"
+
+    _async_await_error_codes:
+      uri: "_internal/js_runtime/lib/shared/async_await_error_codes.dart"
+
+    _recipe_syntax:
+      uri: "_internal/js_runtime/lib/shared/recipe_syntax.dart"
+
+    _metadata:
+      uri: "html/html_common/metadata.dart"
+
+dart2js_server:
+  libraries:
+    async:
+      uri: "async/async.dart"
+      patches: "_internal/js_runtime/lib/async_patch.dart"
+
+    collection:
+      uri: "collection/collection.dart"
+      patches: "_internal/js_runtime/lib/collection_patch.dart"
+
+    convert:
+      uri: "convert/convert.dart"
+      patches: "_internal/js_runtime/lib/convert_patch.dart"
+
+    core:
+      uri: "core/core.dart"
+      patches: "_internal/js_runtime/lib/core_patch.dart"
+
+    developer:
+      uri: "developer/developer.dart"
+      patches: "_internal/js_runtime/lib/developer_patch.dart"
+
+    _http:
+      uri: "_http/http.dart"
+
+    io:
+      uri: "io/io.dart"
+      patches: "_internal/js_runtime/lib/io_patch.dart"
+      supported: false
+
+    isolate:
+      uri: "isolate/isolate.dart"
+      patches: "_internal/js_runtime/lib/isolate_patch.dart"
+      supported: false
+
+    js:
+      uri: "js/dart2js/js_dart2js.dart"
+
+    _js:
+      uri: "js/_js.dart"
+      patches: "js/_js_server.dart"
+
+    js_util:
+      uri: "js_util/dart2js/js_util_dart2js.dart"
+
+    math:
+      uri: "math/math.dart"
+      patches: "_internal/js_runtime/lib/math_patch.dart"
+
+    mirrors:
+      uri: "mirrors/mirrors.dart"
+      patches: "_internal/js_runtime/lib/mirrors_patch_cfe.dart"
+      supported: false
+
+    typed_data:
+      uri: "typed_data/typed_data.dart"
+      patches: "_internal/js_runtime/lib/typed_data_patch.dart"
+
+    _native_typed_data:
+      uri: "_internal/js_runtime/lib/native_typed_data.dart"
+
+    _internal:
+      uri: "internal/internal.dart"
+      patches: "_internal/js_runtime/lib/internal_patch.dart"
+
+    _js_helper:
+      uri: "_internal/js_runtime/lib/js_helper.dart"
+
+    _rti:
+      uri: "_internal/js_runtime/lib/rti.dart"
+
+    _interceptors:
+      uri: "_internal/js_runtime/lib/interceptors.dart"
+
+    _foreign_helper:
+      uri: "_internal/js_runtime/lib/foreign_helper.dart"
+
+    _js_names:
+      uri: "_internal/js_runtime/lib/js_names.dart"
+
+    _js_primitives:
+      uri: "_internal/js_runtime/lib/js_primitives.dart"
+
+    _js_embedded_names:
+      uri: "_internal/js_runtime/lib/shared/embedded_names.dart"
+
+    _async_await_error_codes:
+      uri: "_internal/js_runtime/lib/shared/async_await_error_codes.dart"
+
+    _recipe_syntax:
+      uri: "_internal/js_runtime/lib/shared/recipe_syntax.dart"
+
+dartdevc:
+    libraries:
+      _runtime:
+        uri: "_internal/js_dev_runtime/private/ddc_runtime/runtime.dart"
+
+      _debugger:
+        uri: "_internal/js_dev_runtime/private/debugger.dart"
+
+      _foreign_helper:
+        uri: "_internal/js_dev_runtime/private/foreign_helper.dart"
+
+      _http:
+        uri: "_http/http.dart"
+
+      _interceptors:
+        uri: "_internal/js_dev_runtime/private/interceptors.dart"
+
+      _internal:
+        uri: "internal/internal.dart"
+        patches: "_internal/js_dev_runtime/patch/internal_patch.dart"
+
+      _isolate_helper:
+        uri: "_internal/js_dev_runtime/private/isolate_helper.dart"
+
+      _js_helper:
+        uri: "_internal/js_dev_runtime/private/js_helper.dart"
+
+      _js_mirrors:
+        uri: "_internal/js_dev_runtime/private/js_mirrors.dart"
+
+      _js_primitives:
+        uri: "_internal/js_dev_runtime/private/js_primitives.dart"
+
+      _metadata:
+        uri: "html/html_common/metadata.dart"
+
+      _native_typed_data:
+        uri: "_internal/js_dev_runtime/private/native_typed_data.dart"
+
+      async:
+        uri: "async/async.dart"
+        patches: "_internal/js_dev_runtime/patch/async_patch.dart"
+
+      collection:
+        uri: "collection/collection.dart"
+        patches: "_internal/js_dev_runtime/patch/collection_patch.dart"
+
+      convert:
+        uri: "convert/convert.dart"
+        patches: "_internal/js_dev_runtime/patch/convert_patch.dart"
+
+      core:
+        uri: "core/core.dart"
+        patches: "_internal/js_dev_runtime/patch/core_patch.dart"
+
+      developer:
+        uri: "developer/developer.dart"
+        patches: "_internal/js_dev_runtime/patch/developer_patch.dart"
+
+      io:
+        uri: "io/io.dart"
+        patches: "_internal/js_dev_runtime/patch/io_patch.dart"
+        supported: false
+
+      isolate:
+        uri: "isolate/isolate.dart"
+        patches: "_internal/js_dev_runtime/patch/isolate_patch.dart"
+        supported: false
+
+      mirrors:
+        uri: "mirrors/mirrors.dart"
+        patches: "_internal/js_dev_runtime/patch/mirrors_patch.dart"
+        supported: false
+
+      math:
+        uri: "math/math.dart"
+        patches: "_internal/js_dev_runtime/patch/math_patch.dart"
+
+      typed_data:
+        uri: "typed_data/typed_data.dart"
+        patches: "_internal/js_dev_runtime/patch/typed_data_patch.dart"
+
+      html:
+        uri: "html/dart2js/html_dart2js.dart"
+
+      html_common:
+        uri: "html/html_common/html_common_dart2js.dart"
+
+      indexed_db:
+        uri: "indexed_db/dart2js/indexed_db_dart2js.dart"
+
+      js:
+        uri: "_internal/js_dev_runtime/lib/js/dart2js/js_dart2js.dart"
+
+      js_util:
+        uri: "_internal/js_dev_runtime/lib/js_util/dart2js/js_util_dart2js.dart"
+
+      svg:
+        uri: "svg/dart2js/svg_dart2js.dart"
+
+      web_audio:
+        uri: "web_audio/dart2js/web_audio_dart2js.dart"
+
+      web_gl:
+        uri: "web_gl/dart2js/web_gl_dart2js.dart"
+
+      web_sql:
+        uri: "web_sql/dart2js/web_sql_dart2js.dart"
diff --git a/sdk_nnbd/lib/math/jenkins_smi_hash.dart b/sdk_nnbd/lib/math/jenkins_smi_hash.dart
new file mode 100644
index 0000000..d756b37
--- /dev/null
+++ b/sdk_nnbd/lib/math/jenkins_smi_hash.dart
@@ -0,0 +1,39 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+part of dart.math;
+
+/// This is the [Jenkins hash function][1] but using masking to keep
+/// values in SMI range.
+///
+/// [1]: http://en.wikipedia.org/wiki/Jenkins_hash_function
+///
+/// Use:
+/// Hash each value with the hash of the previous value, then get the final
+/// hash by calling finish.
+///
+///     var hash = 0;
+///     for (var value in values) {
+///       hash = JenkinsSmiHash.combine(hash, value.hashCode);
+///     }
+///     hash = JenkinsSmiHash.finish(hash);
+class _JenkinsSmiHash {
+  // TODO(11617): This class should be optimized and standardized elsewhere.
+
+  static int combine(int hash, int value) {
+    hash = 0x1fffffff & (hash + value);
+    hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10));
+    return hash ^ (hash >> 6);
+  }
+
+  static int finish(int hash) {
+    hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3));
+    hash = hash ^ (hash >> 11);
+    return 0x1fffffff & (hash + ((0x00003fff & hash) << 15));
+  }
+
+  static int hash2(a, b) => finish(combine(combine(0, a), b));
+
+  static int hash4(a, b, c, d) =>
+      finish(combine(combine(combine(combine(0, a), b), c), d));
+}
diff --git a/sdk_nnbd/lib/math/math.dart b/sdk_nnbd/lib/math/math.dart
new file mode 100644
index 0000000..548fb59
--- /dev/null
+++ b/sdk_nnbd/lib/math/math.dart
@@ -0,0 +1,179 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// Mathematical constants and functions, plus a random number generator.
+///
+/// To use this library in your code:
+///
+///     import 'dart:math';
+///
+/// {@category Core}
+library dart.math;
+
+part "jenkins_smi_hash.dart";
+part "point.dart";
+part "random.dart";
+part "rectangle.dart";
+
+/// Base of the natural logarithms.
+///
+/// Typically written as "e".
+const double e = 2.718281828459045;
+
+/// Natural logarithm of 10.
+///
+/// The natural logarithm of 10 is the number such that `pow(E, LN10) == 10`.
+/// This value is not exact, but it is the closest representable double to the
+/// exact mathematical value.
+const double ln10 = 2.302585092994046;
+
+/// Natural logarithm of 2.
+///
+/// The natural logarithm of 2 is the number such that `pow(E, LN2) == 2`.
+/// This value is not exact, but it is the closest representable double to the
+/// exact mathematical value.
+const double ln2 = 0.6931471805599453;
+
+/// Base-2 logarithm of [e].
+const double log2e = 1.4426950408889634;
+
+/// Base-10 logarithm of [e].
+const double log10e = 0.4342944819032518;
+
+/// The PI constant.
+const double pi = 3.1415926535897932;
+
+/// Square root of 1/2.
+const double sqrt1_2 = 0.7071067811865476;
+
+/// Square root of 2.
+const double sqrt2 = 1.4142135623730951;
+
+/// Returns the lesser of two numbers.
+///
+/// Returns NaN if either argument is NaN.
+/// The lesser of `-0.0` and `0.0` is `-0.0`.
+/// If the arguments are otherwise equal (including int and doubles with the
+/// same mathematical value) then it is unspecified which of the two arguments
+/// is returned.
+external T min<T extends num>(T a, T b);
+
+/// Returns the larger of two numbers.
+///
+/// Returns NaN if either argument is NaN.
+/// The larger of `-0.0` and `0.0` is `0.0`. If the arguments are
+/// otherwise equal (including int and doubles with the same mathematical value)
+/// then it is unspecified which of the two arguments is returned.
+external T max<T extends num>(T a, T b);
+
+/// A variant of [atan].
+///
+/// Converts both arguments to [double]s.
+///
+/// Returns the angle in radians between the positive x-axis
+/// and the vector ([b],[a]).
+/// The result is in the range -PI..PI.
+///
+/// If [b] is positive, this is the same as `atan(b/a)`.
+///
+/// The result is negative when [a] is negative (including when [a] is the
+/// double -0.0).
+///
+/// If [a] is equal to zero, the vector ([b],[a]) is considered parallel to
+/// the x-axis, even if [b] is also equal to zero. The sign of [b] determines
+/// the direction of the vector along the x-axis.
+///
+/// Returns NaN if either argument is NaN.
+external double atan2(num a, num b);
+
+/// Returns [x] to the power of [exponent].
+///
+/// If [x] is an [int] and [exponent] is a non-negative [int], the result is
+/// an [int], otherwise both arguments are converted to doubles first, and the
+/// result is a [double].
+///
+/// For integers, the power is always equal to the mathematical result of `x` to
+/// the power `exponent`, only limited by the available memory.
+///
+/// For doubles, `pow(x, y)` handles edge cases as follows:
+///
+/// - if `y` is zero (0.0 or -0.0), the result is always 1.0.
+/// - if `x` is 1.0, the result is always 1.0.
+/// - otherwise, if either `x` or `y` is NaN then the result is NaN.
+/// - if `x` is negative (but not -0.0) and `y` is a finite non-integer, the
+///   result is NaN.
+/// - if `x` is Infinity and `y` is negative, the result is 0.0.
+/// - if `x` is Infinity and `y` is positive, the result is Infinity.
+/// - if `x` is 0.0 and `y` is negative, the result is Infinity.
+/// - if `x` is 0.0 and `y` is positive, the result is 0.0.
+/// - if `x` is -Infinity or -0.0 and `y` is an odd integer, then the result is
+///   `-pow(-x ,y)`.
+/// - if `x` is -Infinity or -0.0 and `y` is not an odd integer, then the result
+///   is the same as `pow(-x , y)`.
+/// - if `y` is Infinity and the absolute value of `x` is less than 1, the
+///   result is 0.0.
+/// - if `y` is Infinity and `x` is -1, the result is 1.0.
+/// - if `y` is Infinity and the absolute value of `x` is greater than 1,
+///   the result is Infinity.
+/// - if `y` is -Infinity, the result is `1/pow(x, Infinity)`.
+///
+/// This corresponds to the `pow` function defined in the IEEE Standard
+/// 754-2008.
+///
+/// Notice that the result may overflow. If integers are represented as 64-bit
+/// numbers, an integer result may be truncated, and a double result may
+/// overflow to positive or negative [double.infinity].
+external num pow(num x, num exponent);
+
+/// Converts [radians] to a [double] and returns the sine of the value.
+///
+/// If [radians] is not a finite number, the result is NaN.
+external double sin(num radians);
+
+/// Converts [radians] to a [double] and returns the cosine of the value.
+///
+/// If [radians] is not a finite number, the result is NaN.
+external double cos(num radians);
+
+/// Converts [radians] to a [double] and returns the tangent of the value.
+///
+/// The tangent function is equivalent to `sin(radians)/cos(radians)` and may be
+/// infinite (positive or negative) when `cos(radians)` is equal to zero.
+/// If [radians] is not a finite number, the result is NaN.
+external double tan(num radians);
+
+/// Converts [x] to a [double] and returns its arc cosine in radians.
+///
+/// Returns a value in the range 0..PI, or NaN if [x] is outside
+/// the range -1..1.
+external double acos(num x);
+
+/// Converts [x] to a [double] and returns its arc sine in radians.
+///
+/// Returns a value in the range -PI/2..PI/2, or NaN if [x] is outside
+/// the range -1..1.
+external double asin(num x);
+
+/// Converts [x] to a [double] and returns its arc tangent in radians.
+///
+/// Returns a value in the range -PI/2..PI/2, or NaN if [x] is NaN.
+external double atan(num x);
+
+/// Converts [x] to a [double] and returns the positive square root of the
+/// value.
+///
+/// Returns -0.0 if [x] is -0.0, and NaN if [x] is otherwise negative or NaN.
+external double sqrt(num x);
+
+/// Converts [x] to a [double] and returns the natural exponent, [e],
+/// to the power [x].
+///
+/// Returns NaN if [x] is NaN.
+external double exp(num x);
+
+/// Converts [x] to a [double] and returns the natural logarithm of the value.
+///
+/// Returns negative infinity if [x] is equal to zero.
+/// Returns NaN if [x] is NaN or less than zero.
+external double log(num x);
diff --git a/sdk_nnbd/lib/math/math_sources.gni b/sdk_nnbd/lib/math/math_sources.gni
new file mode 100644
index 0000000..ff8f3fa
--- /dev/null
+++ b/sdk_nnbd/lib/math/math_sources.gni
@@ -0,0 +1,13 @@
+# 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.
+
+math_sdk_sources = [
+  "math.dart",
+
+  # The above file needs to be first as it lists the parts below.
+  "jenkins_smi_hash.dart",
+  "point.dart",
+  "random.dart",
+  "rectangle.dart",
+]
diff --git a/sdk_nnbd/lib/math/point.dart b/sdk_nnbd/lib/math/point.dart
new file mode 100644
index 0000000..1015e7b
--- /dev/null
+++ b/sdk_nnbd/lib/math/point.dart
@@ -0,0 +1,74 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+part of dart.math;
+
+/// A utility class for representing two-dimensional positions.
+class Point<T extends num> {
+  final T x;
+  final T y;
+
+  const Point(T x, T y)
+      : this.x = x,
+        this.y = y;
+
+  String toString() => 'Point($x, $y)';
+
+  /// A `Point` is only equal to another `Point` with the same coordinates.
+  ///
+  /// This point is equal to `other` if, and only if,
+  /// `other` is a `Point` with
+  /// [x] equal to `other.x` and [y] equal to `other.y`.
+  bool operator ==(dynamic other) =>
+      // Cannot change parameter type to `Object` in case some class
+      // inherits the type and uses their argument dynamically.
+      other is Point && x == other.x && y == other.y;
+
+  int get hashCode => _JenkinsSmiHash.hash2(x.hashCode, y.hashCode);
+
+  /// Add [other] to `this`, as if both points were vectors.
+  ///
+  /// Returns the resulting "vector" as a Point.
+  Point<T> operator +(Point<T> other) {
+    return Point<T>(x + other.x, y + other.y);
+  }
+
+  /// Subtract [other] from `this`, as if both points were vectors.
+  ///
+  /// Returns the resulting "vector" as a Point.
+  Point<T> operator -(Point<T> other) {
+    return Point<T>(x - other.x, y - other.y);
+  }
+
+  /// Scale this point by [factor] as if it were a vector.
+  ///
+  /// *Important* *Note*: This function accepts a `num` as its argument only so
+  /// that you can scale Point<double> objects by an `int` factor. Because the
+  /// star operator always returns the same type of Point that originally called
+  /// it, passing in a double [factor] on a `Point<int>` _causes_ _a_
+  /// _runtime_ _error_ in checked mode.
+  Point<T> operator *(num /*T|int*/ factor) {
+    return Point<T>((x * factor), (y * factor));
+  }
+
+  /// Get the straight line (Euclidean) distance between the origin (0, 0) and
+  /// this point.
+  double get magnitude => sqrt(x * x + y * y);
+
+  /// Returns the distance between `this` and [other].
+  double distanceTo(Point<T> other) {
+    var dx = x - other.x;
+    var dy = y - other.y;
+    return sqrt(dx * dx + dy * dy);
+  }
+
+  /// Returns the squared distance between `this` and [other].
+  ///
+  /// Squared distances can be used for comparisons when the actual value is not
+  /// required.
+  T squaredDistanceTo(Point<T> other) {
+    var dx = x - other.x;
+    var dy = y - other.y;
+    return dx * dx + dy * dy;
+  }
+}
diff --git a/sdk_nnbd/lib/math/random.dart b/sdk_nnbd/lib/math/random.dart
new file mode 100644
index 0000000..80e588b
--- /dev/null
+++ b/sdk_nnbd/lib/math/random.dart
@@ -0,0 +1,40 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.math;
+
+/// A generator of random bool, int, or double values.
+///
+/// The default implementation supplies a stream of pseudo-random bits that are
+/// not suitable for cryptographic purposes.
+///
+/// Use the [Random.secure]() constructor for cryptographic purposes.
+abstract class Random {
+  /// Creates a random number generator.
+  ///
+  /// The optional parameter [seed] is used to initialize the
+  /// internal state of the generator. The implementation of the
+  /// random stream can change between releases of the library.
+  external factory Random([int seed]);
+
+  /// Creates a cryptographically secure random number generator.
+  ///
+  /// If the program cannot provide a cryptographically secure
+  /// source of random numbers, it throws an [UnsupportedError].
+  external factory Random.secure();
+
+  /// Generates a non-negative random integer uniformly distributed in the range
+  /// from 0, inclusive, to [max], exclusive.
+  ///
+  /// Implementation note: The default implementation supports [max] values
+  /// between 1 and (1<<32) inclusive.
+  int nextInt(int max);
+
+  /// Generates a non-negative random floating point value uniformly distributed
+  /// in the range from 0.0, inclusive, to 1.0, exclusive.
+  double nextDouble();
+
+  /// Generates a random boolean value.
+  bool nextBool();
+}
diff --git a/sdk_nnbd/lib/math/rectangle.dart b/sdk_nnbd/lib/math/rectangle.dart
new file mode 100644
index 0000000..6e72036
--- /dev/null
+++ b/sdk_nnbd/lib/math/rectangle.dart
@@ -0,0 +1,247 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+part of dart.math;
+
+/// A base class for representing two-dimensional axis-aligned rectangles.
+///
+/// This rectangle uses a left-handed Cartesian coordinate system, with x
+/// directed to the right and y directed down, as per the convention in 2D
+/// computer graphics.
+///
+/// See also:
+///    [W3C Coordinate Systems Specification](http://www.w3.org/TR/SVG/coords.html#InitialCoordinateSystem).
+///
+/// The rectangle is the set of points with representable coordinates greater
+/// than or equal to left/top, and with distance to left/top no greater than
+/// width/height (to the limit of the precision of the coordinates).
+abstract class _RectangleBase<T extends num> {
+  const _RectangleBase();
+
+  /// The x-coordinate of the left edge.
+  T get left;
+
+  /// The y-coordinate of the top edge.
+  T get top;
+
+  /// The width of the rectangle.
+  T get width;
+
+  /// The height of the rectangle.
+  T get height;
+
+  /// The x-coordinate of the right edge.
+  T get right => left + width;
+
+  /// The y-coordinate of the bottom edge.
+  T get bottom => top + height;
+
+  String toString() {
+    return 'Rectangle ($left, $top) $width x $height';
+  }
+
+  bool operator ==(dynamic other) =>
+      // Can't change argument type to `Object` since subclasses inherit it
+      // and uses their argument dynamically.
+      other is Rectangle &&
+      left == other.left &&
+      top == other.top &&
+      right == other.right &&
+      bottom == other.bottom;
+
+  int get hashCode => _JenkinsSmiHash.hash4(
+      left.hashCode, top.hashCode, right.hashCode, bottom.hashCode);
+
+  /// Computes the intersection of `this` and [other].
+  ///
+  /// The intersection of two axis-aligned rectangles, if any, is always another
+  /// axis-aligned rectangle.
+  ///
+  /// Returns the intersection of this and `other`, or `null` if they don't
+  /// intersect.
+  Rectangle<T> intersection(Rectangle<T> other) {
+    var x0 = max(left, other.left);
+    var x1 = min(left + width, other.left + other.width);
+
+    if (x0 <= x1) {
+      var y0 = max(top, other.top);
+      var y1 = min(top + height, other.top + other.height);
+
+      if (y0 <= y1) {
+        return Rectangle<T>(x0, y0, x1 - x0, y1 - y0);
+      }
+    }
+    return null;
+  }
+
+  /// Returns true if `this` intersects [other].
+  bool intersects(Rectangle<num> other) {
+    return (left <= other.left + other.width &&
+        other.left <= left + width &&
+        top <= other.top + other.height &&
+        other.top <= top + height);
+  }
+
+  /// Returns a new rectangle which completely contains `this` and [other].
+  Rectangle<T> boundingBox(Rectangle<T> other) {
+    var right = max(this.left + this.width, other.left + other.width);
+    var bottom = max(this.top + this.height, other.top + other.height);
+
+    var left = min(this.left, other.left);
+    var top = min(this.top, other.top);
+
+    return Rectangle<T>(left, top, right - left, bottom - top);
+  }
+
+  /// Tests whether `this` entirely contains [another].
+  bool containsRectangle(Rectangle<num> another) {
+    return left <= another.left &&
+        left + width >= another.left + another.width &&
+        top <= another.top &&
+        top + height >= another.top + another.height;
+  }
+
+  /// Tests whether [another] is inside or along the edges of `this`.
+  bool containsPoint(Point<num> another) {
+    return another.x >= left &&
+        another.x <= left + width &&
+        another.y >= top &&
+        another.y <= top + height;
+  }
+
+  Point<T> get topLeft => Point<T>(this.left, this.top);
+  Point<T> get topRight => Point<T>(this.left + this.width, this.top);
+  Point<T> get bottomRight =>
+      Point<T>(this.left + this.width, this.top + this.height);
+  Point<T> get bottomLeft => Point<T>(this.left, this.top + this.height);
+}
+
+/// A class for representing two-dimensional rectangles whose properties are
+/// immutable.
+class Rectangle<T extends num> extends _RectangleBase<T> {
+  final T left;
+  final T top;
+  final T width;
+  final T height;
+
+  /// Create a rectangle spanned by `(left, top)` and
+  /// `(left+width, top+height)`.
+  ///
+  /// The rectangle contains the points
+  /// with x-coordinate between `left` and `left + width`, and
+  /// with y-coordinate between `top` and `top + height`, both inclusive.
+  ///
+  /// The `width` and `height` should be non-negative.
+  /// If `width` or `height` are negative, they are clamped to zero.
+  ///
+  /// If `width` and `height` are zero, the "rectangle" comprises only the
+  /// single point `(left, top)`.
+  const Rectangle(this.left, this.top, T width, T height)
+      : this.width = (width < 0) ? -width * 0 : width, // Inline _clampToZero.
+        this.height = (height < 0) ? -height * 0 : height;
+
+  /// Create a rectangle spanned by the points [a] and [b];
+  ///
+  /// The rectangle contains the points
+  /// with x-coordinate between `a.x` and `b.x`, and
+  /// with y-coordinate between `a.y` and `b.y`, both inclusive.
+  ///
+  /// If the distance between `a.x` and `b.x` is not representable
+  /// (which can happen if one or both is a double),
+  /// the actual right edge might be slightly off from `max(a.x, b.x)`.
+  /// Similar for the y-coordinates and the bottom edge.
+  factory Rectangle.fromPoints(Point<T> a, Point<T> b) {
+    T left = min(a.x, b.x);
+    T width = max(a.x, b.x) - left;
+    T top = min(a.y, b.y);
+    T height = max(a.y, b.y) - top;
+    return Rectangle<T>(left, top, width, height);
+  }
+}
+
+/// A class for representing two-dimensional axis-aligned rectangles with
+/// mutable properties.
+class MutableRectangle<T extends num> extends _RectangleBase<T>
+    implements Rectangle<T> {
+  /// The x-coordinate of the left edge.
+  ///
+  /// Setting the value will move the rectangle without changing its width.
+  T left;
+
+  /// The y-coordinate of the left edge.
+  ///
+  /// Setting the value will move the rectangle without changing its height.
+  T top;
+  T _width;
+  T _height;
+
+  /// Create a mutable rectangle spanned by `(left, top)` and
+  /// `(left+width, top+height)`.
+  ///
+  /// The rectangle contains the points
+  /// with x-coordinate between `left` and `left + width`, and
+  /// with y-coordinate between `top` and `top + height`, both inclusive.
+  ///
+  /// The `width` and `height` should be non-negative.
+  /// If `width` or `height` are negative, they are clamped to zero.
+  ///
+  /// If `width` and `height` are zero, the "rectangle" comprises only the
+  /// single point `(left, top)`.
+  MutableRectangle(this.left, this.top, T width, T height)
+      : this._width = (width < 0) ? _clampToZero<T>(width) : width,
+        this._height = (height < 0) ? _clampToZero<T>(height) : height;
+
+  /// Create a mutable rectangle spanned by the points [a] and [b];
+  ///
+  /// The rectangle contains the points
+  /// with x-coordinate between `a.x` and `b.x`, and
+  /// with y-coordinate between `a.y` and `b.y`, both inclusive.
+  ///
+  /// If the distance between `a.x` and `b.x` is not representable
+  /// (which can happen if one or both is a double),
+  /// the actual right edge might be slightly off from `max(a.x, b.x)`.
+  /// Similar for the y-coordinates and the bottom edge.
+  factory MutableRectangle.fromPoints(Point<T> a, Point<T> b) {
+    T left = min(a.x, b.x);
+    T width = max(a.x, b.x) - left;
+    T top = min(a.y, b.y);
+    T height = max(a.y, b.y) - top;
+    return MutableRectangle<T>(left, top, width, height);
+  }
+
+  T get width => _width;
+
+  /// Sets the width of the rectangle.
+  ///
+  /// The width must be non-negative.
+  /// If a negative width is supplied, it is clamped to zero.
+  ///
+  /// Setting the value will change the right edge of the rectangle,
+  /// but will not change [left].
+  set width(T width) {
+    if (width < 0) width = _clampToZero<T>(width);
+    _width = width;
+  }
+
+  T get height => _height;
+
+  /// Sets the height of the rectangle.
+  ///
+  /// The height must be non-negative.
+  /// If a negative height is supplied, it is clamped to zero.
+  ///
+  /// Setting the value will change the bottom edge of the rectangle,
+  /// but will not change [top].
+  set height(T height) {
+    if (height < 0) height = _clampToZero<T>(height);
+    _height = height;
+  }
+}
+
+/// Converts a negative [int] or [double] to a zero-value of the same type.
+///
+/// Returns `0` if value is int, `0.0` if value is double.
+T _clampToZero<T extends num>(T value) {
+  assert(value < 0);
+  return -value * 0;
+}
diff --git a/sdk_nnbd/lib/mirrors/mirrors.dart b/sdk_nnbd/lib/mirrors/mirrors.dart
new file mode 100644
index 0000000..64f88a2
--- /dev/null
+++ b/sdk_nnbd/lib/mirrors/mirrors.dart
@@ -0,0 +1,1467 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// For the purposes of the mirrors library, we adopt a naming
+// convention with respect to getters and setters.  Specifically, for
+// some variable or field...
+//
+//   var myField;
+//
+// ...the getter is named 'myField' and the setter is named
+// 'myField='.  This allows us to assign unique names to getters and
+// setters for the purposes of member lookup.
+
+/**
+ * Basic reflection in Dart,
+ * with support for introspection and dynamic invocation.
+ *
+ * *Introspection* is that subset of reflection by which a running
+ * program can examine its own structure. For example, a function
+ * that prints out the names of all the members of an arbitrary object.
+ *
+ * *Dynamic invocation* refers the ability to evaluate code that
+ * has not been literally specified at compile time, such as calling a method
+ * whose name is provided as an argument (because it is looked up
+ * in a database, or provided interactively by the user).
+ *
+ * ## How to interpret this library's documentation
+ *
+ * As a rule, the names of Dart declarations are represented using
+ * instances of class [Symbol]. Whenever the doc speaks of an object *s*
+ * of class [Symbol] denoting a name, it means the string that
+ * was used to construct *s*.
+ *
+ * The documentation frequently abuses notation with
+ * Dart pseudo-code such as [:o.x(a):], where
+ * o and a are defined to be objects; what is actually meant in these
+ * cases is [:o'.x(a'):] where *o'* and *a'* are Dart variables
+ * bound to *o* and *a* respectively. Furthermore, *o'* and *a'*
+ * are assumed to be fresh variables (meaning that they are
+ * distinct from any other variables in the program).
+ *
+ * Sometimes the documentation refers to *serializable* objects.
+ * An object is serializable across isolates if and only if it is an instance of
+ * num, bool, String, a list of objects that are serializable
+ * across isolates, or a map with keys and values that are all serializable across
+ * isolates.
+ *
+ * ## Status: Unstable
+ *
+ * The dart:mirrors library is unstable and its API might change slightly as a
+ * result of user feedback. This library is platform dependent and therefore it
+ * has implementations for both dart2js and the Dart VM. Both are under
+ * development and may not support all operations yet.
+ *
+ * {@category VM}
+ */
+library dart.mirrors;
+
+import 'dart:async' show Future;
+
+/**
+ * A [MirrorSystem] is the main interface used to reflect on a set of
+ * associated libraries.
+ *
+ * At runtime each running isolate has a distinct [MirrorSystem].
+ *
+ * It is also possible to have a [MirrorSystem] which represents a set
+ * of libraries which are not running -- perhaps at compile-time.  In
+ * this case, all available reflective functionality would be
+ * supported, but runtime functionality (such as invoking a function
+ * or inspecting the contents of a variable) would fail dynamically.
+ */
+abstract class MirrorSystem {
+  /**
+   * All libraries known to the mirror system, indexed by their URI.
+   *
+   * Returns an unmodifiable map of the libraries with [LibraryMirror.uri] as
+   * keys.
+   *
+   * For a runtime mirror system, only libraries which are currently loaded
+   * are included, and repeated calls of this method may return different maps
+   * as libraries are loaded.
+   */
+  Map<Uri, LibraryMirror> get libraries;
+
+  /**
+   * Returns the unique library named [libraryName] if it exists.
+   *
+   * If no unique library exists, an error is thrown.
+   */
+  external LibraryMirror findLibrary(Symbol libraryName);
+
+  /**
+   * A mirror on the isolate associated with this [MirrorSystem].
+   *
+   * This may be null if this mirror system is not running.
+   */
+  IsolateMirror get isolate;
+
+  /**
+   * A mirror on the [:dynamic:] type.
+   */
+  TypeMirror get dynamicType;
+
+  /**
+   * A mirror on the [:void:] type.
+   */
+  TypeMirror get voidType;
+
+  /**
+   * Returns the name of [symbol].
+   *
+   * The following text is non-normative:
+   *
+   * Using this method may result in larger output.  If possible, use
+   * [MirrorsUsed] to specify which symbols must be retained in clear text.
+   */
+  external static String getName(Symbol symbol);
+
+  /**
+   * Returns a symbol for [name].
+   *
+   * If [library] is not a [LibraryMirror] or if [name] is a private identifier
+   * and [library] is `null`, throws an [ArgumentError]. If [name] is a private
+   * identifier, the symbol returned is with respect to [library].
+   *
+   * The following text is non-normative:
+   *
+   * Using this method may result in larger output.  If possible, use
+   * the const constructor of [Symbol] or symbol literals.
+   */
+  external static Symbol getSymbol(String name, [LibraryMirror library]);
+}
+
+/**
+ * Returns a [MirrorSystem] for the current isolate.
+ */
+external MirrorSystem currentMirrorSystem();
+
+/**
+ * Reflects an instance.
+ *
+ * Returns an [InstanceMirror] reflecting [reflectee]. If [reflectee] is a
+ * function or an instance of a class that has a [:call:] method, the returned
+ * instance mirror will be a [ClosureMirror].
+ *
+ * Note that since one cannot obtain an object from another isolate, this
+ * function can only be used to obtain  mirrors on objects of the current
+ * isolate.
+ */
+external InstanceMirror reflect(Object reflectee);
+
+/**
+ * Reflects a class declaration.
+ *
+ * Let *C* be the original class declaration of the class represented by [key].
+ * This function returns a [ClassMirror] reflecting *C*.
+ *
+ * If [key] is not an instance of [Type], then this function throws an
+ * [ArgumentError]. If [key] is the Type for dynamic or a function typedef,
+ * throws an [ArgumentError].
+ *
+ * Note that since one cannot obtain a [Type] object from another isolate, this
+ * function can only be used to obtain class mirrors on classes of the current
+ * isolate.
+ */
+external ClassMirror reflectClass(Type key);
+
+/**
+ * Reflects the type represented by [key].
+ *
+ * If [key] is not an instance of [Type], then this function throws an
+ * [ArgumentError].
+ *
+ * Optionally takes a list of [typeArguments] for generic classes. If the list
+ * is provided, then the [key] must be a generic class type, and the number of
+ * the provided type arguments must be equal to the number of type variables
+ * declared by the class.
+ *
+ * Note that since one cannot obtain a [Type] object from another isolate, this
+ * function can only be used to obtain type mirrors on types of the current
+ * isolate.
+ */
+external TypeMirror reflectType(Type key, [List<Type> typeArguments]);
+
+/**
+ * A [Mirror] reflects some Dart language entity.
+ *
+ * Every [Mirror] originates from some [MirrorSystem].
+ */
+abstract class Mirror {}
+
+/**
+ * An [IsolateMirror] reflects an isolate.
+ */
+abstract class IsolateMirror implements Mirror {
+  /**
+   * A unique name used to refer to the isolate in debugging messages.
+   */
+  String get debugName;
+
+  /**
+   * Whether this mirror reflects the currently running isolate.
+   */
+  bool get isCurrent;
+
+  /**
+   * The root library for the reflected isolate.
+   */
+  LibraryMirror get rootLibrary;
+
+  /**
+   * Whether [other] is an [IsolateMirror] on the same isolate as this mirror.
+   *
+   * The equality holds if and only if
+   *
+   * 1. [other] is a mirror of the same kind, and
+   * 2. the isolate being reflected by this mirror is the same isolate being
+   *    reflected by [other].
+   */
+  bool operator ==(other);
+
+  /**
+   * Loads the library at the given uri into this isolate.
+   *
+   * WARNING: You are strongly encouraged to use Isolate.spawnUri instead when
+   * possible. IsolateMirror.loadUri should only be used when synchronous
+   * communication or shared state with dynamically loaded code is needed.
+   *
+   * If a library with the same canonicalized uri has already been loaded,
+   * the existing library will be returned. (The isolate will not load a new
+   * copy of the library.)
+   *
+   * This behavior is similar to the behavior of an import statement that
+   * appears in the root library, except that the import scope of the root
+   * library is not changed.
+   */
+  Future<LibraryMirror> loadUri(Uri uri);
+}
+
+/**
+ * A [DeclarationMirror] reflects some entity declared in a Dart program.
+ */
+abstract class DeclarationMirror implements Mirror {
+  /**
+   * The simple name for this Dart language entity.
+   *
+   * The simple name is in most cases the identifier name of the entity,
+   * such as 'myMethod' for a method, [:void myMethod() {...}:] or 'mylibrary'
+   * for a [:library 'mylibrary';:] declaration.
+   */
+  Symbol get simpleName;
+
+  /**
+   * The fully-qualified name for this Dart language entity.
+   *
+   * This name is qualified by the name of the owner. For instance,
+   * the qualified name of a method 'method' in class 'Class' in
+   * library 'library' is 'library.Class.method'.
+   *
+   * Returns a [Symbol] constructed from a string representing the
+   * fully qualified name of the reflectee.
+   * Let *o* be the [owner] of this mirror, let *r* be the reflectee of
+   * this mirror, let *p* be the fully qualified
+   * name of the reflectee of *o*, and let *s* be the simple name of *r*
+   * computed by [simpleName].
+   * The fully qualified name of *r* is the
+   * concatenation of *p*, '.', and *s*.
+   *
+   * Because an isolate can contain more than one library with the same name (at
+   * different URIs), a fully-qualified name does not uniquely identify any
+   * language entity.
+   */
+  Symbol get qualifiedName;
+
+  /**
+   * A mirror on the owner of this Dart language entity.
+   *
+   * The owner is the declaration immediately surrounding the reflectee:
+   *
+   * * For a library, the owner is [:null:].
+   * * For a class declaration, typedef or top level function or variable, the
+   *   owner is the enclosing library.
+   * * For a mixin application `S with M`, the owner is the owner of `M`.
+   * * For a constructor, the owner is the immediately enclosing class.
+   * * For a method, instance variable or a static variable, the owner is the
+   *   immediately enclosing class, unless the class is a mixin application
+   *   `S with M`, in which case the owner is `M`. Note that `M` may be an
+   *   invocation of a generic.
+   * * For a parameter, local variable or local function the owner is the
+   *   immediately enclosing function.
+   */
+  DeclarationMirror get owner;
+
+  /**
+   * Whether this declaration is library private.
+   *
+   * Always returns `false` for a library declaration,
+   * otherwise returns `true` if the declaration's name starts with an
+   * underscore character (`_`), and `false` if it doesn't.
+   */
+  bool get isPrivate;
+
+  /**
+   * Whether this declaration is top-level.
+   *
+   * A declaration is considered top-level if its [owner] is a [LibraryMirror].
+   */
+  bool get isTopLevel;
+
+  /**
+   * The source location of this Dart language entity, or [:null:] if the
+   * entity is synthetic.
+   *
+   * If the reflectee is a variable, the returned location gives the position
+   * of the variable name at its point of declaration.
+   *
+   * If the reflectee is a library, class, typedef, function or type variable
+   * with associated metadata, the returned location gives the position of the
+   * first metadata declaration associated with the reflectee.
+   *
+   * Otherwise:
+   *
+   * If the reflectee is a library, the returned location gives the position of
+   * the keyword 'library' at the reflectee's point of declaration, if the
+   * reflectee is a named library, or the first character of the first line in
+   * the compilation unit defining the reflectee if the reflectee is anonymous.
+   *
+   * If the reflectee is an abstract class, the returned location gives the
+   * position of the keyword 'abstract' at the reflectee's point of declaration.
+   * Otherwise, if the reflectee is a class, the returned location gives the
+   * position of the keyword 'class' at the reflectee's point of declaration.
+   *
+   * If the reflectee is a typedef the returned location gives the position of
+   * the of the keyword 'typedef' at the reflectee's point of declaration.
+   *
+   * If the reflectee is a function with a declared return type, the returned
+   * location gives the position of the function's return type at the
+   * reflectee's point of declaration. Otherwise. the returned location gives
+   * the position of the function's name at the reflectee's point of
+   * declaration.
+   *
+   * This operation is optional and may throw an [UnsupportedError].
+   */
+  SourceLocation get location;
+
+  /**
+   * A list of the metadata associated with this declaration.
+   *
+   * Let *D* be the declaration this mirror reflects.
+   * If *D* is decorated with annotations *A1, ..., An*
+   * where *n > 0*, then for each annotation *Ai* associated
+   * with *D, 1 <= i <= n*, let *ci* be the constant object
+   * specified by *Ai*. Then this method returns a list whose
+   * members are instance mirrors on *c1, ..., cn*.
+   * If no annotations are associated with *D*, then
+   * an empty list is returned.
+   *
+   * If evaluating any of *c1, ..., cn* would cause a
+   * compilation error
+   * the effect is the same as if a non-reflective compilation error
+   * had been encountered.
+   */
+  List<InstanceMirror> get metadata;
+}
+
+/**
+ * An [ObjectMirror] is a common superinterface of [InstanceMirror],
+ * [ClassMirror], and [LibraryMirror] that represents their shared
+ * functionality.
+ *
+ * For the purposes of the mirrors library, these types are all
+ * object-like, in that they support method invocation and field
+ * access.  Real Dart objects are represented by the [InstanceMirror]
+ * type.
+ *
+ * See [InstanceMirror], [ClassMirror], and [LibraryMirror].
+ */
+abstract class ObjectMirror implements Mirror {
+  /**
+   * Invokes the named function and returns a mirror on the result.
+   *
+   * Let *o* be the object reflected by this mirror, let *f* be the simple name
+   * of the member denoted by [memberName], let *a1, ..., an* be the elements
+   * of [positionalArguments], let *k1, ..., km* be the identifiers denoted by
+   * the elements of [namedArguments.keys], and let *v1, ..., vm* be the
+   * elements of [namedArguments.values]. Then this method will perform the
+   * method invocation *o.f(a1, ..., an, k1: v1, ..., km: vm)* in a scope that
+   * has access to the private members of *o* (if *o* is a class or library) or
+   * the private members of the class of *o* (otherwise).
+   *
+   * If the invocation returns a result *r*, this method returns the result of
+   * calling [reflect]\(*r*\).
+   *
+   * If the invocation causes a compilation error the effect is the same as if
+   * a non-reflective compilation error had been encountered.
+   *
+   * If the invocation throws an exception *e* (that it does not catch), this
+   * method throws *e*.
+   */
+  /*
+   * TODO(turnidge): Handle ambiguous names.
+   * TODO(turnidge): Handle optional & named arguments.
+   */
+  InstanceMirror invoke(Symbol memberName, List positionalArguments,
+      [Map<Symbol, dynamic> namedArguments]);
+
+  /**
+   * Invokes a getter and returns a mirror on the result.
+   *
+   * The getter can be the implicit getter for a field or a user-defined getter
+   * method.
+   *
+   * Let *o* be the object reflected by this mirror,
+   * let *f* be the simple name of the getter denoted by [fieldName].
+   *
+   * Then this method will perform the getter invocation *o.f* in a scope that
+   * has access to the private members of *o* (if *o* is a class or library) or
+   * the private members of the class of *o* (otherwise).
+   *
+   * If this mirror is an [InstanceMirror], and [fieldName] denotes an instance
+   * method on its reflectee, the result of the invocation is an instance
+   * mirror on a closure corresponding to that method.
+   *
+   * If this mirror is a [LibraryMirror], and [fieldName] denotes a top-level
+   * method in the corresponding library, the result of the invocation is an
+   * instance mirror on a closure corresponding to that method.
+   *
+   * If this mirror is a [ClassMirror], and [fieldName] denotes a static method
+   * in the corresponding class, the result of the invocation is an instance
+   * mirror on a closure corresponding to that method.
+   *
+   * If the invocation returns a result *r*, this method returns the result of
+   * calling [reflect]\(*r*\).
+   *
+   * If the invocation causes a compilation error, the effect is the same as if
+   * a non-reflective compilation error had been encountered.
+   *
+   * If the invocation throws an exception *e* (that it does not catch), this
+   * method throws *e*.
+   */
+  // TODO(ahe): Remove stuff about scope and private members. [fieldName] is a
+  // capability giving access to private members.
+  InstanceMirror getField(Symbol fieldName);
+
+  /**
+   * Invokes a setter and returns a mirror on the result.
+   *
+   * The setter may be either the implicit setter for a non-final field or a
+   * user-defined setter method.
+   *
+   * Let *o* be the object reflected by this mirror,
+   * let *f* be the simple name of the getter denoted by [fieldName],
+   * and let *a* be the object bound to [value].
+   *
+   * Then this method will perform the setter invocation *o.f = a* in a scope
+   * that has access to the private members of *o* (if *o* is a class or
+   * library) or the private members of the class of *o* (otherwise).
+   *
+   * If the invocation returns a result *r*, this method returns the result of
+   * calling [reflect]\([value]\).
+   *
+   * If the invocation causes a compilation error, the effect is the same as if
+   * a non-reflective compilation error had been encountered.
+   *
+   * If the invocation throws an exception *e* (that it does not catch) this
+   * method throws *e*.
+   */
+  /* TODO(turnidge): Handle ambiguous names.*/
+  InstanceMirror setField(Symbol fieldName, Object value);
+
+  /**
+   * Performs [invocation] on the reflectee of this [ObjectMirror].
+   *
+   * Equivalent to
+   *
+   *     if (invocation.isGetter) {
+   *       return this.getField(invocation.memberName).reflectee;
+   *     } else if (invocation.isSetter) {
+   *       return this.setField(invocation.memberName,
+   *                            invocation.positionalArguments[0]).reflectee;
+   *     } else {
+   *       return this.invoke(invocation.memberName,
+   *                          invocation.positionalArguments,
+   *                          invocation.namedArguments).reflectee;
+   *     }
+   */
+  delegate(Invocation invocation);
+}
+
+/**
+ * An [InstanceMirror] reflects an instance of a Dart language object.
+ */
+abstract class InstanceMirror implements ObjectMirror {
+  /**
+   * A mirror on the type of the reflectee.
+   *
+   * Returns a mirror on the actual class of the reflectee.
+   * The class of the reflectee may differ from
+   * the object returned by invoking [runtimeType] on
+   * the reflectee.
+   */
+  ClassMirror get type;
+
+  /**
+   * Whether [reflectee] will return the instance reflected by this mirror.
+   *
+   * This will always be true in the local case (reflecting instances in the
+   * same isolate), but only true in the remote case if this mirror reflects a
+   * simple value.
+   *
+   * A value is simple if one of the following holds:
+   *
+   * * the value is [:null:]
+   * * the value is of type [num]
+   * * the value is of type [bool]
+   * * the value is of type [String]
+   */
+  bool get hasReflectee;
+
+  /**
+   * If the [InstanceMirror] reflects an instance it is meaningful to
+   * have a local reference to, we provide access to the actual
+   * instance here.
+   *
+   * If you access [reflectee] when [hasReflectee] is false, an
+   * exception is thrown.
+   */
+  get reflectee;
+
+  /**
+   * Whether this mirror is equal to [other].
+   *
+   * The equality holds if and only if
+   *
+   * 1. [other] is a mirror of the same kind, and
+   * 2. either
+   *
+   *    a. [hasReflectee] is true and so is
+   *    [:identical(reflectee, other.reflectee):], or
+   *
+   *    b. the remote objects reflected by this mirror and by [other] are
+   *    identical.
+   */
+  bool operator ==(other);
+}
+
+/**
+ * A [ClosureMirror] reflects a closure.
+ *
+ * A [ClosureMirror] provides the ability to execute its reflectee and
+ * introspect its function.
+ */
+abstract class ClosureMirror implements InstanceMirror {
+  /**
+   * A mirror on the function associated with this closure.
+   *
+   * The function associated with an implicit closure of a function is that
+   * function.
+   *
+   * The function associated with an instance of a class that has a [:call:]
+   * method is that [:call:] method.
+   *
+   * A Dart implementation might choose to create a class for each closure
+   * expression, in which case [:function:] would be the same as
+   * [:type.declarations[#call]:]. But the Dart language model does not require
+   * this. A more typical implementation involves a single closure class for
+   * each type signature, where the call method dispatches to a function held
+   * in the closure rather the call method
+   * directly implementing the closure body. So one cannot rely on closures from
+   * distinct closure expressions having distinct classes ([:type:]), but one
+   * can rely on them having distinct functions ([:function:]).
+   */
+  MethodMirror get function;
+
+  /**
+   * Executes the closure and returns a mirror on the result.
+   *
+   * Let *f* be the closure reflected by this mirror,
+   * let *a1, ..., an* be the elements of [positionalArguments],
+   * let *k1, ..., km* be the identifiers denoted by the elements of
+   * [namedArguments.keys],
+   * and let *v1, ..., vm* be the elements of [namedArguments.values].
+   *
+   * Then this method will perform the method invocation
+   * *f(a1, ..., an, k1: v1, ..., km: vm)*.
+   *
+   * If the invocation returns a result *r*, this method returns the result of
+   * calling [reflect]\(*r*\).
+   *
+   * If the invocation causes a compilation error, the effect is the same as if
+   * a non-reflective compilation error had been encountered.
+   *
+   * If the invocation throws an exception *e* (that it does not catch), this
+   * method throws *e*.
+   */
+  InstanceMirror apply(List positionalArguments,
+      [Map<Symbol, dynamic> namedArguments]);
+}
+
+/**
+ * A [LibraryMirror] reflects a Dart language library, providing
+ * access to the variables, functions, and classes of the
+ * library.
+ */
+abstract class LibraryMirror implements DeclarationMirror, ObjectMirror {
+  /**
+   * The absolute uri of the library.
+   */
+  Uri get uri;
+
+  /**
+   * Returns an immutable map of the declarations actually given in the library.
+   *
+   * This map includes all regular methods, getters, setters, fields, classes
+   * and typedefs actually declared in the library. The map is keyed by the
+   * simple names of the declarations.
+   */
+  Map<Symbol, DeclarationMirror> get declarations;
+
+  /**
+   * Whether this mirror is equal to [other].
+   *
+   * The equality holds if and only if
+   *
+   * 1. [other] is a mirror of the same kind, and
+   * 2. The library being reflected by this mirror and the library being
+   *    reflected by [other] are the same library in the same isolate.
+   */
+  bool operator ==(other);
+
+  /**
+   * Returns a list of the imports and exports in this library;
+   */
+  List<LibraryDependencyMirror> get libraryDependencies;
+}
+
+/// A mirror on an import or export declaration.
+abstract class LibraryDependencyMirror implements Mirror {
+  /// Is `true` if this dependency is an import.
+  bool get isImport;
+
+  /// Is `true` if this dependency is an export.
+  bool get isExport;
+
+  /// Returns true iff this dependency is a deferred import. Otherwise returns
+  /// false.
+  bool get isDeferred;
+
+  /// Returns the library mirror of the library that imports or exports the
+  /// [targetLibrary].
+  LibraryMirror get sourceLibrary;
+
+  /// Returns the library mirror of the library that is imported or exported,
+  /// or null if the library is not loaded.
+  LibraryMirror get targetLibrary;
+
+  /// Returns the prefix if this is a prefixed import and `null` otherwise.
+  Symbol get prefix;
+
+  /// Returns the list of show/hide combinators on the import/export
+  /// declaration.
+  List<CombinatorMirror> get combinators;
+
+  /// Returns the source location for this import/export declaration.
+  SourceLocation get location;
+
+  List<InstanceMirror> get metadata;
+
+  /// Returns a future that completes with a library mirror on the library being
+  /// imported or exported when it is loaded, and initiates a load of that
+  /// library if it is not loaded.
+  Future<LibraryMirror> loadLibrary();
+}
+
+/// A mirror on a show/hide combinator declared on a library dependency.
+abstract class CombinatorMirror implements Mirror {
+  /// The list of identifiers on the combinator.
+  List<Symbol> get identifiers;
+
+  /// Is `true` if this is a 'show' combinator.
+  bool get isShow;
+
+  /// Is `true` if this is a 'hide' combinator.
+  bool get isHide;
+}
+
+/**
+ * A [TypeMirror] reflects a Dart language class, typedef,
+ * function type or type variable.
+ */
+abstract class TypeMirror implements DeclarationMirror {
+  /**
+   * Returns true if this mirror reflects dynamic, a non-generic class or
+   * typedef, or an instantiated generic class or typedef in the current
+   * isolate. Otherwise, returns false.
+   */
+  bool get hasReflectedType;
+
+  /**
+   * If [:hasReflectedType:] returns true, returns the corresponding [Type].
+   * Otherwise, an [UnsupportedError] is thrown.
+   */
+  Type get reflectedType;
+
+  /**
+   * An immutable list with mirrors for all type variables for this type.
+   *
+   * If this type is a generic declaration or an invocation of a generic
+   * declaration, the returned list contains mirrors on the type variables
+   * declared in the original declaration.
+   * Otherwise, the returned list is empty.
+   *
+   * This list preserves the order of declaration of the type variables.
+   */
+  List<TypeVariableMirror> get typeVariables;
+
+  /**
+   * An immutable list with mirrors for all type arguments for
+   * this type.
+   *
+   * If the reflectee is an invocation of a generic class,
+   * the type arguments are the bindings of its type parameters.
+   * If the reflectee is the original declaration of a generic,
+   * it has no type arguments and this method returns an empty list.
+   * If the reflectee is not generic, then
+   * it has no type arguments and this method returns an empty list.
+   *
+   * This list preserves the order of declaration of the type variables.
+   */
+  List<TypeMirror> get typeArguments;
+
+  /**
+   * Is this the original declaration of this type?
+   *
+   * For most classes, they are their own original declaration.  For
+   * generic classes, however, there is a distinction between the
+   * original class declaration, which has unbound type variables, and
+   * the instantiations of generic classes, which have bound type
+   * variables.
+   */
+  bool get isOriginalDeclaration;
+
+  /**
+   * A mirror on the original declaration of this type.
+   *
+   * For most classes, they are their own original declaration.  For
+   * generic classes, however, there is a distinction between the
+   * original class declaration, which has unbound type variables, and
+   * the instantiations of generic classes, which have bound type
+   * variables.
+   */
+  TypeMirror get originalDeclaration;
+
+  /**
+   * Checks the subtype relationship, denoted by `<:` in the language
+   * specification.
+   *
+   * This is the type relationship used in `is` test checks.
+   */
+  bool isSubtypeOf(TypeMirror other);
+
+  /**
+   * Checks the assignability relationship, denoted by `<=>` in the language
+   * specification.
+   *
+   * This is the type relationship tested on assignment in checked mode.
+   */
+  bool isAssignableTo(TypeMirror other);
+}
+
+/**
+ * A [ClassMirror] reflects a Dart language class.
+ */
+abstract class ClassMirror implements TypeMirror, ObjectMirror {
+  /**
+   * A mirror on the superclass on the reflectee.
+   *
+   * If this type is [:Object:], the superclass will be null.
+   */
+  ClassMirror get superclass;
+
+  /**
+   * A list of mirrors on the superinterfaces of the reflectee.
+   */
+  List<ClassMirror> get superinterfaces;
+
+  /**
+   * Is the reflectee abstract?
+   */
+  bool get isAbstract;
+
+  /**
+   * Is the reflectee an enum?
+   */
+  bool get isEnum;
+
+  /**
+   * Returns an immutable map of the declarations actually given in the class
+   * declaration.
+   *
+   * This map includes all regular methods, getters, setters, fields,
+   * constructors and type variables actually declared in the class. Both
+   * static and instance members are included, but no inherited members are
+   * included. The map is keyed by the simple names of the declarations.
+   *
+   * This does not include inherited members.
+   */
+  Map<Symbol, DeclarationMirror> get declarations;
+
+  /**
+   * Returns a map of the methods, getters and setters of an instance of the
+   * class.
+   *
+   * The intent is to capture those members that constitute the API of an
+   * instance. Hence fields are not included, but the getters and setters
+   * implicitly introduced by fields are included. The map includes methods,
+   * getters and setters that are inherited as well as those introduced by the
+   * class itself.
+   *
+   * The map is keyed by the simple names of the members.
+   */
+  Map<Symbol, MethodMirror> get instanceMembers;
+
+  /**
+   * Returns a map of the static methods, getters and setters of the class.
+   *
+   * The intent is to capture those members that constitute the API of a class.
+   * Hence fields are not included, but the getters and setters implicitly
+   * introduced by fields are included.
+   *
+   * The map is keyed by the simple names of the members.
+   */
+  Map<Symbol, MethodMirror> get staticMembers;
+
+  /**
+   * The mixin of this class.
+   *
+   * If this class is the result of a mixin application of the form S with M,
+   * returns a class mirror on M. Otherwise returns a class mirror on
+   * the reflectee.
+   */
+  ClassMirror get mixin;
+
+  // TODO(ahe): What about:
+  // /// Finds the instance member named [name] declared or inherited in the
+  // /// reflected class.
+  // DeclarationMirror instanceLookup(Symbol name);
+
+  /**
+   * Invokes the named constructor and returns a mirror on the result.
+   *
+   * Let *c* be the class reflected by this mirror,
+   * let *a1, ..., an* be the elements of [positionalArguments],
+   * let *k1, ..., km* be the identifiers denoted by the elements of
+   * [namedArguments.keys],
+   * and let *v1, ..., vm* be the elements of [namedArguments.values].
+   *
+   * If [constructorName] was created from the empty string, then this method
+   * will execute the instance creation expression
+   * *new c(a1, ..., an, k1: v1, ..., km: vm)* in a scope that has access to
+   * the private members of *c*.
+   *
+   * Otherwise, let *f* be the simple name of the constructor denoted by
+   * [constructorName]. Then this method will execute the instance creation
+   * expression *new c.f(a1, ..., an, k1: v1, ..., km: vm)* in a scope that has
+   * access to the private members of *c*.
+   *
+   * In either case:
+   *
+   * * If the expression evaluates to a result *r*, this method returns the
+   *   result of calling [reflect]\(*r*\).
+   * * If evaluating the expression causes a compilation error, the effect is
+   *   the same as if a non-reflective compilation error had been encountered.
+   * * If evaluating the expression throws an exception *e* (that it does not
+   *   catch), this method throws *e*.
+   */
+  InstanceMirror newInstance(Symbol constructorName, List positionalArguments,
+      [Map<Symbol, dynamic> namedArguments]);
+
+  /**
+   * Whether this mirror is equal to [other].
+   *
+   * The equality holds if and only if
+   *
+   * 1. [other] is a mirror of the same kind, and
+   * 2. This mirror and [other] reflect the same class.
+   *
+   * Note that if the reflected class is an invocation of a generic class, 2.
+   * implies that the reflected class and [other] have equal type arguments.
+   */
+  bool operator ==(other);
+
+  /**
+   * Returns whether the class denoted by the receiver is a subclass of the
+   * class denoted by the argument.
+   *
+   * Note that the subclass relationship is reflexive.
+   */
+  bool isSubclassOf(ClassMirror other);
+}
+
+/**
+ * A [FunctionTypeMirror] represents the type of a function in the
+ * Dart language.
+ */
+abstract class FunctionTypeMirror implements ClassMirror {
+  /**
+   * Returns the return type of the reflectee.
+   */
+  TypeMirror get returnType;
+
+  /**
+   * Returns a list of the parameter types of the reflectee.
+   */
+  List<ParameterMirror> get parameters;
+
+  /**
+   * A mirror on the [:call:] method for the reflectee.
+   */
+  // This is only here because in the past the VM did not implement a call
+  // method on closures.
+  MethodMirror get callMethod;
+}
+
+/**
+ * A [TypeVariableMirror] represents a type parameter of a generic type.
+ */
+abstract class TypeVariableMirror extends TypeMirror {
+  /**
+   * A mirror on the type that is the upper bound of this type variable.
+   */
+  TypeMirror get upperBound;
+
+  /**
+   * Is the reflectee static?
+   *
+   * For the purposes of the mirrors library, type variables are considered
+   * non-static.
+   */
+  bool get isStatic;
+
+  /**
+   * Whether [other] is a [TypeVariableMirror] on the same type variable as this
+   * mirror.
+   *
+   * The equality holds if and only if
+   *
+   * 1. [other] is a mirror of the same kind, and
+   * 2. [:simpleName == other.simpleName:] and [:owner == other.owner:].
+   */
+  bool operator ==(other);
+}
+
+/**
+ * A [TypedefMirror] represents a typedef in a Dart language program.
+ */
+abstract class TypedefMirror implements TypeMirror {
+  /**
+   * The defining type for this typedef.
+   *
+   * If the type referred to by the reflectee is a function type *F*, the
+   * result will be [:FunctionTypeMirror:] reflecting *F* which is abstract
+   * and has an abstract method [:call:] whose signature corresponds to *F*.
+   * For instance [:void f(int):] is the referent for [:typedef void f(int):].
+   */
+  FunctionTypeMirror get referent;
+}
+
+/**
+ * A [MethodMirror] reflects a Dart language function, method,
+ * constructor, getter, or setter.
+ */
+abstract class MethodMirror implements DeclarationMirror {
+  /**
+   * A mirror on the return type for the reflectee.
+   */
+  TypeMirror get returnType;
+
+  /**
+   * The source code for the reflectee, if available. Otherwise null.
+   */
+  String get source;
+
+  /**
+   * A list of mirrors on the parameters for the reflectee.
+   */
+  List<ParameterMirror> get parameters;
+
+  /**
+   * A function is considered non-static iff it is permited to refer to 'this'.
+   *
+   * Note that generative constructors are considered non-static, whereas
+   * factory constructors are considered static.
+   */
+  bool get isStatic;
+
+  /**
+   * Is the reflectee abstract?
+   */
+  bool get isAbstract;
+
+  /**
+   * Returns true if the reflectee is synthetic, and returns false otherwise.
+   *
+   * A reflectee is synthetic if it is a getter or setter implicitly introduced
+   * for a field or Type, or if it is a constructor that was implicitly
+   * introduced as a default constructor or as part of a mixin application.
+   */
+  bool get isSynthetic;
+
+  /**
+   * Is the reflectee a regular function or method?
+   *
+   * A function or method is regular if it is not a getter, setter, or
+   * constructor.  Note that operators, by this definition, are
+   * regular methods.
+   */
+  bool get isRegularMethod;
+
+  /**
+   * Is the reflectee an operator?
+   */
+  bool get isOperator;
+
+  /**
+   * Is the reflectee a getter?
+   */
+  bool get isGetter;
+
+  /**
+   * Is the reflectee a setter?
+   */
+  bool get isSetter;
+
+  /**
+   * Is the reflectee a constructor?
+   */
+  bool get isConstructor;
+
+  /**
+   * The constructor name for named constructors and factory methods.
+   *
+   * For unnamed constructors, this is the empty string.  For
+   * non-constructors, this is the empty string.
+   *
+   * For example, [:'bar':] is the constructor name for constructor
+   * [:Foo.bar:] of type [:Foo:].
+   */
+  Symbol get constructorName;
+
+  /**
+   * Is the reflectee a const constructor?
+   */
+  bool get isConstConstructor;
+
+  /**
+   * Is the reflectee a generative constructor?
+   */
+  bool get isGenerativeConstructor;
+
+  /**
+   * Is the reflectee a redirecting constructor?
+   */
+  bool get isRedirectingConstructor;
+
+  /**
+   * Is the reflectee a factory constructor?
+   */
+  bool get isFactoryConstructor;
+
+  /**
+   * Whether this mirror is equal to [other].
+   *
+   * The equality holds if and only if
+   *
+   * 1. [other] is a mirror of the same kind, and
+   * 2. [:simpleName == other.simpleName:] and [:owner == other.owner:].
+   */
+  bool operator ==(other);
+}
+
+/**
+ * A [VariableMirror] reflects a Dart language variable declaration.
+ */
+abstract class VariableMirror implements DeclarationMirror {
+  /**
+   * Returns a mirror on the type of the reflectee.
+   */
+  TypeMirror get type;
+
+  /**
+   * Returns [:true:] if the reflectee is a static variable.
+   * Otherwise returns [:false:].
+   *
+   * For the purposes of the mirror library, top-level variables are
+   * implicitly declared static.
+   */
+  bool get isStatic;
+
+  /**
+   * Returns [:true:] if the reflectee is a final variable.
+   * Otherwise returns [:false:].
+   */
+  bool get isFinal;
+
+  /**
+   * Returns [:true:] if the reflectee is declared [:const:].
+   * Otherwise returns [:false:].
+   */
+  bool get isConst;
+
+  /**
+   * Whether this mirror is equal to [other].
+   *
+   * The equality holds if and only if
+   *
+   * 1. [other] is a mirror of the same kind, and
+   * 2. [:simpleName == other.simpleName:] and [:owner == other.owner:].
+   */
+  bool operator ==(other);
+}
+
+/**
+ * A [ParameterMirror] reflects a Dart formal parameter declaration.
+ */
+abstract class ParameterMirror implements VariableMirror {
+  /**
+   * A mirror on the type of this parameter.
+   */
+  TypeMirror get type;
+
+  /**
+   * Returns [:true:] if the reflectee is an optional parameter.
+   * Otherwise returns [:false:].
+   */
+  bool get isOptional;
+
+  /**
+   * Returns [:true:] if the reflectee is a named parameter.
+   * Otherwise returns [:false:].
+   */
+  bool get isNamed;
+
+  /**
+   * Returns [:true:] if the reflectee has explicitly declared a default value.
+   * Otherwise returns [:false:].
+   */
+  bool get hasDefaultValue;
+
+  /**
+   * Returns the default value of an optional parameter.
+   *
+   * Returns an [InstanceMirror] on the (compile-time constant)
+   * default value for an optional parameter.
+   * If no default value is declared, it defaults to `null`
+   * and a mirror of `null` is returned.
+   *
+   * Returns `null` for a required parameter.
+   */
+  InstanceMirror get defaultValue;
+}
+
+/**
+ * A [SourceLocation] describes the span of an entity in Dart source code.
+ */
+abstract class SourceLocation {
+  /**
+   * The 1-based line number for this source location.
+   *
+   * A value of 0 means that the line number is unknown.
+   */
+  int get line;
+
+  /**
+   * The 1-based column number for this source location.
+   *
+   * A value of 0 means that the column number is unknown.
+   */
+  int get column;
+
+  /**
+   * Returns the URI where the source originated.
+   */
+  Uri get sourceUri;
+}
+
+/**
+ * Class used for encoding comments as metadata annotations.
+ */
+class Comment {
+  /**
+   * The comment text as written in the source text.
+   */
+  final String text;
+
+  /**
+   * The comment text without the start, end, and padding text.
+   *
+   * For example, if [text] is [: /** Comment text. */ :] then the [trimmedText]
+   * is [: Comment text. :].
+   */
+  final String trimmedText;
+
+  /**
+   * Is [:true:] if this comment is a documentation comment.
+   *
+   * That is, that the comment is either enclosed in [: /** ... */ :] or starts
+   * with [: /// :].
+   */
+  final bool isDocComment;
+
+  const Comment(this.text, this.trimmedText, this.isDocComment);
+}
+
+/**
+ * Annotation describing how "dart:mirrors" is used (EXPERIMENTAL).
+ *
+ * When used as metadata on an import of "dart:mirrors" in library *L*, this
+ * class describes how "dart:mirrors" is used by library *L* unless overridden.
+ * See [override].
+ *
+ * The following text is non-normative:
+ *
+ * In some scenarios, for example, when minifying Dart code, or when generating
+ * JavaScript code from a Dart program, the size and performance of the output
+ * can suffer from use of reflection.  In those cases, telling the compiler
+ * what is used, can have a significant impact.
+ *
+ * Example usage:
+ *
+ *     @MirrorsUsed(symbols: 'foo')
+ *     import 'dart:mirrors';
+ *
+ *     class Foo {
+ *       noSuchMethod(Invocation invocation) {
+ *         print(MirrorSystem.getName(invocation.memberName));
+ *       }
+ *     }
+ *
+ *     main() {
+ *       new Foo().foo(); // Prints "foo".
+ *       new Foo().bar(); // Might print an arbitrary (mangled) name, "bar".
+ *     }
+ *
+ * For a detailed description of the parameters to the [MirrorsUsed] constructor
+ * see the comments for [symbols], [targets], [metaTargets] and [override].
+ *
+ * An import of `dart:mirrors` may have multiple [MirrorsUsed] annotations. This
+ * is particularly helpful to specify overrides for specific libraries. For
+ * example:
+ *
+ *     @MirrorsUsed(targets: 'foo.Bar', override: 'foo')
+ *     @MirrorsUsed(targets: 'Bar')
+ *     import 'dart:mirrors';
+ *
+ * will ensure that the target `Bar` from the current library and from library
+ * `foo` is available for reflection. See also [override].
+ */
+@Deprecated("No longer has any effect. Will be removed in a later release.")
+class MirrorsUsed {
+  // Note: the fields of this class are untyped.  This is because the most
+  // convenient way to specify symbols today is using a single string. In
+  // some cases, a const list of classes might be convenient. Some
+  // might prefer to use a const list of symbols.
+
+  /**
+   * The list of strings passed to new [Symbol], and symbols that might be
+   * passed to [MirrorSystem.getName].
+   *
+   * Combined with the names of [targets], [metaTargets] and their members,
+   * this forms the complete list of strings passed to new [Symbol], and
+   * symbols that might be passed to [MirrorSystem.getName] by the library to
+   * which this metadata applies.
+   *
+   * The following text is non-normative:
+   *
+   * Dart2js currently supports the following formats to specify symbols:
+   *
+   * * A constant [List] of [String] constants representing symbol names,
+   *   e.g., `const ['foo', 'bar']`.
+   * * A single [String] constant whose value is a comma-separated list of
+   *   symbol names, e.g., `"foo, bar"`.
+   *
+   * Specifying the `symbols` field turns off the following warnings emitted by
+   * dart2js:
+   *
+   * * Using "MirrorSystem.getName" may result in larger output.
+   * * Using "new Symbol" may result in larger output.
+   *
+   * For example, if you're using [noSuchMethod] to interact with a database,
+   * extract all the possible column names and include them in this list.
+   * Similarly, if you're using [noSuchMethod] to interact with another
+   * language (JavaScript, for example) extract all the identifiers from the
+   * API you use and include them in this list.
+   *
+   * Note that specifying a symbol only ensures that the symbol will be
+   * available under that name at runtime. It does not mark targets with
+   * that name as available for reflection. See [targets] and [metaTargets]
+   * for that purpose.
+   */
+  final symbols;
+
+  /**
+   * A list of reflective targets.
+   *
+   * Combined with [metaTargets], this provides the complete list of reflective
+   * targets used by the library to which this metadata applies.
+   *
+   * The following text is non-normative:
+   *
+   * For now, there is no formal description of what a reflective target is.
+   * Informally, a target is a library, a class, a method or a field.
+   *
+   * Dart2js currently supports the following formats to specify targets:
+   *
+   * * A constant [List] containing [String] constants representing (qualified)
+   *   names of targets and Dart types.
+   * * A single [String] constant whose value is a comma-separated list of
+   *   (qualified) names.
+   * * A single Dart type.
+   *
+   * A (qualified) name is resolved to a target as follows:
+   *
+   * 1. If the qualified name matches a library name, the matching library is
+   *    the target.
+   * 2. Else, find the longest prefix of the name such that the prefix ends
+   *    just before a `.` and is a library name.
+   * 3. Use that library as current scope. If no matching prefix was found, use
+   *    the current library, i.e., the library where the [MirrorsUsed]
+   *    annotation was placed.
+   * 4. Split the remaining suffix (the entire name if no library name was
+   *    found in step 3) into a list of [String] using `.` as a
+   *    separator.
+   * 5. Select all targets in the current scope whose name matches a [String]
+   *    from the list.
+   *
+   * For example:
+   *
+   *     library my.library.one;
+   *
+   *     class A {
+   *       var aField;
+   *     }
+   *
+   *     library main;
+   *
+   *     @MirrorsUsed(targets: "my.library.one.A.aField")
+   *     import "dart:mirrors";
+   *
+   * The [MirrorsUsed] annotation specifies `A` and `aField` from library
+   * `my.library.one` as targets. This will mark the class `A` as a reflective
+   * target. The target specification for `aField` has no effect, as there is
+   * no target in `my.library.one` with that name.
+   *
+   * Note that everything within a target also is available for reflection.
+   * So, if a library is specified as target, all classes in that library
+   * become targets for reflection. Likewise, if a class is a target, all
+   * its methods and fields become targets for reflection. As a consequence,
+   * `aField` in the above example is also a reflective target.
+   *
+   */
+  final targets;
+
+  /**
+   * A list of classes that when used as metadata indicates a reflective
+   * target. See also [targets].
+   *
+   * The following text is non-normative:
+   *
+   * The format for specifying the list of classes is the same as used for
+   * specifying [targets]. However, as a library cannot be used as a metadata
+   * annotation in Dart, adding a library to the list of [metaTargets] has no
+   * effect. In particular, adding a library to [metaTargets] does not make
+   * the library's classes valid metadata annotations to enable reflection.
+   *
+   * If an instance of a class specified in [metaTargets] is used as
+   * metadata annotation on a library, class, field or method, that library,
+   * class, field or  method is added to the set of targets for reflection.
+   *
+   * Example usage:
+   *
+   *     library example;
+   *     @MirrorsUsed(metaTargets: "example.Reflectable")
+   *     import "dart:mirrors";
+   *
+   *     class Reflectable {
+   *       const Reflectable();
+   *     }
+   *
+   *     class Foo {
+   *       @Reflectable()
+   *       reflectableMethod() { ... }
+   *
+   *       nonReflectableMethod() { ... }
+   *     }
+   *
+   * In the above example. `reflectableMethod` is marked as reflectable by
+   * using the `Reflectable` class, which in turn is specified in the
+   * [metaTargets] annotation.
+   *
+   * The method `nonReflectableMethod` lacks a metadata annotation and thus
+   * will not be reflectable at runtime.
+   */
+  final metaTargets;
+
+  /**
+   * A list of library names or "*".
+   *
+   * When used as metadata on an import of "dart:mirrors", this metadata does
+   * not apply to the library in which the annotation is used, but instead
+   * applies to the other libraries (all libraries if "*" is used).
+   *
+   * The following text is non-normative:
+   *
+   * Dart2js currently supports the following formats to specify libraries:
+   *
+   * * A constant [List] containing [String] constants representing names of
+   *   libraries.
+   * * A single [String] constant whose value is a comma-separated list of
+   *   library names.
+   *
+   * Conceptually, a [MirrorsUsed] annotation with [override] has the same
+   * effect as placing the annotation directly on the import of `dart:mirrors`
+   * in each of the referenced libraries. Thus, if the library had no
+   * [MirrorsUsed] annotation before, its unconditional import of
+   * `dart:mirrors` is overridden by an annotated import.
+   *
+   * Note that, like multiple explicit [MirrorsUsed] annotations, using
+   * override on a library with an existing [MirrorsUsed] annotation is
+   * additive. That is, the overall set of reflective targets is the union
+   * of the reflective targets that arise from the original and the
+   * overriding [MirrorsUsed] annotations.
+   *
+   * The use of [override] is only meaningful for libraries that have an
+   * import of `dart:mirrors` without annotation because otherwise it would
+   * work exactly the same way without the [override] parameter.
+   *
+   * While the annotation will apply to the given target libraries, the
+   * [symbols], [targets] and [metaTargets] are still evaluated in the
+   * scope of the annotation. Thus, to select a target from library `foo`,
+   * a qualified name has to be used or, if the target is visible in the
+   * current scope, its type may be referenced.
+   *
+   * For example, the following code marks all targets in the library `foo`
+   * as reflectable that have a metadata annotation using the `Reflectable`
+   * class from the same library.
+   *
+   *     @MirrorsUsed(metaTargets: "foo.Reflectable", override: "foo")
+   *
+   * However, the following code would require the use of the `Reflectable`
+   * class from the current library, instead.
+   *
+   *     @MirrorsUsed(metaTargets: "Reflectable", override: "foo")
+   *
+   */
+  final override;
+
+  /**
+   * See the documentation for [MirrorsUsed.symbols], [MirrorsUsed.targets],
+   * [MirrorsUsed.metaTargets] and [MirrorsUsed.override] for documentation
+   * of the parameters.
+   */
+  const MirrorsUsed(
+      {this.symbols, this.targets, this.metaTargets, this.override});
+}
diff --git a/sdk_nnbd/lib/mirrors/mirrors_sources.gni b/sdk_nnbd/lib/mirrors/mirrors_sources.gni
new file mode 100644
index 0000000..e019c34
--- /dev/null
+++ b/sdk_nnbd/lib/mirrors/mirrors_sources.gni
@@ -0,0 +1,8 @@
+# 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.
+
+mirrors_sdk_sources = [
+  "mirrors.dart",
+  # The above file needs to be first if additional parts are added to the lib.
+]
diff --git a/sdk_nnbd/lib/profiler/profiler.dart b/sdk_nnbd/lib/profiler/profiler.dart
new file mode 100644
index 0000000..1b96dfe
--- /dev/null
+++ b/sdk_nnbd/lib/profiler/profiler.dart
@@ -0,0 +1,10 @@
+// Copyright (c) 2014, 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.
+
+/// Please see 'dart:developer'.
+@Deprecated("Dart SDK 1.12")
+library dart.profiler;
+
+export 'dart:developer'
+    show getCurrentTag, Counter, Gauge, Metric, Metrics, UserTag;
diff --git a/sdk_nnbd/lib/profiler/profiler_sources.gni b/sdk_nnbd/lib/profiler/profiler_sources.gni
new file mode 100644
index 0000000..adbf447
--- /dev/null
+++ b/sdk_nnbd/lib/profiler/profiler_sources.gni
@@ -0,0 +1,8 @@
+# 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.
+
+profiler_sdk_sources = [
+  "profiler.dart",
+  # The above file needs to be first if additional parts are added to the lib.
+]
diff --git a/sdk_nnbd/lib/svg/dart2js/svg_dart2js.dart b/sdk_nnbd/lib/svg/dart2js/svg_dart2js.dart
new file mode 100644
index 0000000..7966fd7
--- /dev/null
+++ b/sdk_nnbd/lib/svg/dart2js/svg_dart2js.dart
@@ -0,0 +1,4011 @@
+/**
+ * Scalable Vector Graphics:
+ * Two-dimensional vector graphics with support for events and animation.
+ *
+ * For details about the features and syntax of SVG, a W3C standard,
+ * refer to the
+ * [Scalable Vector Graphics Specification](http://www.w3.org/TR/SVG/).
+ *
+ * {@category Web}
+ */
+library dart.dom.svg;
+
+import 'dart:async';
+import 'dart:collection' hide LinkedList, LinkedListEntry;
+import 'dart:_internal' show FixedLengthListMixin;
+import 'dart:html';
+import 'dart:html_common';
+import 'dart:_js_helper' show Creates, Returns, JSName, Native;
+import 'dart:_foreign_helper' show JS;
+import 'dart:_interceptors' show Interceptor;
+// DO NOT EDIT - unless you are editing documentation as per:
+// https://code.google.com/p/dart/wiki/ContributingHTMLDocumentation
+// Auto-generated dart:svg library.
+
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+class _SvgElementFactoryProvider {
+  static SvgElement createSvgElement_tag(String tag) {
+    final Element temp =
+        document.createElementNS("http://www.w3.org/2000/svg", tag);
+    return temp;
+  }
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGAElement")
+class AElement extends GraphicsElement implements UriReference {
+  // To suppress missing implicit constructor warnings.
+  factory AElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory AElement() => _SvgElementFactoryProvider.createSvgElement_tag("a");
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  AElement.created() : super.created();
+
+  final AnimatedString target;
+
+  // From SVGURIReference
+
+  final AnimatedString href;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGAngle")
+class Angle extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory Angle._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  static const int SVG_ANGLETYPE_DEG = 2;
+
+  static const int SVG_ANGLETYPE_GRAD = 4;
+
+  static const int SVG_ANGLETYPE_RAD = 3;
+
+  static const int SVG_ANGLETYPE_UNKNOWN = 0;
+
+  static const int SVG_ANGLETYPE_UNSPECIFIED = 1;
+
+  final int unitType;
+
+  num value;
+
+  String valueAsString;
+
+  num valueInSpecifiedUnits;
+
+  void convertToSpecifiedUnits(int unitType) native;
+
+  void newValueSpecifiedUnits(int unitType, num valueInSpecifiedUnits) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.FIREFOX)
+@SupportedBrowser(SupportedBrowser.SAFARI)
+@Unstable()
+@Native("SVGAnimateElement")
+class AnimateElement extends AnimationElement {
+  // To suppress missing implicit constructor warnings.
+  factory AnimateElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory AnimateElement() =>
+      _SvgElementFactoryProvider.createSvgElement_tag("animate");
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  AnimateElement.created() : super.created();
+
+  /// Checks if this type is supported on the current platform.
+  static bool get supported =>
+      SvgElement.isTagSupported('animate') &&
+      (new SvgElement.tag('animate') is AnimateElement);
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.FIREFOX)
+@SupportedBrowser(SupportedBrowser.SAFARI)
+@Unstable()
+@Native("SVGAnimateMotionElement")
+class AnimateMotionElement extends AnimationElement {
+  // To suppress missing implicit constructor warnings.
+  factory AnimateMotionElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory AnimateMotionElement() =>
+      _SvgElementFactoryProvider.createSvgElement_tag("animateMotion");
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  AnimateMotionElement.created() : super.created();
+
+  /// Checks if this type is supported on the current platform.
+  static bool get supported =>
+      SvgElement.isTagSupported('animateMotion') &&
+      (new SvgElement.tag('animateMotion') is AnimateMotionElement);
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.FIREFOX)
+@SupportedBrowser(SupportedBrowser.SAFARI)
+@Unstable()
+@Native("SVGAnimateTransformElement")
+class AnimateTransformElement extends AnimationElement {
+  // To suppress missing implicit constructor warnings.
+  factory AnimateTransformElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory AnimateTransformElement() =>
+      _SvgElementFactoryProvider.createSvgElement_tag("animateTransform");
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  AnimateTransformElement.created() : super.created();
+
+  /// Checks if this type is supported on the current platform.
+  static bool get supported =>
+      SvgElement.isTagSupported('animateTransform') &&
+      (new SvgElement.tag('animateTransform') is AnimateTransformElement);
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGAnimatedAngle")
+class AnimatedAngle extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory AnimatedAngle._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final Angle animVal;
+
+  final Angle baseVal;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGAnimatedBoolean")
+class AnimatedBoolean extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory AnimatedBoolean._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final bool animVal;
+
+  bool baseVal;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGAnimatedEnumeration")
+class AnimatedEnumeration extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory AnimatedEnumeration._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final int animVal;
+
+  int baseVal;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGAnimatedInteger")
+class AnimatedInteger extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory AnimatedInteger._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final int animVal;
+
+  int baseVal;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGAnimatedLength")
+class AnimatedLength extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory AnimatedLength._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final Length animVal;
+
+  final Length baseVal;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGAnimatedLengthList")
+class AnimatedLengthList extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory AnimatedLengthList._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final LengthList animVal;
+
+  final LengthList baseVal;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGAnimatedNumber")
+class AnimatedNumber extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory AnimatedNumber._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final num animVal;
+
+  num baseVal;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGAnimatedNumberList")
+class AnimatedNumberList extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory AnimatedNumberList._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final NumberList animVal;
+
+  final NumberList baseVal;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGAnimatedPreserveAspectRatio")
+class AnimatedPreserveAspectRatio extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory AnimatedPreserveAspectRatio._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final PreserveAspectRatio animVal;
+
+  final PreserveAspectRatio baseVal;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGAnimatedRect")
+class AnimatedRect extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory AnimatedRect._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final Rect animVal;
+
+  final Rect baseVal;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGAnimatedString")
+class AnimatedString extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory AnimatedString._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final String animVal;
+
+  String baseVal;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGAnimatedTransformList")
+class AnimatedTransformList extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory AnimatedTransformList._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final TransformList animVal;
+
+  final TransformList baseVal;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGAnimationElement")
+class AnimationElement extends SvgElement implements Tests {
+  // To suppress missing implicit constructor warnings.
+  factory AnimationElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory AnimationElement() =>
+      _SvgElementFactoryProvider.createSvgElement_tag("animation");
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  AnimationElement.created() : super.created();
+
+  final SvgElement targetElement;
+
+  void beginElement() native;
+
+  void beginElementAt(num offset) native;
+
+  void endElement() native;
+
+  void endElementAt(num offset) native;
+
+  double getCurrentTime() native;
+
+  double getSimpleDuration() native;
+
+  double getStartTime() native;
+
+  // From SVGTests
+
+  final StringList requiredExtensions;
+
+  final StringList systemLanguage;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGCircleElement")
+class CircleElement extends GeometryElement {
+  // To suppress missing implicit constructor warnings.
+  factory CircleElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory CircleElement() =>
+      _SvgElementFactoryProvider.createSvgElement_tag("circle");
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  CircleElement.created() : super.created();
+
+  final AnimatedLength cx;
+
+  final AnimatedLength cy;
+
+  final AnimatedLength r;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGClipPathElement")
+class ClipPathElement extends GraphicsElement {
+  // To suppress missing implicit constructor warnings.
+  factory ClipPathElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory ClipPathElement() =>
+      _SvgElementFactoryProvider.createSvgElement_tag("clipPath");
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  ClipPathElement.created() : super.created();
+
+  final AnimatedEnumeration clipPathUnits;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGDefsElement")
+class DefsElement extends GraphicsElement {
+  // To suppress missing implicit constructor warnings.
+  factory DefsElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory DefsElement() =>
+      _SvgElementFactoryProvider.createSvgElement_tag("defs");
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  DefsElement.created() : super.created();
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGDescElement")
+class DescElement extends SvgElement {
+  // To suppress missing implicit constructor warnings.
+  factory DescElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory DescElement() =>
+      _SvgElementFactoryProvider.createSvgElement_tag("desc");
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  DescElement.created() : super.created();
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("SVGDiscardElement")
+class DiscardElement extends SvgElement {
+  // To suppress missing implicit constructor warnings.
+  factory DiscardElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  DiscardElement.created() : super.created();
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGEllipseElement")
+class EllipseElement extends GeometryElement {
+  // To suppress missing implicit constructor warnings.
+  factory EllipseElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory EllipseElement() =>
+      _SvgElementFactoryProvider.createSvgElement_tag("ellipse");
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  EllipseElement.created() : super.created();
+
+  final AnimatedLength cx;
+
+  final AnimatedLength cy;
+
+  final AnimatedLength rx;
+
+  final AnimatedLength ry;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.FIREFOX)
+@SupportedBrowser(SupportedBrowser.IE, '10')
+@SupportedBrowser(SupportedBrowser.SAFARI)
+@Unstable()
+@Native("SVGFEBlendElement")
+class FEBlendElement extends SvgElement
+    implements FilterPrimitiveStandardAttributes {
+  // To suppress missing implicit constructor warnings.
+  factory FEBlendElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory FEBlendElement() =>
+      _SvgElementFactoryProvider.createSvgElement_tag("feBlend");
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  FEBlendElement.created() : super.created();
+
+  /// Checks if this type is supported on the current platform.
+  static bool get supported =>
+      SvgElement.isTagSupported('feBlend') &&
+      (new SvgElement.tag('feBlend') is FEBlendElement);
+
+  static const int SVG_FEBLEND_MODE_DARKEN = 4;
+
+  static const int SVG_FEBLEND_MODE_LIGHTEN = 5;
+
+  static const int SVG_FEBLEND_MODE_MULTIPLY = 2;
+
+  static const int SVG_FEBLEND_MODE_NORMAL = 1;
+
+  static const int SVG_FEBLEND_MODE_SCREEN = 3;
+
+  static const int SVG_FEBLEND_MODE_UNKNOWN = 0;
+
+  final AnimatedString in1;
+
+  final AnimatedString in2;
+
+  final AnimatedEnumeration mode;
+
+  // From SVGFilterPrimitiveStandardAttributes
+
+  final AnimatedLength height;
+
+  final AnimatedString result;
+
+  final AnimatedLength width;
+
+  final AnimatedLength x;
+
+  final AnimatedLength y;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.FIREFOX)
+@SupportedBrowser(SupportedBrowser.IE, '10')
+@SupportedBrowser(SupportedBrowser.SAFARI)
+@Unstable()
+@Native("SVGFEColorMatrixElement")
+class FEColorMatrixElement extends SvgElement
+    implements FilterPrimitiveStandardAttributes {
+  // To suppress missing implicit constructor warnings.
+  factory FEColorMatrixElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory FEColorMatrixElement() =>
+      _SvgElementFactoryProvider.createSvgElement_tag("feColorMatrix");
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  FEColorMatrixElement.created() : super.created();
+
+  /// Checks if this type is supported on the current platform.
+  static bool get supported =>
+      SvgElement.isTagSupported('feColorMatrix') &&
+      (new SvgElement.tag('feColorMatrix') is FEColorMatrixElement);
+
+  static const int SVG_FECOLORMATRIX_TYPE_HUEROTATE = 3;
+
+  static const int SVG_FECOLORMATRIX_TYPE_LUMINANCETOALPHA = 4;
+
+  static const int SVG_FECOLORMATRIX_TYPE_MATRIX = 1;
+
+  static const int SVG_FECOLORMATRIX_TYPE_SATURATE = 2;
+
+  static const int SVG_FECOLORMATRIX_TYPE_UNKNOWN = 0;
+
+  final AnimatedString in1;
+
+  final AnimatedEnumeration type;
+
+  final AnimatedNumberList values;
+
+  // From SVGFilterPrimitiveStandardAttributes
+
+  final AnimatedLength height;
+
+  final AnimatedString result;
+
+  final AnimatedLength width;
+
+  final AnimatedLength x;
+
+  final AnimatedLength y;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.FIREFOX)
+@SupportedBrowser(SupportedBrowser.IE, '10')
+@SupportedBrowser(SupportedBrowser.SAFARI)
+@Unstable()
+@Native("SVGFEComponentTransferElement")
+class FEComponentTransferElement extends SvgElement
+    implements FilterPrimitiveStandardAttributes {
+  // To suppress missing implicit constructor warnings.
+  factory FEComponentTransferElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory FEComponentTransferElement() =>
+      _SvgElementFactoryProvider.createSvgElement_tag("feComponentTransfer");
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  FEComponentTransferElement.created() : super.created();
+
+  /// Checks if this type is supported on the current platform.
+  static bool get supported =>
+      SvgElement.isTagSupported('feComponentTransfer') &&
+      (new SvgElement.tag('feComponentTransfer') is FEComponentTransferElement);
+
+  final AnimatedString in1;
+
+  // From SVGFilterPrimitiveStandardAttributes
+
+  final AnimatedLength height;
+
+  final AnimatedString result;
+
+  final AnimatedLength width;
+
+  final AnimatedLength x;
+
+  final AnimatedLength y;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGFECompositeElement")
+class FECompositeElement extends SvgElement
+    implements FilterPrimitiveStandardAttributes {
+  // To suppress missing implicit constructor warnings.
+  factory FECompositeElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  FECompositeElement.created() : super.created();
+
+  static const int SVG_FECOMPOSITE_OPERATOR_ARITHMETIC = 6;
+
+  static const int SVG_FECOMPOSITE_OPERATOR_ATOP = 4;
+
+  static const int SVG_FECOMPOSITE_OPERATOR_IN = 2;
+
+  static const int SVG_FECOMPOSITE_OPERATOR_OUT = 3;
+
+  static const int SVG_FECOMPOSITE_OPERATOR_OVER = 1;
+
+  static const int SVG_FECOMPOSITE_OPERATOR_UNKNOWN = 0;
+
+  static const int SVG_FECOMPOSITE_OPERATOR_XOR = 5;
+
+  final AnimatedString in1;
+
+  final AnimatedString in2;
+
+  final AnimatedNumber k1;
+
+  final AnimatedNumber k2;
+
+  final AnimatedNumber k3;
+
+  final AnimatedNumber k4;
+
+  final AnimatedEnumeration operator;
+
+  // From SVGFilterPrimitiveStandardAttributes
+
+  final AnimatedLength height;
+
+  final AnimatedString result;
+
+  final AnimatedLength width;
+
+  final AnimatedLength x;
+
+  final AnimatedLength y;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.FIREFOX)
+@SupportedBrowser(SupportedBrowser.IE, '10')
+@SupportedBrowser(SupportedBrowser.SAFARI)
+@Unstable()
+@Native("SVGFEConvolveMatrixElement")
+class FEConvolveMatrixElement extends SvgElement
+    implements FilterPrimitiveStandardAttributes {
+  // To suppress missing implicit constructor warnings.
+  factory FEConvolveMatrixElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory FEConvolveMatrixElement() =>
+      _SvgElementFactoryProvider.createSvgElement_tag("feConvolveMatrix");
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  FEConvolveMatrixElement.created() : super.created();
+
+  /// Checks if this type is supported on the current platform.
+  static bool get supported =>
+      SvgElement.isTagSupported('feConvolveMatrix') &&
+      (new SvgElement.tag('feConvolveMatrix') is FEConvolveMatrixElement);
+
+  static const int SVG_EDGEMODE_DUPLICATE = 1;
+
+  static const int SVG_EDGEMODE_NONE = 3;
+
+  static const int SVG_EDGEMODE_UNKNOWN = 0;
+
+  static const int SVG_EDGEMODE_WRAP = 2;
+
+  final AnimatedNumber bias;
+
+  final AnimatedNumber divisor;
+
+  final AnimatedEnumeration edgeMode;
+
+  final AnimatedString in1;
+
+  final AnimatedNumberList kernelMatrix;
+
+  final AnimatedNumber kernelUnitLengthX;
+
+  final AnimatedNumber kernelUnitLengthY;
+
+  final AnimatedInteger orderX;
+
+  final AnimatedInteger orderY;
+
+  final AnimatedBoolean preserveAlpha;
+
+  final AnimatedInteger targetX;
+
+  final AnimatedInteger targetY;
+
+  // From SVGFilterPrimitiveStandardAttributes
+
+  final AnimatedLength height;
+
+  final AnimatedString result;
+
+  final AnimatedLength width;
+
+  final AnimatedLength x;
+
+  final AnimatedLength y;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.FIREFOX)
+@SupportedBrowser(SupportedBrowser.IE, '10')
+@SupportedBrowser(SupportedBrowser.SAFARI)
+@Unstable()
+@Native("SVGFEDiffuseLightingElement")
+class FEDiffuseLightingElement extends SvgElement
+    implements FilterPrimitiveStandardAttributes {
+  // To suppress missing implicit constructor warnings.
+  factory FEDiffuseLightingElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory FEDiffuseLightingElement() =>
+      _SvgElementFactoryProvider.createSvgElement_tag("feDiffuseLighting");
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  FEDiffuseLightingElement.created() : super.created();
+
+  /// Checks if this type is supported on the current platform.
+  static bool get supported =>
+      SvgElement.isTagSupported('feDiffuseLighting') &&
+      (new SvgElement.tag('feDiffuseLighting') is FEDiffuseLightingElement);
+
+  final AnimatedNumber diffuseConstant;
+
+  final AnimatedString in1;
+
+  final AnimatedNumber kernelUnitLengthX;
+
+  final AnimatedNumber kernelUnitLengthY;
+
+  final AnimatedNumber surfaceScale;
+
+  // From SVGFilterPrimitiveStandardAttributes
+
+  final AnimatedLength height;
+
+  final AnimatedString result;
+
+  final AnimatedLength width;
+
+  final AnimatedLength x;
+
+  final AnimatedLength y;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.FIREFOX)
+@SupportedBrowser(SupportedBrowser.IE, '10')
+@SupportedBrowser(SupportedBrowser.SAFARI)
+@Unstable()
+@Native("SVGFEDisplacementMapElement")
+class FEDisplacementMapElement extends SvgElement
+    implements FilterPrimitiveStandardAttributes {
+  // To suppress missing implicit constructor warnings.
+  factory FEDisplacementMapElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory FEDisplacementMapElement() =>
+      _SvgElementFactoryProvider.createSvgElement_tag("feDisplacementMap");
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  FEDisplacementMapElement.created() : super.created();
+
+  /// Checks if this type is supported on the current platform.
+  static bool get supported =>
+      SvgElement.isTagSupported('feDisplacementMap') &&
+      (new SvgElement.tag('feDisplacementMap') is FEDisplacementMapElement);
+
+  static const int SVG_CHANNEL_A = 4;
+
+  static const int SVG_CHANNEL_B = 3;
+
+  static const int SVG_CHANNEL_G = 2;
+
+  static const int SVG_CHANNEL_R = 1;
+
+  static const int SVG_CHANNEL_UNKNOWN = 0;
+
+  final AnimatedString in1;
+
+  final AnimatedString in2;
+
+  final AnimatedNumber scale;
+
+  final AnimatedEnumeration xChannelSelector;
+
+  final AnimatedEnumeration yChannelSelector;
+
+  // From SVGFilterPrimitiveStandardAttributes
+
+  final AnimatedLength height;
+
+  final AnimatedString result;
+
+  final AnimatedLength width;
+
+  final AnimatedLength x;
+
+  final AnimatedLength y;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.FIREFOX)
+@SupportedBrowser(SupportedBrowser.IE, '10')
+@SupportedBrowser(SupportedBrowser.SAFARI)
+@Unstable()
+@Native("SVGFEDistantLightElement")
+class FEDistantLightElement extends SvgElement {
+  // To suppress missing implicit constructor warnings.
+  factory FEDistantLightElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory FEDistantLightElement() =>
+      _SvgElementFactoryProvider.createSvgElement_tag("feDistantLight");
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  FEDistantLightElement.created() : super.created();
+
+  /// Checks if this type is supported on the current platform.
+  static bool get supported =>
+      SvgElement.isTagSupported('feDistantLight') &&
+      (new SvgElement.tag('feDistantLight') is FEDistantLightElement);
+
+  final AnimatedNumber azimuth;
+
+  final AnimatedNumber elevation;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.FIREFOX)
+@SupportedBrowser(SupportedBrowser.IE, '10')
+@SupportedBrowser(SupportedBrowser.SAFARI)
+@Unstable()
+@Native("SVGFEFloodElement")
+class FEFloodElement extends SvgElement
+    implements FilterPrimitiveStandardAttributes {
+  // To suppress missing implicit constructor warnings.
+  factory FEFloodElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory FEFloodElement() =>
+      _SvgElementFactoryProvider.createSvgElement_tag("feFlood");
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  FEFloodElement.created() : super.created();
+
+  /// Checks if this type is supported on the current platform.
+  static bool get supported =>
+      SvgElement.isTagSupported('feFlood') &&
+      (new SvgElement.tag('feFlood') is FEFloodElement);
+
+  // From SVGFilterPrimitiveStandardAttributes
+
+  final AnimatedLength height;
+
+  final AnimatedString result;
+
+  final AnimatedLength width;
+
+  final AnimatedLength x;
+
+  final AnimatedLength y;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.FIREFOX)
+@SupportedBrowser(SupportedBrowser.IE, '10')
+@SupportedBrowser(SupportedBrowser.SAFARI)
+@Unstable()
+@Native("SVGFEFuncAElement")
+class FEFuncAElement extends _SVGComponentTransferFunctionElement {
+  // To suppress missing implicit constructor warnings.
+  factory FEFuncAElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory FEFuncAElement() =>
+      _SvgElementFactoryProvider.createSvgElement_tag("feFuncA");
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  FEFuncAElement.created() : super.created();
+
+  /// Checks if this type is supported on the current platform.
+  static bool get supported =>
+      SvgElement.isTagSupported('feFuncA') &&
+      (new SvgElement.tag('feFuncA') is FEFuncAElement);
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.FIREFOX)
+@SupportedBrowser(SupportedBrowser.IE, '10')
+@SupportedBrowser(SupportedBrowser.SAFARI)
+@Unstable()
+@Native("SVGFEFuncBElement")
+class FEFuncBElement extends _SVGComponentTransferFunctionElement {
+  // To suppress missing implicit constructor warnings.
+  factory FEFuncBElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory FEFuncBElement() =>
+      _SvgElementFactoryProvider.createSvgElement_tag("feFuncB");
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  FEFuncBElement.created() : super.created();
+
+  /// Checks if this type is supported on the current platform.
+  static bool get supported =>
+      SvgElement.isTagSupported('feFuncB') &&
+      (new SvgElement.tag('feFuncB') is FEFuncBElement);
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.FIREFOX)
+@SupportedBrowser(SupportedBrowser.IE, '10')
+@SupportedBrowser(SupportedBrowser.SAFARI)
+@Unstable()
+@Native("SVGFEFuncGElement")
+class FEFuncGElement extends _SVGComponentTransferFunctionElement {
+  // To suppress missing implicit constructor warnings.
+  factory FEFuncGElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory FEFuncGElement() =>
+      _SvgElementFactoryProvider.createSvgElement_tag("feFuncG");
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  FEFuncGElement.created() : super.created();
+
+  /// Checks if this type is supported on the current platform.
+  static bool get supported =>
+      SvgElement.isTagSupported('feFuncG') &&
+      (new SvgElement.tag('feFuncG') is FEFuncGElement);
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.FIREFOX)
+@SupportedBrowser(SupportedBrowser.IE, '10')
+@SupportedBrowser(SupportedBrowser.SAFARI)
+@Unstable()
+@Native("SVGFEFuncRElement")
+class FEFuncRElement extends _SVGComponentTransferFunctionElement {
+  // To suppress missing implicit constructor warnings.
+  factory FEFuncRElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory FEFuncRElement() =>
+      _SvgElementFactoryProvider.createSvgElement_tag("feFuncR");
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  FEFuncRElement.created() : super.created();
+
+  /// Checks if this type is supported on the current platform.
+  static bool get supported =>
+      SvgElement.isTagSupported('feFuncR') &&
+      (new SvgElement.tag('feFuncR') is FEFuncRElement);
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.FIREFOX)
+@SupportedBrowser(SupportedBrowser.IE, '10')
+@SupportedBrowser(SupportedBrowser.SAFARI)
+@Unstable()
+@Native("SVGFEGaussianBlurElement")
+class FEGaussianBlurElement extends SvgElement
+    implements FilterPrimitiveStandardAttributes {
+  // To suppress missing implicit constructor warnings.
+  factory FEGaussianBlurElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory FEGaussianBlurElement() =>
+      _SvgElementFactoryProvider.createSvgElement_tag("feGaussianBlur");
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  FEGaussianBlurElement.created() : super.created();
+
+  /// Checks if this type is supported on the current platform.
+  static bool get supported =>
+      SvgElement.isTagSupported('feGaussianBlur') &&
+      (new SvgElement.tag('feGaussianBlur') is FEGaussianBlurElement);
+
+  final AnimatedString in1;
+
+  final AnimatedNumber stdDeviationX;
+
+  final AnimatedNumber stdDeviationY;
+
+  void setStdDeviation(num stdDeviationX, num stdDeviationY) native;
+
+  // From SVGFilterPrimitiveStandardAttributes
+
+  final AnimatedLength height;
+
+  final AnimatedString result;
+
+  final AnimatedLength width;
+
+  final AnimatedLength x;
+
+  final AnimatedLength y;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.FIREFOX)
+@SupportedBrowser(SupportedBrowser.IE, '10')
+@SupportedBrowser(SupportedBrowser.SAFARI)
+@Unstable()
+@Native("SVGFEImageElement")
+class FEImageElement extends SvgElement
+    implements FilterPrimitiveStandardAttributes, UriReference {
+  // To suppress missing implicit constructor warnings.
+  factory FEImageElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory FEImageElement() =>
+      _SvgElementFactoryProvider.createSvgElement_tag("feImage");
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  FEImageElement.created() : super.created();
+
+  /// Checks if this type is supported on the current platform.
+  static bool get supported =>
+      SvgElement.isTagSupported('feImage') &&
+      (new SvgElement.tag('feImage') is FEImageElement);
+
+  final AnimatedPreserveAspectRatio preserveAspectRatio;
+
+  // From SVGFilterPrimitiveStandardAttributes
+
+  final AnimatedLength height;
+
+  final AnimatedString result;
+
+  final AnimatedLength width;
+
+  final AnimatedLength x;
+
+  final AnimatedLength y;
+
+  // From SVGURIReference
+
+  final AnimatedString href;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.FIREFOX)
+@SupportedBrowser(SupportedBrowser.IE, '10')
+@SupportedBrowser(SupportedBrowser.SAFARI)
+@Unstable()
+@Native("SVGFEMergeElement")
+class FEMergeElement extends SvgElement
+    implements FilterPrimitiveStandardAttributes {
+  // To suppress missing implicit constructor warnings.
+  factory FEMergeElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory FEMergeElement() =>
+      _SvgElementFactoryProvider.createSvgElement_tag("feMerge");
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  FEMergeElement.created() : super.created();
+
+  /// Checks if this type is supported on the current platform.
+  static bool get supported =>
+      SvgElement.isTagSupported('feMerge') &&
+      (new SvgElement.tag('feMerge') is FEMergeElement);
+
+  // From SVGFilterPrimitiveStandardAttributes
+
+  final AnimatedLength height;
+
+  final AnimatedString result;
+
+  final AnimatedLength width;
+
+  final AnimatedLength x;
+
+  final AnimatedLength y;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.FIREFOX)
+@SupportedBrowser(SupportedBrowser.IE, '10')
+@SupportedBrowser(SupportedBrowser.SAFARI)
+@Unstable()
+@Native("SVGFEMergeNodeElement")
+class FEMergeNodeElement extends SvgElement {
+  // To suppress missing implicit constructor warnings.
+  factory FEMergeNodeElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory FEMergeNodeElement() =>
+      _SvgElementFactoryProvider.createSvgElement_tag("feMergeNode");
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  FEMergeNodeElement.created() : super.created();
+
+  /// Checks if this type is supported on the current platform.
+  static bool get supported =>
+      SvgElement.isTagSupported('feMergeNode') &&
+      (new SvgElement.tag('feMergeNode') is FEMergeNodeElement);
+
+  final AnimatedString in1;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.FIREFOX)
+@SupportedBrowser(SupportedBrowser.IE, '10')
+@SupportedBrowser(SupportedBrowser.SAFARI)
+@Unstable()
+@Native("SVGFEMorphologyElement")
+class FEMorphologyElement extends SvgElement
+    implements FilterPrimitiveStandardAttributes {
+  // To suppress missing implicit constructor warnings.
+  factory FEMorphologyElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  FEMorphologyElement.created() : super.created();
+
+  static const int SVG_MORPHOLOGY_OPERATOR_DILATE = 2;
+
+  static const int SVG_MORPHOLOGY_OPERATOR_ERODE = 1;
+
+  static const int SVG_MORPHOLOGY_OPERATOR_UNKNOWN = 0;
+
+  final AnimatedString in1;
+
+  final AnimatedEnumeration operator;
+
+  final AnimatedNumber radiusX;
+
+  final AnimatedNumber radiusY;
+
+  // From SVGFilterPrimitiveStandardAttributes
+
+  final AnimatedLength height;
+
+  final AnimatedString result;
+
+  final AnimatedLength width;
+
+  final AnimatedLength x;
+
+  final AnimatedLength y;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.FIREFOX)
+@SupportedBrowser(SupportedBrowser.IE, '10')
+@SupportedBrowser(SupportedBrowser.SAFARI)
+@Unstable()
+@Native("SVGFEOffsetElement")
+class FEOffsetElement extends SvgElement
+    implements FilterPrimitiveStandardAttributes {
+  // To suppress missing implicit constructor warnings.
+  factory FEOffsetElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory FEOffsetElement() =>
+      _SvgElementFactoryProvider.createSvgElement_tag("feOffset");
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  FEOffsetElement.created() : super.created();
+
+  /// Checks if this type is supported on the current platform.
+  static bool get supported =>
+      SvgElement.isTagSupported('feOffset') &&
+      (new SvgElement.tag('feOffset') is FEOffsetElement);
+
+  final AnimatedNumber dx;
+
+  final AnimatedNumber dy;
+
+  final AnimatedString in1;
+
+  // From SVGFilterPrimitiveStandardAttributes
+
+  final AnimatedLength height;
+
+  final AnimatedString result;
+
+  final AnimatedLength width;
+
+  final AnimatedLength x;
+
+  final AnimatedLength y;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.FIREFOX)
+@SupportedBrowser(SupportedBrowser.IE, '10')
+@SupportedBrowser(SupportedBrowser.SAFARI)
+@Unstable()
+@Native("SVGFEPointLightElement")
+class FEPointLightElement extends SvgElement {
+  // To suppress missing implicit constructor warnings.
+  factory FEPointLightElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory FEPointLightElement() =>
+      _SvgElementFactoryProvider.createSvgElement_tag("fePointLight");
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  FEPointLightElement.created() : super.created();
+
+  /// Checks if this type is supported on the current platform.
+  static bool get supported =>
+      SvgElement.isTagSupported('fePointLight') &&
+      (new SvgElement.tag('fePointLight') is FEPointLightElement);
+
+  final AnimatedNumber x;
+
+  final AnimatedNumber y;
+
+  final AnimatedNumber z;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.FIREFOX)
+@SupportedBrowser(SupportedBrowser.IE, '10')
+@SupportedBrowser(SupportedBrowser.SAFARI)
+@Unstable()
+@Native("SVGFESpecularLightingElement")
+class FESpecularLightingElement extends SvgElement
+    implements FilterPrimitiveStandardAttributes {
+  // To suppress missing implicit constructor warnings.
+  factory FESpecularLightingElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory FESpecularLightingElement() =>
+      _SvgElementFactoryProvider.createSvgElement_tag("feSpecularLighting");
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  FESpecularLightingElement.created() : super.created();
+
+  /// Checks if this type is supported on the current platform.
+  static bool get supported =>
+      SvgElement.isTagSupported('feSpecularLighting') &&
+      (new SvgElement.tag('feSpecularLighting') is FESpecularLightingElement);
+
+  final AnimatedString in1;
+
+  final AnimatedNumber kernelUnitLengthX;
+
+  final AnimatedNumber kernelUnitLengthY;
+
+  final AnimatedNumber specularConstant;
+
+  final AnimatedNumber specularExponent;
+
+  final AnimatedNumber surfaceScale;
+
+  // From SVGFilterPrimitiveStandardAttributes
+
+  final AnimatedLength height;
+
+  final AnimatedString result;
+
+  final AnimatedLength width;
+
+  final AnimatedLength x;
+
+  final AnimatedLength y;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.FIREFOX)
+@SupportedBrowser(SupportedBrowser.IE, '10')
+@SupportedBrowser(SupportedBrowser.SAFARI)
+@Unstable()
+@Native("SVGFESpotLightElement")
+class FESpotLightElement extends SvgElement {
+  // To suppress missing implicit constructor warnings.
+  factory FESpotLightElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory FESpotLightElement() =>
+      _SvgElementFactoryProvider.createSvgElement_tag("feSpotLight");
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  FESpotLightElement.created() : super.created();
+
+  /// Checks if this type is supported on the current platform.
+  static bool get supported =>
+      SvgElement.isTagSupported('feSpotLight') &&
+      (new SvgElement.tag('feSpotLight') is FESpotLightElement);
+
+  final AnimatedNumber limitingConeAngle;
+
+  final AnimatedNumber pointsAtX;
+
+  final AnimatedNumber pointsAtY;
+
+  final AnimatedNumber pointsAtZ;
+
+  final AnimatedNumber specularExponent;
+
+  final AnimatedNumber x;
+
+  final AnimatedNumber y;
+
+  final AnimatedNumber z;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.FIREFOX)
+@SupportedBrowser(SupportedBrowser.IE, '10')
+@SupportedBrowser(SupportedBrowser.SAFARI)
+@Unstable()
+@Native("SVGFETileElement")
+class FETileElement extends SvgElement
+    implements FilterPrimitiveStandardAttributes {
+  // To suppress missing implicit constructor warnings.
+  factory FETileElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory FETileElement() =>
+      _SvgElementFactoryProvider.createSvgElement_tag("feTile");
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  FETileElement.created() : super.created();
+
+  /// Checks if this type is supported on the current platform.
+  static bool get supported =>
+      SvgElement.isTagSupported('feTile') &&
+      (new SvgElement.tag('feTile') is FETileElement);
+
+  final AnimatedString in1;
+
+  // From SVGFilterPrimitiveStandardAttributes
+
+  final AnimatedLength height;
+
+  final AnimatedString result;
+
+  final AnimatedLength width;
+
+  final AnimatedLength x;
+
+  final AnimatedLength y;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.FIREFOX)
+@SupportedBrowser(SupportedBrowser.IE, '10')
+@SupportedBrowser(SupportedBrowser.SAFARI)
+@Unstable()
+@Native("SVGFETurbulenceElement")
+class FETurbulenceElement extends SvgElement
+    implements FilterPrimitiveStandardAttributes {
+  // To suppress missing implicit constructor warnings.
+  factory FETurbulenceElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory FETurbulenceElement() =>
+      _SvgElementFactoryProvider.createSvgElement_tag("feTurbulence");
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  FETurbulenceElement.created() : super.created();
+
+  /// Checks if this type is supported on the current platform.
+  static bool get supported =>
+      SvgElement.isTagSupported('feTurbulence') &&
+      (new SvgElement.tag('feTurbulence') is FETurbulenceElement);
+
+  static const int SVG_STITCHTYPE_NOSTITCH = 2;
+
+  static const int SVG_STITCHTYPE_STITCH = 1;
+
+  static const int SVG_STITCHTYPE_UNKNOWN = 0;
+
+  static const int SVG_TURBULENCE_TYPE_FRACTALNOISE = 1;
+
+  static const int SVG_TURBULENCE_TYPE_TURBULENCE = 2;
+
+  static const int SVG_TURBULENCE_TYPE_UNKNOWN = 0;
+
+  final AnimatedNumber baseFrequencyX;
+
+  final AnimatedNumber baseFrequencyY;
+
+  final AnimatedInteger numOctaves;
+
+  final AnimatedNumber seed;
+
+  final AnimatedEnumeration stitchTiles;
+
+  final AnimatedEnumeration type;
+
+  // From SVGFilterPrimitiveStandardAttributes
+
+  final AnimatedLength height;
+
+  final AnimatedString result;
+
+  final AnimatedLength width;
+
+  final AnimatedLength x;
+
+  final AnimatedLength y;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.FIREFOX)
+@SupportedBrowser(SupportedBrowser.IE, '10')
+@SupportedBrowser(SupportedBrowser.SAFARI)
+@Unstable()
+@Native("SVGFilterElement")
+class FilterElement extends SvgElement implements UriReference {
+  // To suppress missing implicit constructor warnings.
+  factory FilterElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory FilterElement() =>
+      _SvgElementFactoryProvider.createSvgElement_tag("filter");
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  FilterElement.created() : super.created();
+
+  /// Checks if this type is supported on the current platform.
+  static bool get supported =>
+      SvgElement.isTagSupported('filter') &&
+      (new SvgElement.tag('filter') is FilterElement);
+
+  final AnimatedEnumeration filterUnits;
+
+  final AnimatedLength height;
+
+  final AnimatedEnumeration primitiveUnits;
+
+  final AnimatedLength width;
+
+  final AnimatedLength x;
+
+  final AnimatedLength y;
+
+  // From SVGURIReference
+
+  final AnimatedString href;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+abstract class FilterPrimitiveStandardAttributes extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory FilterPrimitiveStandardAttributes._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final AnimatedLength height;
+
+  final AnimatedString result;
+
+  final AnimatedLength width;
+
+  final AnimatedLength x;
+
+  final AnimatedLength y;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+abstract class FitToViewBox extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory FitToViewBox._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final AnimatedPreserveAspectRatio preserveAspectRatio;
+
+  final AnimatedRect viewBox;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.FIREFOX)
+@SupportedBrowser(SupportedBrowser.SAFARI)
+@Unstable()
+@Native("SVGForeignObjectElement")
+class ForeignObjectElement extends GraphicsElement {
+  // To suppress missing implicit constructor warnings.
+  factory ForeignObjectElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory ForeignObjectElement() =>
+      _SvgElementFactoryProvider.createSvgElement_tag("foreignObject");
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  ForeignObjectElement.created() : super.created();
+
+  /// Checks if this type is supported on the current platform.
+  static bool get supported =>
+      SvgElement.isTagSupported('foreignObject') &&
+      (new SvgElement.tag('foreignObject') is ForeignObjectElement);
+
+  final AnimatedLength height;
+
+  final AnimatedLength width;
+
+  final AnimatedLength x;
+
+  final AnimatedLength y;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGGElement")
+class GElement extends GraphicsElement {
+  // To suppress missing implicit constructor warnings.
+  factory GElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory GElement() => _SvgElementFactoryProvider.createSvgElement_tag("g");
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  GElement.created() : super.created();
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("SVGGeometryElement")
+class GeometryElement extends GraphicsElement {
+  // To suppress missing implicit constructor warnings.
+  factory GeometryElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  GeometryElement.created() : super.created();
+
+  final AnimatedNumber pathLength;
+
+  Point getPointAtLength(num distance) native;
+
+  double getTotalLength() native;
+
+  bool isPointInFill(Point point) native;
+
+  bool isPointInStroke(Point point) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("SVGGraphicsElement")
+class GraphicsElement extends SvgElement implements Tests {
+  // To suppress missing implicit constructor warnings.
+  factory GraphicsElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  GraphicsElement.created() : super.created();
+
+  final SvgElement farthestViewportElement;
+
+  final SvgElement nearestViewportElement;
+
+  final AnimatedTransformList transform;
+
+  Rect getBBox() native;
+
+  @JSName('getCTM')
+  Matrix getCtm() native;
+
+  @JSName('getScreenCTM')
+  Matrix getScreenCtm() native;
+
+  // From SVGTests
+
+  final StringList requiredExtensions;
+
+  final StringList systemLanguage;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGImageElement")
+class ImageElement extends GraphicsElement implements UriReference {
+  // To suppress missing implicit constructor warnings.
+  factory ImageElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory ImageElement() =>
+      _SvgElementFactoryProvider.createSvgElement_tag("image");
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  ImageElement.created() : super.created();
+
+  String async;
+
+  final AnimatedLength height;
+
+  final AnimatedPreserveAspectRatio preserveAspectRatio;
+
+  final AnimatedLength width;
+
+  final AnimatedLength x;
+
+  final AnimatedLength y;
+
+  Future decode() => promiseToFuture(JS("", "#.decode()", this));
+
+  // From SVGURIReference
+
+  final AnimatedString href;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGLength")
+class Length extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory Length._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  static const int SVG_LENGTHTYPE_CM = 6;
+
+  static const int SVG_LENGTHTYPE_EMS = 3;
+
+  static const int SVG_LENGTHTYPE_EXS = 4;
+
+  static const int SVG_LENGTHTYPE_IN = 8;
+
+  static const int SVG_LENGTHTYPE_MM = 7;
+
+  static const int SVG_LENGTHTYPE_NUMBER = 1;
+
+  static const int SVG_LENGTHTYPE_PC = 10;
+
+  static const int SVG_LENGTHTYPE_PERCENTAGE = 2;
+
+  static const int SVG_LENGTHTYPE_PT = 9;
+
+  static const int SVG_LENGTHTYPE_PX = 5;
+
+  static const int SVG_LENGTHTYPE_UNKNOWN = 0;
+
+  final int unitType;
+
+  num value;
+
+  String valueAsString;
+
+  num valueInSpecifiedUnits;
+
+  void convertToSpecifiedUnits(int unitType) native;
+
+  void newValueSpecifiedUnits(int unitType, num valueInSpecifiedUnits) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGLengthList")
+class LengthList extends Interceptor
+    with ListMixin<Length>, ImmutableListMixin<Length>
+    implements List<Length> {
+  // To suppress missing implicit constructor warnings.
+  factory LengthList._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  int get length => JS("int", "#.length", this);
+
+  final int numberOfItems;
+
+  Length operator [](int index) {
+    if (JS("bool", "# >>> 0 !== # || # >= #", index, index, index, length))
+      throw new RangeError.index(index, this);
+    return this.getItem(index);
+  }
+
+  void operator []=(int index, Length value) {
+    throw new UnsupportedError("Cannot assign element of immutable List.");
+  }
+  // -- start List<Length> mixins.
+  // Length is the element type.
+
+  set length(int value) {
+    throw new UnsupportedError("Cannot resize immutable List.");
+  }
+
+  Length get first {
+    if (this.length > 0) {
+      return JS('Length', '#[0]', this);
+    }
+    throw new StateError("No elements");
+  }
+
+  Length get last {
+    int len = this.length;
+    if (len > 0) {
+      return JS('Length', '#[#]', this, len - 1);
+    }
+    throw new StateError("No elements");
+  }
+
+  Length get single {
+    int len = this.length;
+    if (len == 1) {
+      return JS('Length', '#[0]', this);
+    }
+    if (len == 0) throw new StateError("No elements");
+    throw new StateError("More than one element");
+  }
+
+  Length elementAt(int index) => this[index];
+  // -- end List<Length> mixins.
+
+  void __setter__(int index, Length newItem) native;
+
+  Length appendItem(Length newItem) native;
+
+  void clear() native;
+
+  Length getItem(int index) native;
+
+  Length initialize(Length newItem) native;
+
+  Length insertItemBefore(Length newItem, int index) native;
+
+  Length removeItem(int index) native;
+
+  Length replaceItem(Length newItem, int index) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGLineElement")
+class LineElement extends GeometryElement {
+  // To suppress missing implicit constructor warnings.
+  factory LineElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory LineElement() =>
+      _SvgElementFactoryProvider.createSvgElement_tag("line");
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  LineElement.created() : super.created();
+
+  final AnimatedLength x1;
+
+  final AnimatedLength x2;
+
+  final AnimatedLength y1;
+
+  final AnimatedLength y2;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGLinearGradientElement")
+class LinearGradientElement extends _GradientElement {
+  // To suppress missing implicit constructor warnings.
+  factory LinearGradientElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory LinearGradientElement() =>
+      _SvgElementFactoryProvider.createSvgElement_tag("linearGradient");
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  LinearGradientElement.created() : super.created();
+
+  final AnimatedLength x1;
+
+  final AnimatedLength x2;
+
+  final AnimatedLength y1;
+
+  final AnimatedLength y2;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGMarkerElement")
+class MarkerElement extends SvgElement implements FitToViewBox {
+  // To suppress missing implicit constructor warnings.
+  factory MarkerElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory MarkerElement() =>
+      _SvgElementFactoryProvider.createSvgElement_tag("marker");
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  MarkerElement.created() : super.created();
+
+  static const int SVG_MARKERUNITS_STROKEWIDTH = 2;
+
+  static const int SVG_MARKERUNITS_UNKNOWN = 0;
+
+  static const int SVG_MARKERUNITS_USERSPACEONUSE = 1;
+
+  static const int SVG_MARKER_ORIENT_ANGLE = 2;
+
+  static const int SVG_MARKER_ORIENT_AUTO = 1;
+
+  static const int SVG_MARKER_ORIENT_UNKNOWN = 0;
+
+  final AnimatedLength markerHeight;
+
+  final AnimatedEnumeration markerUnits;
+
+  final AnimatedLength markerWidth;
+
+  final AnimatedAngle orientAngle;
+
+  final AnimatedEnumeration orientType;
+
+  final AnimatedLength refX;
+
+  final AnimatedLength refY;
+
+  void setOrientToAngle(Angle angle) native;
+
+  void setOrientToAuto() native;
+
+  // From SVGFitToViewBox
+
+  final AnimatedPreserveAspectRatio preserveAspectRatio;
+
+  final AnimatedRect viewBox;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGMaskElement")
+class MaskElement extends SvgElement implements Tests {
+  // To suppress missing implicit constructor warnings.
+  factory MaskElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory MaskElement() =>
+      _SvgElementFactoryProvider.createSvgElement_tag("mask");
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  MaskElement.created() : super.created();
+
+  final AnimatedLength height;
+
+  final AnimatedEnumeration maskContentUnits;
+
+  final AnimatedEnumeration maskUnits;
+
+  final AnimatedLength width;
+
+  final AnimatedLength x;
+
+  final AnimatedLength y;
+
+  // From SVGTests
+
+  final StringList requiredExtensions;
+
+  final StringList systemLanguage;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGMatrix")
+class Matrix extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory Matrix._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  num a;
+
+  num b;
+
+  num c;
+
+  num d;
+
+  num e;
+
+  num f;
+
+  Matrix flipX() native;
+
+  Matrix flipY() native;
+
+  Matrix inverse() native;
+
+  Matrix multiply(Matrix secondMatrix) native;
+
+  Matrix rotate(num angle) native;
+
+  Matrix rotateFromVector(num x, num y) native;
+
+  Matrix scale(num scaleFactor) native;
+
+  Matrix scaleNonUniform(num scaleFactorX, num scaleFactorY) native;
+
+  Matrix skewX(num angle) native;
+
+  Matrix skewY(num angle) native;
+
+  Matrix translate(num x, num y) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGMetadataElement")
+class MetadataElement extends SvgElement {
+  // To suppress missing implicit constructor warnings.
+  factory MetadataElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  MetadataElement.created() : super.created();
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGNumber")
+class Number extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory Number._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  num value;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGNumberList")
+class NumberList extends Interceptor
+    with ListMixin<Number>, ImmutableListMixin<Number>
+    implements List<Number> {
+  // To suppress missing implicit constructor warnings.
+  factory NumberList._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  int get length => JS("int", "#.length", this);
+
+  final int numberOfItems;
+
+  Number operator [](int index) {
+    if (JS("bool", "# >>> 0 !== # || # >= #", index, index, index, length))
+      throw new RangeError.index(index, this);
+    return this.getItem(index);
+  }
+
+  void operator []=(int index, Number value) {
+    throw new UnsupportedError("Cannot assign element of immutable List.");
+  }
+  // -- start List<Number> mixins.
+  // Number is the element type.
+
+  set length(int value) {
+    throw new UnsupportedError("Cannot resize immutable List.");
+  }
+
+  Number get first {
+    if (this.length > 0) {
+      return JS('Number', '#[0]', this);
+    }
+    throw new StateError("No elements");
+  }
+
+  Number get last {
+    int len = this.length;
+    if (len > 0) {
+      return JS('Number', '#[#]', this, len - 1);
+    }
+    throw new StateError("No elements");
+  }
+
+  Number get single {
+    int len = this.length;
+    if (len == 1) {
+      return JS('Number', '#[0]', this);
+    }
+    if (len == 0) throw new StateError("No elements");
+    throw new StateError("More than one element");
+  }
+
+  Number elementAt(int index) => this[index];
+  // -- end List<Number> mixins.
+
+  void __setter__(int index, Number newItem) native;
+
+  Number appendItem(Number newItem) native;
+
+  void clear() native;
+
+  Number getItem(int index) native;
+
+  Number initialize(Number newItem) native;
+
+  Number insertItemBefore(Number newItem, int index) native;
+
+  Number removeItem(int index) native;
+
+  Number replaceItem(Number newItem, int index) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGPathElement")
+class PathElement extends GeometryElement {
+  // To suppress missing implicit constructor warnings.
+  factory PathElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory PathElement() =>
+      _SvgElementFactoryProvider.createSvgElement_tag("path");
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  PathElement.created() : super.created();
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGPatternElement")
+class PatternElement extends SvgElement
+    implements FitToViewBox, UriReference, Tests {
+  // To suppress missing implicit constructor warnings.
+  factory PatternElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory PatternElement() =>
+      _SvgElementFactoryProvider.createSvgElement_tag("pattern");
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  PatternElement.created() : super.created();
+
+  final AnimatedLength height;
+
+  final AnimatedEnumeration patternContentUnits;
+
+  final AnimatedTransformList patternTransform;
+
+  final AnimatedEnumeration patternUnits;
+
+  final AnimatedLength width;
+
+  final AnimatedLength x;
+
+  final AnimatedLength y;
+
+  // From SVGFitToViewBox
+
+  final AnimatedPreserveAspectRatio preserveAspectRatio;
+
+  final AnimatedRect viewBox;
+
+  // From SVGTests
+
+  final StringList requiredExtensions;
+
+  final StringList systemLanguage;
+
+  // From SVGURIReference
+
+  final AnimatedString href;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGPoint")
+class Point extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory Point._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  num x;
+
+  num y;
+
+  Point matrixTransform(Matrix matrix) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGPointList")
+class PointList extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory PointList._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final int length;
+
+  final int numberOfItems;
+
+  void __setter__(int index, Point newItem) native;
+
+  Point appendItem(Point newItem) native;
+
+  void clear() native;
+
+  Point getItem(int index) native;
+
+  Point initialize(Point newItem) native;
+
+  Point insertItemBefore(Point newItem, int index) native;
+
+  Point removeItem(int index) native;
+
+  Point replaceItem(Point newItem, int index) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGPolygonElement")
+class PolygonElement extends GeometryElement {
+  // To suppress missing implicit constructor warnings.
+  factory PolygonElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory PolygonElement() =>
+      _SvgElementFactoryProvider.createSvgElement_tag("polygon");
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  PolygonElement.created() : super.created();
+
+  final PointList animatedPoints;
+
+  final PointList points;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGPolylineElement")
+class PolylineElement extends GeometryElement {
+  // To suppress missing implicit constructor warnings.
+  factory PolylineElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory PolylineElement() =>
+      _SvgElementFactoryProvider.createSvgElement_tag("polyline");
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  PolylineElement.created() : super.created();
+
+  final PointList animatedPoints;
+
+  final PointList points;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGPreserveAspectRatio")
+class PreserveAspectRatio extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory PreserveAspectRatio._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  static const int SVG_MEETORSLICE_MEET = 1;
+
+  static const int SVG_MEETORSLICE_SLICE = 2;
+
+  static const int SVG_MEETORSLICE_UNKNOWN = 0;
+
+  static const int SVG_PRESERVEASPECTRATIO_NONE = 1;
+
+  static const int SVG_PRESERVEASPECTRATIO_UNKNOWN = 0;
+
+  static const int SVG_PRESERVEASPECTRATIO_XMAXYMAX = 10;
+
+  static const int SVG_PRESERVEASPECTRATIO_XMAXYMID = 7;
+
+  static const int SVG_PRESERVEASPECTRATIO_XMAXYMIN = 4;
+
+  static const int SVG_PRESERVEASPECTRATIO_XMIDYMAX = 9;
+
+  static const int SVG_PRESERVEASPECTRATIO_XMIDYMID = 6;
+
+  static const int SVG_PRESERVEASPECTRATIO_XMIDYMIN = 3;
+
+  static const int SVG_PRESERVEASPECTRATIO_XMINYMAX = 8;
+
+  static const int SVG_PRESERVEASPECTRATIO_XMINYMID = 5;
+
+  static const int SVG_PRESERVEASPECTRATIO_XMINYMIN = 2;
+
+  int align;
+
+  int meetOrSlice;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGRadialGradientElement")
+class RadialGradientElement extends _GradientElement {
+  // To suppress missing implicit constructor warnings.
+  factory RadialGradientElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory RadialGradientElement() =>
+      _SvgElementFactoryProvider.createSvgElement_tag("radialGradient");
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  RadialGradientElement.created() : super.created();
+
+  final AnimatedLength cx;
+
+  final AnimatedLength cy;
+
+  final AnimatedLength fr;
+
+  final AnimatedLength fx;
+
+  final AnimatedLength fy;
+
+  final AnimatedLength r;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGRect")
+class Rect extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory Rect._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  num height;
+
+  num width;
+
+  num x;
+
+  num y;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGRectElement")
+class RectElement extends GeometryElement {
+  // To suppress missing implicit constructor warnings.
+  factory RectElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory RectElement() =>
+      _SvgElementFactoryProvider.createSvgElement_tag("rect");
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  RectElement.created() : super.created();
+
+  final AnimatedLength height;
+
+  final AnimatedLength rx;
+
+  final AnimatedLength ry;
+
+  final AnimatedLength width;
+
+  final AnimatedLength x;
+
+  final AnimatedLength y;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGScriptElement")
+class ScriptElement extends SvgElement implements UriReference {
+  // To suppress missing implicit constructor warnings.
+  factory ScriptElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory ScriptElement() =>
+      _SvgElementFactoryProvider.createSvgElement_tag("script");
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  ScriptElement.created() : super.created();
+
+  String type;
+
+  // From SVGURIReference
+
+  final AnimatedString href;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.FIREFOX)
+@SupportedBrowser(SupportedBrowser.SAFARI)
+@Unstable()
+@Native("SVGSetElement")
+class SetElement extends AnimationElement {
+  // To suppress missing implicit constructor warnings.
+  factory SetElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory SetElement() =>
+      _SvgElementFactoryProvider.createSvgElement_tag("set");
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  SetElement.created() : super.created();
+
+  /// Checks if this type is supported on the current platform.
+  static bool get supported =>
+      SvgElement.isTagSupported('set') &&
+      (new SvgElement.tag('set') is SetElement);
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGStopElement")
+class StopElement extends SvgElement {
+  // To suppress missing implicit constructor warnings.
+  factory StopElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory StopElement() =>
+      _SvgElementFactoryProvider.createSvgElement_tag("stop");
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  StopElement.created() : super.created();
+
+  @JSName('offset')
+  final AnimatedNumber gradientOffset;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGStringList")
+class StringList extends Interceptor
+    with ListMixin<String>, ImmutableListMixin<String>
+    implements List<String> {
+  // To suppress missing implicit constructor warnings.
+  factory StringList._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  int get length => JS("int", "#.length", this);
+
+  final int numberOfItems;
+
+  String operator [](int index) {
+    if (JS("bool", "# >>> 0 !== # || # >= #", index, index, index, length))
+      throw new RangeError.index(index, this);
+    return this.getItem(index);
+  }
+
+  void operator []=(int index, String value) {
+    throw new UnsupportedError("Cannot assign element of immutable List.");
+  }
+  // -- start List<String> mixins.
+  // String is the element type.
+
+  set length(int value) {
+    throw new UnsupportedError("Cannot resize immutable List.");
+  }
+
+  String get first {
+    if (this.length > 0) {
+      return JS('String', '#[0]', this);
+    }
+    throw new StateError("No elements");
+  }
+
+  String get last {
+    int len = this.length;
+    if (len > 0) {
+      return JS('String', '#[#]', this, len - 1);
+    }
+    throw new StateError("No elements");
+  }
+
+  String get single {
+    int len = this.length;
+    if (len == 1) {
+      return JS('String', '#[0]', this);
+    }
+    if (len == 0) throw new StateError("No elements");
+    throw new StateError("More than one element");
+  }
+
+  String elementAt(int index) => this[index];
+  // -- end List<String> mixins.
+
+  void __setter__(int index, String newItem) native;
+
+  String appendItem(String newItem) native;
+
+  void clear() native;
+
+  String getItem(int index) native;
+
+  String initialize(String newItem) native;
+
+  String insertItemBefore(String item, int index) native;
+
+  String removeItem(int index) native;
+
+  String replaceItem(String newItem, int index) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("SVGStyleElement")
+class StyleElement extends SvgElement {
+  // To suppress missing implicit constructor warnings.
+  factory StyleElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory StyleElement() =>
+      _SvgElementFactoryProvider.createSvgElement_tag("style");
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  StyleElement.created() : super.created();
+
+  bool disabled;
+
+  String media;
+
+  final StyleSheet sheet;
+
+  // Use implementation from Element.
+  // final String title;
+
+  String type;
+}
+// Copyright (c) 2011, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+class AttributeClassSet extends CssClassSetImpl {
+  final Element _element;
+
+  AttributeClassSet(this._element);
+
+  Set<String> readClasses() {
+    var classname = _element.attributes['class'];
+    if (classname is AnimatedString) {
+      classname = (classname as AnimatedString).baseVal;
+    }
+
+    Set<String> s = new LinkedHashSet<String>();
+    if (classname == null) {
+      return s;
+    }
+    for (String name in classname.split(' ')) {
+      String trimmed = name.trim();
+      if (!trimmed.isEmpty) {
+        s.add(trimmed);
+      }
+    }
+    return s;
+  }
+
+  void writeClasses(Set s) {
+    _element.setAttribute('class', s.join(' '));
+  }
+}
+
+@Unstable()
+@Native("SVGElement")
+class SvgElement extends Element implements GlobalEventHandlers, NoncedElement {
+  static final _START_TAG_REGEXP = new RegExp('<(\\w+)');
+
+  factory SvgElement.tag(String tag) =>
+      document.createElementNS("http://www.w3.org/2000/svg", tag);
+  factory SvgElement.svg(String svg,
+      {NodeValidator validator, NodeTreeSanitizer treeSanitizer}) {
+    if (validator == null && treeSanitizer == null) {
+      validator = new NodeValidatorBuilder.common()..allowSvg();
+    }
+
+    final match = _START_TAG_REGEXP.firstMatch(svg);
+    var parentElement;
+    if (match != null && match.group(1).toLowerCase() == 'svg') {
+      parentElement = document.body;
+    } else {
+      parentElement = new SvgSvgElement();
+    }
+    var fragment = parentElement.createFragment(svg,
+        validator: validator, treeSanitizer: treeSanitizer);
+    return fragment.nodes.where((e) => e is SvgElement).single;
+  }
+
+  CssClassSet get classes => new AttributeClassSet(this);
+
+  List<Element> get children => new FilteredElementList(this);
+
+  set children(List<Element> value) {
+    final children = this.children;
+    children.clear();
+    children.addAll(value);
+  }
+
+  String get outerHtml {
+    final container = new DivElement();
+    final SvgElement cloned = this.clone(true);
+    container.children.add(cloned);
+    return container.innerHtml;
+  }
+
+  String get innerHtml {
+    final container = new DivElement();
+    final SvgElement cloned = this.clone(true);
+    container.children.addAll(cloned.children);
+    return container.innerHtml;
+  }
+
+  set innerHtml(String value) {
+    this.setInnerHtml(value);
+  }
+
+  DocumentFragment createFragment(String svg,
+      {NodeValidator validator, NodeTreeSanitizer treeSanitizer}) {
+    if (treeSanitizer == null) {
+      if (validator == null) {
+        validator = new NodeValidatorBuilder.common()..allowSvg();
+      }
+      treeSanitizer = new NodeTreeSanitizer(validator);
+    }
+
+    // We create a fragment which will parse in the HTML parser
+    var html = '<svg version="1.1">$svg</svg>';
+    var fragment =
+        document.body.createFragment(html, treeSanitizer: treeSanitizer);
+
+    var svgFragment = new DocumentFragment();
+    // The root is the <svg/> element, need to pull out the contents.
+    var root = fragment.nodes.single;
+    while (root.firstChild != null) {
+      svgFragment.append(root.firstChild);
+    }
+    return svgFragment;
+  }
+
+  // Unsupported methods inherited from Element.
+
+  void insertAdjacentText(String where, String text) {
+    throw new UnsupportedError("Cannot invoke insertAdjacentText on SVG.");
+  }
+
+  void insertAdjacentHtml(String where, String text,
+      {NodeValidator validator, NodeTreeSanitizer treeSanitizer}) {
+    throw new UnsupportedError("Cannot invoke insertAdjacentHtml on SVG.");
+  }
+
+  Element insertAdjacentElement(String where, Element element) {
+    throw new UnsupportedError("Cannot invoke insertAdjacentElement on SVG.");
+  }
+
+  HtmlCollection get _children {
+    throw new UnsupportedError("Cannot get _children on SVG.");
+  }
+
+  bool get isContentEditable => false;
+  void click() {
+    throw new UnsupportedError("Cannot invoke click SVG.");
+  }
+
+  /**
+   * Checks to see if the SVG element type is supported by the current platform.
+   *
+   * The tag should be a valid SVG element tag name.
+   */
+  static bool isTagSupported(String tag) {
+    var e = new SvgElement.tag(tag);
+    return e is SvgElement && !(e is UnknownElement);
+  }
+
+  // To suppress missing implicit constructor warnings.
+  factory SvgElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  static const EventStreamProvider<Event> abortEvent =
+      const EventStreamProvider<Event>('abort');
+
+  static const EventStreamProvider<Event> blurEvent =
+      const EventStreamProvider<Event>('blur');
+
+  static const EventStreamProvider<Event> canPlayEvent =
+      const EventStreamProvider<Event>('canplay');
+
+  static const EventStreamProvider<Event> canPlayThroughEvent =
+      const EventStreamProvider<Event>('canplaythrough');
+
+  static const EventStreamProvider<Event> changeEvent =
+      const EventStreamProvider<Event>('change');
+
+  static const EventStreamProvider<MouseEvent> clickEvent =
+      const EventStreamProvider<MouseEvent>('click');
+
+  static const EventStreamProvider<MouseEvent> contextMenuEvent =
+      const EventStreamProvider<MouseEvent>('contextmenu');
+
+  @DomName('SVGElement.dblclickEvent')
+  static const EventStreamProvider<Event> doubleClickEvent =
+      const EventStreamProvider<Event>('dblclick');
+
+  static const EventStreamProvider<MouseEvent> dragEvent =
+      const EventStreamProvider<MouseEvent>('drag');
+
+  static const EventStreamProvider<MouseEvent> dragEndEvent =
+      const EventStreamProvider<MouseEvent>('dragend');
+
+  static const EventStreamProvider<MouseEvent> dragEnterEvent =
+      const EventStreamProvider<MouseEvent>('dragenter');
+
+  static const EventStreamProvider<MouseEvent> dragLeaveEvent =
+      const EventStreamProvider<MouseEvent>('dragleave');
+
+  static const EventStreamProvider<MouseEvent> dragOverEvent =
+      const EventStreamProvider<MouseEvent>('dragover');
+
+  static const EventStreamProvider<MouseEvent> dragStartEvent =
+      const EventStreamProvider<MouseEvent>('dragstart');
+
+  static const EventStreamProvider<MouseEvent> dropEvent =
+      const EventStreamProvider<MouseEvent>('drop');
+
+  static const EventStreamProvider<Event> durationChangeEvent =
+      const EventStreamProvider<Event>('durationchange');
+
+  static const EventStreamProvider<Event> emptiedEvent =
+      const EventStreamProvider<Event>('emptied');
+
+  static const EventStreamProvider<Event> endedEvent =
+      const EventStreamProvider<Event>('ended');
+
+  static const EventStreamProvider<Event> errorEvent =
+      const EventStreamProvider<Event>('error');
+
+  static const EventStreamProvider<Event> focusEvent =
+      const EventStreamProvider<Event>('focus');
+
+  static const EventStreamProvider<Event> inputEvent =
+      const EventStreamProvider<Event>('input');
+
+  static const EventStreamProvider<Event> invalidEvent =
+      const EventStreamProvider<Event>('invalid');
+
+  static const EventStreamProvider<KeyboardEvent> keyDownEvent =
+      const EventStreamProvider<KeyboardEvent>('keydown');
+
+  static const EventStreamProvider<KeyboardEvent> keyPressEvent =
+      const EventStreamProvider<KeyboardEvent>('keypress');
+
+  static const EventStreamProvider<KeyboardEvent> keyUpEvent =
+      const EventStreamProvider<KeyboardEvent>('keyup');
+
+  static const EventStreamProvider<Event> loadEvent =
+      const EventStreamProvider<Event>('load');
+
+  static const EventStreamProvider<Event> loadedDataEvent =
+      const EventStreamProvider<Event>('loadeddata');
+
+  static const EventStreamProvider<Event> loadedMetadataEvent =
+      const EventStreamProvider<Event>('loadedmetadata');
+
+  static const EventStreamProvider<MouseEvent> mouseDownEvent =
+      const EventStreamProvider<MouseEvent>('mousedown');
+
+  static const EventStreamProvider<MouseEvent> mouseEnterEvent =
+      const EventStreamProvider<MouseEvent>('mouseenter');
+
+  static const EventStreamProvider<MouseEvent> mouseLeaveEvent =
+      const EventStreamProvider<MouseEvent>('mouseleave');
+
+  static const EventStreamProvider<MouseEvent> mouseMoveEvent =
+      const EventStreamProvider<MouseEvent>('mousemove');
+
+  static const EventStreamProvider<MouseEvent> mouseOutEvent =
+      const EventStreamProvider<MouseEvent>('mouseout');
+
+  static const EventStreamProvider<MouseEvent> mouseOverEvent =
+      const EventStreamProvider<MouseEvent>('mouseover');
+
+  static const EventStreamProvider<MouseEvent> mouseUpEvent =
+      const EventStreamProvider<MouseEvent>('mouseup');
+
+  static const EventStreamProvider<WheelEvent> mouseWheelEvent =
+      const EventStreamProvider<WheelEvent>('mousewheel');
+
+  static const EventStreamProvider<Event> pauseEvent =
+      const EventStreamProvider<Event>('pause');
+
+  static const EventStreamProvider<Event> playEvent =
+      const EventStreamProvider<Event>('play');
+
+  static const EventStreamProvider<Event> playingEvent =
+      const EventStreamProvider<Event>('playing');
+
+  static const EventStreamProvider<Event> rateChangeEvent =
+      const EventStreamProvider<Event>('ratechange');
+
+  static const EventStreamProvider<Event> resetEvent =
+      const EventStreamProvider<Event>('reset');
+
+  static const EventStreamProvider<Event> resizeEvent =
+      const EventStreamProvider<Event>('resize');
+
+  static const EventStreamProvider<Event> scrollEvent =
+      const EventStreamProvider<Event>('scroll');
+
+  static const EventStreamProvider<Event> seekedEvent =
+      const EventStreamProvider<Event>('seeked');
+
+  static const EventStreamProvider<Event> seekingEvent =
+      const EventStreamProvider<Event>('seeking');
+
+  static const EventStreamProvider<Event> selectEvent =
+      const EventStreamProvider<Event>('select');
+
+  static const EventStreamProvider<Event> stalledEvent =
+      const EventStreamProvider<Event>('stalled');
+
+  static const EventStreamProvider<Event> submitEvent =
+      const EventStreamProvider<Event>('submit');
+
+  static const EventStreamProvider<Event> suspendEvent =
+      const EventStreamProvider<Event>('suspend');
+
+  static const EventStreamProvider<Event> timeUpdateEvent =
+      const EventStreamProvider<Event>('timeupdate');
+
+  static const EventStreamProvider<TouchEvent> touchCancelEvent =
+      const EventStreamProvider<TouchEvent>('touchcancel');
+
+  static const EventStreamProvider<TouchEvent> touchEndEvent =
+      const EventStreamProvider<TouchEvent>('touchend');
+
+  static const EventStreamProvider<TouchEvent> touchMoveEvent =
+      const EventStreamProvider<TouchEvent>('touchmove');
+
+  static const EventStreamProvider<TouchEvent> touchStartEvent =
+      const EventStreamProvider<TouchEvent>('touchstart');
+
+  static const EventStreamProvider<Event> volumeChangeEvent =
+      const EventStreamProvider<Event>('volumechange');
+
+  static const EventStreamProvider<Event> waitingEvent =
+      const EventStreamProvider<Event>('waiting');
+
+  static const EventStreamProvider<WheelEvent> wheelEvent =
+      const EventStreamProvider<WheelEvent>('wheel');
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  SvgElement.created() : super.created();
+
+  // Shadowing definition.
+  AnimatedString get _svgClassName => JS("AnimatedString", "#.className", this);
+
+  @JSName('ownerSVGElement')
+  final SvgSvgElement ownerSvgElement;
+
+  // Use implementation from Element.
+  // final CssStyleDeclaration style;
+
+  // Use implementation from Element.
+  // final int tabIndex;
+
+  final SvgElement viewportElement;
+
+  void blur() native;
+
+  void focus() native;
+
+  // From NoncedElement
+
+  String nonce;
+
+  ElementStream<Event> get onAbort => abortEvent.forElement(this);
+
+  ElementStream<Event> get onBlur => blurEvent.forElement(this);
+
+  ElementStream<Event> get onCanPlay => canPlayEvent.forElement(this);
+
+  ElementStream<Event> get onCanPlayThrough =>
+      canPlayThroughEvent.forElement(this);
+
+  ElementStream<Event> get onChange => changeEvent.forElement(this);
+
+  ElementStream<MouseEvent> get onClick => clickEvent.forElement(this);
+
+  ElementStream<MouseEvent> get onContextMenu =>
+      contextMenuEvent.forElement(this);
+
+  @DomName('SVGElement.ondblclick')
+  ElementStream<Event> get onDoubleClick => doubleClickEvent.forElement(this);
+
+  ElementStream<MouseEvent> get onDrag => dragEvent.forElement(this);
+
+  ElementStream<MouseEvent> get onDragEnd => dragEndEvent.forElement(this);
+
+  ElementStream<MouseEvent> get onDragEnter => dragEnterEvent.forElement(this);
+
+  ElementStream<MouseEvent> get onDragLeave => dragLeaveEvent.forElement(this);
+
+  ElementStream<MouseEvent> get onDragOver => dragOverEvent.forElement(this);
+
+  ElementStream<MouseEvent> get onDragStart => dragStartEvent.forElement(this);
+
+  ElementStream<MouseEvent> get onDrop => dropEvent.forElement(this);
+
+  ElementStream<Event> get onDurationChange =>
+      durationChangeEvent.forElement(this);
+
+  ElementStream<Event> get onEmptied => emptiedEvent.forElement(this);
+
+  ElementStream<Event> get onEnded => endedEvent.forElement(this);
+
+  ElementStream<Event> get onError => errorEvent.forElement(this);
+
+  ElementStream<Event> get onFocus => focusEvent.forElement(this);
+
+  ElementStream<Event> get onInput => inputEvent.forElement(this);
+
+  ElementStream<Event> get onInvalid => invalidEvent.forElement(this);
+
+  ElementStream<KeyboardEvent> get onKeyDown => keyDownEvent.forElement(this);
+
+  ElementStream<KeyboardEvent> get onKeyPress => keyPressEvent.forElement(this);
+
+  ElementStream<KeyboardEvent> get onKeyUp => keyUpEvent.forElement(this);
+
+  ElementStream<Event> get onLoad => loadEvent.forElement(this);
+
+  ElementStream<Event> get onLoadedData => loadedDataEvent.forElement(this);
+
+  ElementStream<Event> get onLoadedMetadata =>
+      loadedMetadataEvent.forElement(this);
+
+  ElementStream<MouseEvent> get onMouseDown => mouseDownEvent.forElement(this);
+
+  ElementStream<MouseEvent> get onMouseEnter =>
+      mouseEnterEvent.forElement(this);
+
+  ElementStream<MouseEvent> get onMouseLeave =>
+      mouseLeaveEvent.forElement(this);
+
+  ElementStream<MouseEvent> get onMouseMove => mouseMoveEvent.forElement(this);
+
+  ElementStream<MouseEvent> get onMouseOut => mouseOutEvent.forElement(this);
+
+  ElementStream<MouseEvent> get onMouseOver => mouseOverEvent.forElement(this);
+
+  ElementStream<MouseEvent> get onMouseUp => mouseUpEvent.forElement(this);
+
+  ElementStream<WheelEvent> get onMouseWheel =>
+      mouseWheelEvent.forElement(this);
+
+  ElementStream<Event> get onPause => pauseEvent.forElement(this);
+
+  ElementStream<Event> get onPlay => playEvent.forElement(this);
+
+  ElementStream<Event> get onPlaying => playingEvent.forElement(this);
+
+  ElementStream<Event> get onRateChange => rateChangeEvent.forElement(this);
+
+  ElementStream<Event> get onReset => resetEvent.forElement(this);
+
+  ElementStream<Event> get onResize => resizeEvent.forElement(this);
+
+  ElementStream<Event> get onScroll => scrollEvent.forElement(this);
+
+  ElementStream<Event> get onSeeked => seekedEvent.forElement(this);
+
+  ElementStream<Event> get onSeeking => seekingEvent.forElement(this);
+
+  ElementStream<Event> get onSelect => selectEvent.forElement(this);
+
+  ElementStream<Event> get onStalled => stalledEvent.forElement(this);
+
+  ElementStream<Event> get onSubmit => submitEvent.forElement(this);
+
+  ElementStream<Event> get onSuspend => suspendEvent.forElement(this);
+
+  ElementStream<Event> get onTimeUpdate => timeUpdateEvent.forElement(this);
+
+  ElementStream<TouchEvent> get onTouchCancel =>
+      touchCancelEvent.forElement(this);
+
+  ElementStream<TouchEvent> get onTouchEnd => touchEndEvent.forElement(this);
+
+  ElementStream<TouchEvent> get onTouchMove => touchMoveEvent.forElement(this);
+
+  ElementStream<TouchEvent> get onTouchStart =>
+      touchStartEvent.forElement(this);
+
+  ElementStream<Event> get onVolumeChange => volumeChangeEvent.forElement(this);
+
+  ElementStream<Event> get onWaiting => waitingEvent.forElement(this);
+
+  ElementStream<WheelEvent> get onWheel => wheelEvent.forElement(this);
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGSVGElement")
+class SvgSvgElement extends GraphicsElement
+    implements FitToViewBox, ZoomAndPan {
+  factory SvgSvgElement() {
+    final el = new SvgElement.tag("svg");
+    // The SVG spec requires the version attribute to match the spec version
+    el.attributes['version'] = "1.1";
+    return el;
+  }
+
+  // To suppress missing implicit constructor warnings.
+  factory SvgSvgElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  SvgSvgElement.created() : super.created();
+
+  num currentScale;
+
+  final Point currentTranslate;
+
+  final AnimatedLength height;
+
+  final AnimatedLength width;
+
+  final AnimatedLength x;
+
+  final AnimatedLength y;
+
+  bool animationsPaused() native;
+
+  bool checkEnclosure(SvgElement element, Rect rect) native;
+
+  bool checkIntersection(SvgElement element, Rect rect) native;
+
+  @JSName('createSVGAngle')
+  Angle createSvgAngle() native;
+
+  @JSName('createSVGLength')
+  Length createSvgLength() native;
+
+  @JSName('createSVGMatrix')
+  Matrix createSvgMatrix() native;
+
+  @JSName('createSVGNumber')
+  Number createSvgNumber() native;
+
+  @JSName('createSVGPoint')
+  Point createSvgPoint() native;
+
+  @JSName('createSVGRect')
+  Rect createSvgRect() native;
+
+  @JSName('createSVGTransform')
+  Transform createSvgTransform() native;
+
+  @JSName('createSVGTransformFromMatrix')
+  Transform createSvgTransformFromMatrix(Matrix matrix) native;
+
+  void deselectAll() native;
+
+  void forceRedraw() native;
+
+  double getCurrentTime() native;
+
+  Element getElementById(String elementId) native;
+
+  @Returns('NodeList|Null')
+  @Creates('NodeList')
+  List<Node> getEnclosureList(Rect rect, SvgElement referenceElement) native;
+
+  @Returns('NodeList|Null')
+  @Creates('NodeList')
+  List<Node> getIntersectionList(Rect rect, SvgElement referenceElement) native;
+
+  void pauseAnimations() native;
+
+  void setCurrentTime(num seconds) native;
+
+  int suspendRedraw(int maxWaitMilliseconds) native;
+
+  void unpauseAnimations() native;
+
+  void unsuspendRedraw(int suspendHandleId) native;
+
+  void unsuspendRedrawAll() native;
+
+  // From SVGFitToViewBox
+
+  final AnimatedPreserveAspectRatio preserveAspectRatio;
+
+  final AnimatedRect viewBox;
+
+  // From SVGZoomAndPan
+
+  int zoomAndPan;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGSwitchElement")
+class SwitchElement extends GraphicsElement {
+  // To suppress missing implicit constructor warnings.
+  factory SwitchElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory SwitchElement() =>
+      _SvgElementFactoryProvider.createSvgElement_tag("switch");
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  SwitchElement.created() : super.created();
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGSymbolElement")
+class SymbolElement extends SvgElement implements FitToViewBox {
+  // To suppress missing implicit constructor warnings.
+  factory SymbolElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory SymbolElement() =>
+      _SvgElementFactoryProvider.createSvgElement_tag("symbol");
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  SymbolElement.created() : super.created();
+
+  // From SVGFitToViewBox
+
+  final AnimatedPreserveAspectRatio preserveAspectRatio;
+
+  final AnimatedRect viewBox;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGTSpanElement")
+class TSpanElement extends TextPositioningElement {
+  // To suppress missing implicit constructor warnings.
+  factory TSpanElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory TSpanElement() =>
+      _SvgElementFactoryProvider.createSvgElement_tag("tspan");
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  TSpanElement.created() : super.created();
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+abstract class Tests extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory Tests._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final StringList requiredExtensions;
+
+  final StringList systemLanguage;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGTextContentElement")
+class TextContentElement extends GraphicsElement {
+  // To suppress missing implicit constructor warnings.
+  factory TextContentElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  TextContentElement.created() : super.created();
+
+  static const int LENGTHADJUST_SPACING = 1;
+
+  static const int LENGTHADJUST_SPACINGANDGLYPHS = 2;
+
+  static const int LENGTHADJUST_UNKNOWN = 0;
+
+  final AnimatedEnumeration lengthAdjust;
+
+  final AnimatedLength textLength;
+
+  int getCharNumAtPosition(Point point) native;
+
+  double getComputedTextLength() native;
+
+  Point getEndPositionOfChar(int charnum) native;
+
+  Rect getExtentOfChar(int charnum) native;
+
+  int getNumberOfChars() native;
+
+  double getRotationOfChar(int charnum) native;
+
+  Point getStartPositionOfChar(int charnum) native;
+
+  double getSubStringLength(int charnum, int nchars) native;
+
+  void selectSubString(int charnum, int nchars) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGTextElement")
+class TextElement extends TextPositioningElement {
+  // To suppress missing implicit constructor warnings.
+  factory TextElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory TextElement() =>
+      _SvgElementFactoryProvider.createSvgElement_tag("text");
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  TextElement.created() : super.created();
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGTextPathElement")
+class TextPathElement extends TextContentElement implements UriReference {
+  // To suppress missing implicit constructor warnings.
+  factory TextPathElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  TextPathElement.created() : super.created();
+
+  static const int TEXTPATH_METHODTYPE_ALIGN = 1;
+
+  static const int TEXTPATH_METHODTYPE_STRETCH = 2;
+
+  static const int TEXTPATH_METHODTYPE_UNKNOWN = 0;
+
+  static const int TEXTPATH_SPACINGTYPE_AUTO = 1;
+
+  static const int TEXTPATH_SPACINGTYPE_EXACT = 2;
+
+  static const int TEXTPATH_SPACINGTYPE_UNKNOWN = 0;
+
+  final AnimatedEnumeration method;
+
+  final AnimatedEnumeration spacing;
+
+  final AnimatedLength startOffset;
+
+  // From SVGURIReference
+
+  final AnimatedString href;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGTextPositioningElement")
+class TextPositioningElement extends TextContentElement {
+  // To suppress missing implicit constructor warnings.
+  factory TextPositioningElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  TextPositioningElement.created() : super.created();
+
+  final AnimatedLengthList dx;
+
+  final AnimatedLengthList dy;
+
+  final AnimatedNumberList rotate;
+
+  final AnimatedLengthList x;
+
+  final AnimatedLengthList y;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGTitleElement")
+class TitleElement extends SvgElement {
+  // To suppress missing implicit constructor warnings.
+  factory TitleElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory TitleElement() =>
+      _SvgElementFactoryProvider.createSvgElement_tag("title");
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  TitleElement.created() : super.created();
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGTransform")
+class Transform extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory Transform._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  static const int SVG_TRANSFORM_MATRIX = 1;
+
+  static const int SVG_TRANSFORM_ROTATE = 4;
+
+  static const int SVG_TRANSFORM_SCALE = 3;
+
+  static const int SVG_TRANSFORM_SKEWX = 5;
+
+  static const int SVG_TRANSFORM_SKEWY = 6;
+
+  static const int SVG_TRANSFORM_TRANSLATE = 2;
+
+  static const int SVG_TRANSFORM_UNKNOWN = 0;
+
+  final num angle;
+
+  final Matrix matrix;
+
+  final int type;
+
+  void setMatrix(Matrix matrix) native;
+
+  void setRotate(num angle, num cx, num cy) native;
+
+  void setScale(num sx, num sy) native;
+
+  void setSkewX(num angle) native;
+
+  void setSkewY(num angle) native;
+
+  void setTranslate(num tx, num ty) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGTransformList")
+class TransformList extends Interceptor
+    with ListMixin<Transform>, ImmutableListMixin<Transform>
+    implements List<Transform> {
+  // To suppress missing implicit constructor warnings.
+  factory TransformList._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  int get length => JS("int", "#.length", this);
+
+  final int numberOfItems;
+
+  Transform operator [](int index) {
+    if (JS("bool", "# >>> 0 !== # || # >= #", index, index, index, length))
+      throw new RangeError.index(index, this);
+    return this.getItem(index);
+  }
+
+  void operator []=(int index, Transform value) {
+    throw new UnsupportedError("Cannot assign element of immutable List.");
+  }
+  // -- start List<Transform> mixins.
+  // Transform is the element type.
+
+  set length(int value) {
+    throw new UnsupportedError("Cannot resize immutable List.");
+  }
+
+  Transform get first {
+    if (this.length > 0) {
+      return JS('Transform', '#[0]', this);
+    }
+    throw new StateError("No elements");
+  }
+
+  Transform get last {
+    int len = this.length;
+    if (len > 0) {
+      return JS('Transform', '#[#]', this, len - 1);
+    }
+    throw new StateError("No elements");
+  }
+
+  Transform get single {
+    int len = this.length;
+    if (len == 1) {
+      return JS('Transform', '#[0]', this);
+    }
+    if (len == 0) throw new StateError("No elements");
+    throw new StateError("More than one element");
+  }
+
+  Transform elementAt(int index) => this[index];
+  // -- end List<Transform> mixins.
+
+  void __setter__(int index, Transform newItem) native;
+
+  Transform appendItem(Transform newItem) native;
+
+  void clear() native;
+
+  Transform consolidate() native;
+
+  @JSName('createSVGTransformFromMatrix')
+  Transform createSvgTransformFromMatrix(Matrix matrix) native;
+
+  Transform getItem(int index) native;
+
+  Transform initialize(Transform newItem) native;
+
+  Transform insertItemBefore(Transform newItem, int index) native;
+
+  Transform removeItem(int index) native;
+
+  Transform replaceItem(Transform newItem, int index) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGUnitTypes")
+class UnitTypes extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory UnitTypes._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  static const int SVG_UNIT_TYPE_OBJECTBOUNDINGBOX = 2;
+
+  static const int SVG_UNIT_TYPE_UNKNOWN = 0;
+
+  static const int SVG_UNIT_TYPE_USERSPACEONUSE = 1;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+abstract class UriReference extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory UriReference._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final AnimatedString href;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGUseElement")
+class UseElement extends GraphicsElement implements UriReference {
+  // To suppress missing implicit constructor warnings.
+  factory UseElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory UseElement() =>
+      _SvgElementFactoryProvider.createSvgElement_tag("use");
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  UseElement.created() : super.created();
+
+  final AnimatedLength height;
+
+  final AnimatedLength width;
+
+  final AnimatedLength x;
+
+  final AnimatedLength y;
+
+  // From SVGURIReference
+
+  final AnimatedString href;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGViewElement")
+class ViewElement extends SvgElement implements FitToViewBox, ZoomAndPan {
+  // To suppress missing implicit constructor warnings.
+  factory ViewElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory ViewElement() =>
+      _SvgElementFactoryProvider.createSvgElement_tag("view");
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  ViewElement.created() : super.created();
+
+  // From SVGFitToViewBox
+
+  final AnimatedPreserveAspectRatio preserveAspectRatio;
+
+  final AnimatedRect viewBox;
+
+  // From SVGZoomAndPan
+
+  int zoomAndPan;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+abstract class ZoomAndPan extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory ZoomAndPan._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  static const int SVG_ZOOMANDPAN_DISABLE = 1;
+
+  static const int SVG_ZOOMANDPAN_MAGNIFY = 2;
+
+  static const int SVG_ZOOMANDPAN_UNKNOWN = 0;
+
+  int zoomAndPan;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGGradientElement")
+class _GradientElement extends SvgElement implements UriReference {
+  // To suppress missing implicit constructor warnings.
+  factory _GradientElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  _GradientElement.created() : super.created();
+
+  static const int SVG_SPREADMETHOD_PAD = 1;
+
+  static const int SVG_SPREADMETHOD_REFLECT = 2;
+
+  static const int SVG_SPREADMETHOD_REPEAT = 3;
+
+  static const int SVG_SPREADMETHOD_UNKNOWN = 0;
+
+  final AnimatedTransformList gradientTransform;
+
+  final AnimatedEnumeration gradientUnits;
+
+  final AnimatedEnumeration spreadMethod;
+
+  // From SVGURIReference
+
+  final AnimatedString href;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGComponentTransferFunctionElement")
+abstract class _SVGComponentTransferFunctionElement extends SvgElement {
+  // To suppress missing implicit constructor warnings.
+  factory _SVGComponentTransferFunctionElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  _SVGComponentTransferFunctionElement.created() : super.created();
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("SVGFEDropShadowElement")
+abstract class _SVGFEDropShadowElement extends SvgElement
+    implements FilterPrimitiveStandardAttributes {
+  // To suppress missing implicit constructor warnings.
+  factory _SVGFEDropShadowElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  _SVGFEDropShadowElement.created() : super.created();
+
+  // From SVGFilterPrimitiveStandardAttributes
+
+}
+
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("SVGMPathElement")
+abstract class _SVGMPathElement extends SvgElement implements UriReference {
+  // To suppress missing implicit constructor warnings.
+  factory _SVGMPathElement._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory _SVGMPathElement() =>
+      _SvgElementFactoryProvider.createSvgElement_tag("mpath");
+  /**
+   * Constructor instantiated by the DOM when a custom element has been created.
+   *
+   * This can only be called by subclasses from their created constructor.
+   */
+  _SVGMPathElement.created() : super.created();
+
+  // From SVGURIReference
+
+}
diff --git a/sdk_nnbd/lib/typed_data/typed_data.dart b/sdk_nnbd/lib/typed_data/typed_data.dart
new file mode 100644
index 0000000..89c9496
--- /dev/null
+++ b/sdk_nnbd/lib/typed_data/typed_data.dart
@@ -0,0 +1,2596 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// Lists that efficiently handle fixed sized data
+/// (for example, unsigned 8 byte integers) and SIMD numeric types.
+///
+/// To use this library in your code:
+///
+///     import 'dart:typed_data';
+///
+/// {@category Core}
+library dart.typed_data;
+
+import "dart:_internal" show UnmodifiableListBase;
+
+part "unmodifiable_typed_data.dart";
+
+/**
+ * A sequence of bytes underlying a typed data object.
+ *
+ * Used to process large quantities of binary or numerical data
+ * more efficiently using a typed view.
+ */
+abstract class ByteBuffer {
+  /**
+   * Returns the length of this byte buffer, in bytes.
+   */
+  int get lengthInBytes;
+
+  /**
+   * Creates a [Uint8List] _view_ of a region of this byte buffer.
+   *
+   * The view is backed by the bytes of this byte buffer.
+   * Any changes made to the `Uint8List` will also change the buffer,
+   * and vice versa.
+   *
+   * The viewed region start at [offsetInBytes] and contains [length] bytes.
+   * If [length] is omitted, the range extends to the end of the buffer.
+   *
+   * The start index and length must describe a valid range of the buffer:
+   *
+   * * `offsetInBytes` must not be negative,
+   * * `length` must not be negative, and
+   * * `offsetInBytes + length` must not be greater than [lengthInBytes].
+   */
+  Uint8List asUint8List([int offsetInBytes = 0, int length]);
+
+  /**
+   * Creates a [Int8List] _view_ of a region of this byte buffer.
+   *
+   * The view is backed by the bytes of this byte buffer.
+   * Any changes made to the `Int8List` will also change the buffer,
+   * and vice versa.
+   *
+   * The viewed region start at [offsetInBytes] and contains [length] bytes.
+   * If [length] is omitted, the range extends to the end of the buffer.
+   *
+   * The start index and length must describe a valid range of the buffer:
+   *
+   * * `offsetInBytes` must not be negative,
+   * * `length` must not be negative, and
+   * * `offsetInBytes + length` must not be greater than [lengthInBytes].
+   */
+  Int8List asInt8List([int offsetInBytes = 0, int length]);
+
+  /**
+   * Creates a [Uint8ClampedList] _view_ of a region of this byte buffer.
+   *
+   * The view is backed by the bytes of this byte buffer.
+   * Any changes made to the `Uint8ClampedList` will also change the buffer,
+   * and vice versa.
+   *
+   * The viewed region start at [offsetInBytes] and contains [length] bytes.
+   * If [length] is omitted, the range extends to the end of the buffer.
+   *
+   * The start index and length must describe a valid range of the buffer:
+   *
+   * * `offsetInBytes` must not be negative,
+   * * `length` must not be negative, and
+   * * `offsetInBytes + length` must not be greater than [lengthInBytes].
+   */
+  Uint8ClampedList asUint8ClampedList([int offsetInBytes = 0, int length]);
+
+  /**
+   * Creates a [Uint16List] _view_ of a region of this byte buffer.
+   *
+   * The view is backed by the bytes of this byte buffer.
+   * Any changes made to the `Uint16List` will also change the buffer,
+   * and vice versa.
+   *
+   * The viewed region start at [offsetInBytes], which must be 16-bit aligned,
+   * and contains [length] 16-bit integers.
+   * If [length] is omitted, the range extends as far towards the end of
+   * the buffer as possible -
+   * if [lengthInBytes] is not even, the last byte can't be part of the view.
+   *
+   * The start index and length must describe a valid 16-bit aligned range
+   * of the buffer:
+   *
+   * * `offsetInBytes` must not be negative,
+   * * `offsetInBytes` must be divisible by two,
+   * * `length` must not be negative, and
+   * * `offsetInBytes + length * 2` must not be greater than [lengthInBytes].
+   */
+  Uint16List asUint16List([int offsetInBytes = 0, int length]);
+
+  /**
+   * Creates a [Int16List] _view_ of a region of this byte buffer.
+   *
+   * The view is backed by the bytes of this byte buffer.
+   * Any changes made to the `Int16List` will also change the buffer,
+   * and vice versa.
+   *
+   * The viewed region start at [offsetInBytes], which must be 16-bit aligned,
+   * and contains [length] 16-bit integers.
+   * If [length] is omitted, the range extends as far towards the end of
+   * the buffer as possible -
+   * if [lengthInBytes] is not even, the last byte can't be part of the view.
+   *
+   * The start index and length must describe a valid 16-bit aligned range
+   * of the buffer:
+   *
+   * * `offsetInBytes` must not be negative,
+   * * `offsetInBytes` must be divisible by two,
+   * * `length` must not be negative, and
+   * * `offsetInBytes + length * 2` must not be greater than [lengthInBytes].
+   */
+  Int16List asInt16List([int offsetInBytes = 0, int length]);
+
+  /**
+   * Creates a [Uint32List] _view_ of a region of this byte buffer.
+   *
+   * The view is backed by the bytes of this byte buffer.
+   * Any changes made to the `Uint32List` will also change the buffer,
+   * and vice versa.
+   *
+   * The viewed region start at [offsetInBytes], which must be 32-bit aligned,
+   * and contains [length] 32-bit integers.
+   * If [length] is omitted, the range extends as far towards the end of
+   * the buffer as possible -
+   * if [lengthInBytes] is not divisible by four, the last bytes can't be part
+   * of the view.
+   *
+   * The start index and length must describe a valid 32-bit aligned range
+   * of the buffer:
+   *
+   * * `offsetInBytes` must not be negative,
+   * * `offsetInBytes` must be divisible by four,
+   * * `length` must not be negative, and
+   * * `offsetInBytes + length * 4` must not be greater than [lengthInBytes].
+   */
+  Uint32List asUint32List([int offsetInBytes = 0, int length]);
+
+  /**
+   * Creates a [Int32List] _view_ of a region of this byte buffer.
+   *
+   * The view is backed by the bytes of this byte buffer.
+   * Any changes made to the `Int32List` will also change the buffer,
+   * and vice versa.
+   *
+   * The viewed region start at [offsetInBytes], which must be 32-bit aligned,
+   * and contains [length] 32-bit integers.
+   * If [length] is omitted, the range extends as far towards the end of
+   * the buffer as possible -
+   * if [lengthInBytes] is not divisible by four, the last bytes can't be part
+   * of the view.
+   *
+   * The start index and length must describe a valid 32-bit aligned range
+   * of the buffer:
+   *
+   * * `offsetInBytes` must not be negative,
+   * * `offsetInBytes` must be divisible by four,
+   * * `length` must not be negative, and
+   * * `offsetInBytes + length * 4` must not be greater than [lengthInBytes].
+   */
+  Int32List asInt32List([int offsetInBytes = 0, int length]);
+
+  /**
+   * Creates a [Uint64List] _view_ of a region of this byte buffer.
+   *
+   * The view is backed by the bytes of this byte buffer.
+   * Any changes made to the `Uint64List` will also change the buffer,
+   * and vice versa.
+   *
+   * The viewed region start at [offsetInBytes], which must be 64-bit aligned,
+   * and contains [length] 64-bit integers.
+   * If [length] is omitted, the range extends as far towards the end of
+   * the buffer as possible -
+   * if [lengthInBytes] is not divisible by eight, the last bytes can't be part
+   * of the view.
+   *
+   * The start index and length must describe a valid 64-bit aligned range
+   * of the buffer:
+   *
+   * * `offsetInBytes` must not be negative,
+   * * `offsetInBytes` must be divisible by eight,
+   * * `length` must not be negative, and
+   * * `offsetInBytes + length * 8` must not be greater than [lengthInBytes].
+   */
+  Uint64List asUint64List([int offsetInBytes = 0, int length]);
+
+  /**
+   * Creates a [Int64List] _view_ of a region of this byte buffer.
+   *
+   * The view is backed by the bytes of this byte buffer.
+   * Any changes made to the `Int64List` will also change the buffer,
+   * and vice versa.
+   *
+   * The viewed region start at [offsetInBytes], which must be 64-bit aligned,
+   * and contains [length] 64-bit integers.
+   * If [length] is omitted, the range extends as far towards the end of
+   * the buffer as possible -
+   * if [lengthInBytes] is not divisible by eight, the last bytes can't be part
+   * of the view.
+   *
+   * The start index and length must describe a valid 64-bit aligned range
+   * of the buffer:
+   *
+   * * `offsetInBytes` must not be negative,
+   * * `offsetInBytes` must be divisible by eight,
+   * * `length` must not be negative, and
+   * * `offsetInBytes + length * 8` must not be greater than [lengthInBytes].
+   */
+  Int64List asInt64List([int offsetInBytes = 0, int length]);
+
+  /**
+   * Creates a [Int32x4List] _view_ of a region of this byte buffer.
+   *
+   * The view is backed by the bytes of this byte buffer.
+   * Any changes made to the `Int32x4List` will also change the buffer,
+   * and vice versa.
+   *
+   * The viewed region start at [offsetInBytes], which must be 128-bit aligned,
+   * and contains [length] 128-bit integers.
+   * If [length] is omitted, the range extends as far towards the end of
+   * the buffer as possible -
+   * if [lengthInBytes] is not divisible by 16, the last bytes can't be part
+   * of the view.
+   *
+   * The start index and length must describe a valid 128-bit aligned range
+   * of the buffer:
+   *
+   * * `offsetInBytes` must not be negative,
+   * * `offsetInBytes` must be divisible by sixteen,
+   * * `length` must not be negative, and
+   * * `offsetInBytes + length * 16` must not be greater than [lengthInBytes].
+   */
+  Int32x4List asInt32x4List([int offsetInBytes = 0, int length]);
+
+  /**
+   * Creates a [Float32List] _view_ of a region of this byte buffer.
+   *
+   * The view is backed by the bytes of this byte buffer.
+   * Any changes made to the `Float32List` will also change the buffer,
+   * and vice versa.
+   *
+   * The viewed region start at [offsetInBytes], which must be 32-bit aligned,
+   * and contains [length] 32-bit integers.
+   * If [length] is omitted, the range extends as far towards the end of
+   * the buffer as possible -
+   * if [lengthInBytes] is not divisible by four, the last bytes can't be part
+   * of the view.
+   *
+   * The start index and length must describe a valid 32-bit aligned range
+   * of the buffer:
+   *
+   * * `offsetInBytes` must not be negative,
+   * * `offsetInBytes` must be divisible by four,
+   * * `length` must not be negative, and
+   * * `offsetInBytes + length * 4` must not be greater than [lengthInBytes].
+   */
+  Float32List asFloat32List([int offsetInBytes = 0, int length]);
+
+  /**
+   * Creates a [Float64List] _view_ of a region of this byte buffer.
+   *
+   * The view is backed by the bytes of this byte buffer.
+   * Any changes made to the `Float64List` will also change the buffer,
+   * and vice versa.
+   *
+   * The viewed region start at [offsetInBytes], which must be 64-bit aligned,
+   * and contains [length] 64-bit integers.
+   * If [length] is omitted, the range extends as far towards the end of
+   * the buffer as possible -
+   * if [lengthInBytes] is not divisible by eight, the last bytes can't be part
+   * of the view.
+   *
+   * The start index and length must describe a valid 64-bit aligned range
+   * of the buffer:
+   *
+   * * `offsetInBytes` must not be negative,
+   * * `offsetInBytes` must be divisible by eight,
+   * * `length` must not be negative, and
+   * * `offsetInBytes + length * 8` must not be greater than [lengthInBytes].
+   */
+  Float64List asFloat64List([int offsetInBytes = 0, int length]);
+
+  /**
+   * Creates a [Float32x4List] _view_ of a region of this byte buffer.
+   *
+   * The view is backed by the bytes of this byte buffer.
+   * Any changes made to the `Float32x4List` will also change the buffer,
+   * and vice versa.
+   *
+   * The viewed region start at [offsetInBytes], which must be 128-bit aligned,
+   * and contains [length] 128-bit integers.
+   * If [length] is omitted, the range extends as far towards the end of
+   * the buffer as possible -
+   * if [lengthInBytes] is not divisible by 16, the last bytes can't be part
+   * of the view.
+   *
+   * The start index and length must describe a valid 128-bit aligned range
+   * of the buffer:
+   *
+   * * `offsetInBytes` must not be negative,
+   * * `offsetInBytes` must be divisible by sixteen,
+   * * `length` must not be negative, and
+   * * `offsetInBytes + length * 16` must not be greater than [lengthInBytes].
+   */
+  Float32x4List asFloat32x4List([int offsetInBytes = 0, int length]);
+
+  /**
+   * Creates a [Float64x2List] _view_ of a region of this byte buffer.
+   *
+   * The view is backed by the bytes of this byte buffer.
+   * Any changes made to the `Float64x2List` will also change the buffer,
+   * and vice versa.
+   *
+   * The viewed region start at [offsetInBytes], which must be 128-bit aligned,
+   * and contains [length] 128-bit integers.
+   * If [length] is omitted, the range extends as far towards the end of
+   * the buffer as possible -
+   * if [lengthInBytes] is not divisible by 16, the last bytes can't be part
+   * of the view.
+   *
+   * The start index and length must describe a valid 128-bit aligned range
+   * of the buffer:
+   *
+   * * `offsetInBytes` must not be negative,
+   * * `offsetInBytes` must be divisible by sixteen,
+   * * `length` must not be negative, and
+   * * `offsetInBytes + length * 16` must not be greater than [lengthInBytes].
+   */
+  Float64x2List asFloat64x2List([int offsetInBytes = 0, int length]);
+
+  /**
+   * Creates a [ByteData] _view_ of a region of this byte buffer.
+   *
+   * The view is backed by the bytes of this byte buffer.
+   * Any changes made to the `ByteData` will also change the buffer,
+   * and vice versa.
+   *
+   * The viewed region start at [offsetInBytes] and contains [length] bytes.
+   * If [length] is omitted, the range extends to the end of the buffer.
+   *
+   * The start index and length must describe a valid range of the buffer:
+   *
+   * * `offsetInBytes` must not be negative,
+   * * `length` must not be negative, and
+   * * `offsetInBytes + length` must not be greater than [lengthInBytes].
+   */
+  ByteData asByteData([int offsetInBytes = 0, int length]);
+}
+
+/**
+ * A typed view of a sequence of bytes.
+ */
+abstract class TypedData {
+  /**
+   * Returns the number of bytes in the representation of each element in this
+   * list.
+   */
+  int get elementSizeInBytes;
+
+  /**
+   * Returns the offset in bytes into the underlying byte buffer of this view.
+   */
+  int get offsetInBytes;
+
+  /**
+   * Returns the length of this view, in bytes.
+   */
+  int get lengthInBytes;
+
+  /**
+   * Returns the byte buffer associated with this object.
+   */
+  ByteBuffer get buffer;
+}
+
+abstract class _TypedIntList extends TypedData {
+  /**
+   * Returns the concatenation of this list and [other].
+   *
+   * If other is also a typed-data integer list, the returned list will
+   * be a type-data integer list capable of containing all the elements of
+   * this list and of [other].
+   * Otherwise the returned list will be a normal growable `List<int>`.
+   */
+  List<int> operator +(List<int> other);
+}
+
+abstract class _TypedFloatList extends TypedData {
+  /**
+   * Returns the concatenation of this list and [other].
+   *
+   * If other is also a typed-data floating point number list,
+   * the returned list will be a type-data float list capable of containing
+   * all the elements of this list and of [other].
+   * Otherwise the returned list will be a normal growable `List<double>`.
+   */
+  List<double> operator +(List<double> other);
+}
+
+/**
+ * Describes endianness to be used when accessing or updating a
+ * sequence of bytes.
+ */
+class Endian {
+  final bool _littleEndian;
+  const Endian._(this._littleEndian);
+
+  static const Endian big = const Endian._(false);
+  static const Endian little = const Endian._(true);
+  static final Endian host =
+      (new ByteData.view(new Uint16List.fromList([1]).buffer)).getInt8(0) == 1
+          ? little
+          : big;
+}
+
+/**
+ * A fixed-length, random-access sequence of bytes that also provides random
+ * and unaligned access to the fixed-width integers and floating point
+ * numbers represented by those bytes.
+ *
+ * `ByteData` may be used to pack and unpack data from external sources
+ * (such as networks or files systems), and to process large quantities
+ * of numerical data more efficiently than would be possible
+ * with ordinary [List] implementations.
+ * `ByteData` can save space, by eliminating the need for object headers,
+ * and time, by eliminating the need for data copies.
+ * Finally, `ByteData` may be used to intentionally reinterpret the bytes
+ * representing one arithmetic type as another.
+ * For example this code fragment determine what 32-bit signed integer
+ * is represented by the bytes of a 32-bit floating point number:
+ *
+ *     var buffer = new Uint8List(8).buffer;
+ *     var bdata = new ByteData.view(buffer);
+ *     bdata.setFloat32(0, 3.04);
+ *     int huh = bdata.getInt32(0);
+ */
+abstract class ByteData implements TypedData {
+  /**
+   * Creates a [ByteData] of the specified length (in elements), all of
+   * whose bytes are initially zero.
+   */
+  @pragma("vm:entry-point")
+  external factory ByteData(int length);
+
+  /**
+   * Creates an [ByteData] _view_ of the specified region in [buffer].
+   *
+   * Changes in the [ByteData] will be visible in the byte
+   * buffer and vice versa.
+   * If the [offsetInBytes] index of the region is not specified,
+   * it defaults to zero (the first byte in the byte buffer).
+   * If the length is not specified, it defaults to `null`,
+   * which indicates that the view extends to the end of the byte buffer.
+   *
+   * Throws [RangeError] if [offsetInBytes] or [length] are negative, or
+   * if [offsetInBytes] + ([length] * elementSizeInBytes) is greater than
+   * the length of [buffer].
+   */
+  factory ByteData.view(ByteBuffer buffer,
+      [int offsetInBytes = 0, int length]) {
+    return buffer.asByteData(offsetInBytes, length);
+  }
+
+  /**
+   * Returns the (possibly negative) integer represented by the byte at the
+   * specified [byteOffset] in this object, in two's complement binary
+   * representation.
+   *
+   * The return value will be between -128 and 127, inclusive.
+   *
+   * Throws [RangeError] if [byteOffset] is negative, or
+   * greater than or equal to the length of this object.
+   */
+  int getInt8(int byteOffset);
+
+  /**
+   * Sets the byte at the specified [byteOffset] in this object to the
+   * two's complement binary representation of the specified [value], which
+   * must fit in a single byte.
+   *
+   * In other words, [value] must be between -128 and 127, inclusive.
+   *
+   * Throws [RangeError] if [byteOffset] is negative, or
+   * greater than or equal to the length of this object.
+   */
+  void setInt8(int byteOffset, int value);
+
+  /**
+   * Returns the positive integer represented by the byte at the specified
+   * [byteOffset] in this object, in unsigned binary form.
+   *
+   * The return value will be between 0 and 255, inclusive.
+   *
+   * Throws [RangeError] if [byteOffset] is negative, or
+   * greater than or equal to the length of this object.
+   */
+  int getUint8(int byteOffset);
+
+  /**
+   * Sets the byte at the specified [byteOffset] in this object to the
+   * unsigned binary representation of the specified [value], which must fit
+   * in a single byte.
+   *
+   * In other words, [value] must be between 0 and 255, inclusive.
+   *
+   * Throws [RangeError] if [byteOffset] is negative,
+   * or greater than or equal to the length of this object.
+   */
+  void setUint8(int byteOffset, int value);
+
+  /**
+   * Returns the (possibly negative) integer represented by the two bytes at
+   * the specified [byteOffset] in this object, in two's complement binary
+   * form.
+   *
+   * The return value will be between -2<sup>15</sup> and 2<sup>15</sup> - 1,
+   * inclusive.
+   *
+   * Throws [RangeError] if [byteOffset] is negative, or
+   * `byteOffset + 2` is greater than the length of this object.
+   */
+  int getInt16(int byteOffset, [Endian endian = Endian.big]);
+
+  /**
+   * Sets the two bytes starting at the specified [byteOffset] in this
+   * object to the two's complement binary representation of the specified
+   * [value], which must fit in two bytes.
+   *
+   * In other words, [value] must lie
+   * between -2<sup>15</sup> and 2<sup>15</sup> - 1, inclusive.
+   *
+   * Throws [RangeError] if [byteOffset] is negative, or
+   * `byteOffset + 2` is greater than the length of this object.
+   */
+  void setInt16(int byteOffset, int value, [Endian endian = Endian.big]);
+
+  /**
+   * Returns the positive integer represented by the two bytes starting
+   * at the specified [byteOffset] in this object, in unsigned binary
+   * form.
+   *
+   * The return value will be between 0 and  2<sup>16</sup> - 1, inclusive.
+   *
+   * Throws [RangeError] if [byteOffset] is negative, or
+   * `byteOffset + 2` is greater than the length of this object.
+   */
+  int getUint16(int byteOffset, [Endian endian = Endian.big]);
+
+  /**
+   * Sets the two bytes starting at the specified [byteOffset] in this object
+   * to the unsigned binary representation of the specified [value],
+   * which must fit in two bytes.
+   *
+   * In other words, [value] must be between
+   * 0 and 2<sup>16</sup> - 1, inclusive.
+   *
+   * Throws [RangeError] if [byteOffset] is negative, or
+   * `byteOffset + 2` is greater than the length of this object.
+   */
+  void setUint16(int byteOffset, int value, [Endian endian = Endian.big]);
+
+  /**
+   * Returns the (possibly negative) integer represented by the four bytes at
+   * the specified [byteOffset] in this object, in two's complement binary
+   * form.
+   *
+   * The return value will be between -2<sup>31</sup> and 2<sup>31</sup> - 1,
+   * inclusive.
+   *
+   * Throws [RangeError] if [byteOffset] is negative, or
+   * `byteOffset + 4` is greater than the length of this object.
+   */
+  int getInt32(int byteOffset, [Endian endian = Endian.big]);
+
+  /**
+   * Sets the four bytes starting at the specified [byteOffset] in this
+   * object to the two's complement binary representation of the specified
+   * [value], which must fit in four bytes.
+   *
+   * In other words, [value] must lie
+   * between -2<sup>31</sup> and 2<sup>31</sup> - 1, inclusive.
+   *
+   * Throws [RangeError] if [byteOffset] is negative, or
+   * `byteOffset + 4` is greater than the length of this object.
+   */
+  void setInt32(int byteOffset, int value, [Endian endian = Endian.big]);
+
+  /**
+   * Returns the positive integer represented by the four bytes starting
+   * at the specified [byteOffset] in this object, in unsigned binary
+   * form.
+   *
+   * The return value will be between 0 and  2<sup>32</sup> - 1, inclusive.
+   *
+   * Throws [RangeError] if [byteOffset] is negative, or
+   * `byteOffset + 4` is greater than the length of this object.
+   */
+  int getUint32(int byteOffset, [Endian endian = Endian.big]);
+
+  /**
+   * Sets the four bytes starting at the specified [byteOffset] in this object
+   * to the unsigned binary representation of the specified [value],
+   * which must fit in four bytes.
+   *
+   * In other words, [value] must be between
+   * 0 and 2<sup>32</sup> - 1, inclusive.
+   *
+   * Throws [RangeError] if [byteOffset] is negative, or
+   * `byteOffset + 4` is greater than the length of this object.
+   */
+  void setUint32(int byteOffset, int value, [Endian endian = Endian.big]);
+
+  /**
+   * Returns the (possibly negative) integer represented by the eight bytes at
+   * the specified [byteOffset] in this object, in two's complement binary
+   * form.
+   *
+   * The return value will be between -2<sup>63</sup> and 2<sup>63</sup> - 1,
+   * inclusive.
+   *
+   * Throws [RangeError] if [byteOffset] is negative, or
+   * `byteOffset + 8` is greater than the length of this object.
+   */
+  int getInt64(int byteOffset, [Endian endian = Endian.big]);
+
+  /**
+   * Sets the eight bytes starting at the specified [byteOffset] in this
+   * object to the two's complement binary representation of the specified
+   * [value], which must fit in eight bytes.
+   *
+   * In other words, [value] must lie
+   * between -2<sup>63</sup> and 2<sup>63</sup> - 1, inclusive.
+   *
+   * Throws [RangeError] if [byteOffset] is negative, or
+   * `byteOffset + 8` is greater than the length of this object.
+   */
+  void setInt64(int byteOffset, int value, [Endian endian = Endian.big]);
+
+  /**
+   * Returns the positive integer represented by the eight bytes starting
+   * at the specified [byteOffset] in this object, in unsigned binary
+   * form.
+   *
+   * The return value will be between 0 and  2<sup>64</sup> - 1, inclusive.
+   *
+   * Throws [RangeError] if [byteOffset] is negative, or
+   * `byteOffset + 8` is greater than the length of this object.
+   */
+  int getUint64(int byteOffset, [Endian endian = Endian.big]);
+
+  /**
+   * Sets the eight bytes starting at the specified [byteOffset] in this object
+   * to the unsigned binary representation of the specified [value],
+   * which must fit in eight bytes.
+   *
+   * In other words, [value] must be between
+   * 0 and 2<sup>64</sup> - 1, inclusive.
+   *
+   * Throws [RangeError] if [byteOffset] is negative, or
+   * `byteOffset + 8` is greater than the length of this object.
+   */
+  void setUint64(int byteOffset, int value, [Endian endian = Endian.big]);
+
+  /**
+   * Returns the floating point number represented by the four bytes at
+   * the specified [byteOffset] in this object, in IEEE 754
+   * single-precision binary floating-point format (binary32).
+   *
+   * Throws [RangeError] if [byteOffset] is negative, or
+   * `byteOffset + 4` is greater than the length of this object.
+   */
+  double getFloat32(int byteOffset, [Endian endian = Endian.big]);
+
+  /**
+   * Sets the four bytes starting at the specified [byteOffset] in this
+   * object to the IEEE 754 single-precision binary floating-point
+   * (binary32) representation of the specified [value].
+   *
+   * **Note that this method can lose precision.** The input [value] is
+   * a 64-bit floating point value, which will be converted to 32-bit
+   * floating point value by IEEE 754 rounding rules before it is stored.
+   * If [value] cannot be represented exactly as a binary32, it will be
+   * converted to the nearest binary32 value.  If two binary32 values are
+   * equally close, the one whose least significant bit is zero will be used.
+   * Note that finite (but large) values can be converted to infinity, and
+   * small non-zero values can be converted to zero.
+   *
+   * Throws [RangeError] if [byteOffset] is negative, or
+   * `byteOffset + 4` is greater than the length of this object.
+   */
+  void setFloat32(int byteOffset, double value, [Endian endian = Endian.big]);
+
+  /**
+   * Returns the floating point number represented by the eight bytes at
+   * the specified [byteOffset] in this object, in IEEE 754
+   * double-precision binary floating-point format (binary64).
+   *
+   * Throws [RangeError] if [byteOffset] is negative, or
+   * `byteOffset + 8` is greater than the length of this object.
+   */
+  double getFloat64(int byteOffset, [Endian endian = Endian.big]);
+
+  /**
+   * Sets the eight bytes starting at the specified [byteOffset] in this
+   * object to the IEEE 754 double-precision binary floating-point
+   * (binary64) representation of the specified [value].
+   *
+   * Throws [RangeError] if [byteOffset] is negative, or
+   * `byteOffset + 8` is greater than the length of this object.
+   */
+  void setFloat64(int byteOffset, double value, [Endian endian = Endian.big]);
+}
+
+/**
+ * A fixed-length list of 8-bit signed integers.
+ *
+ * For long lists, this implementation can be considerably
+ * more space- and time-efficient than the default [List] implementation.
+ *
+ * Integers stored in the list are truncated to their low eight bits,
+ * interpreted as a signed 8-bit two's complement integer with values in the
+ * range -128 to +127.
+ */
+abstract class Int8List implements List<int>, _TypedIntList {
+  /**
+   * Creates an [Int8List] of the specified length (in elements), all of
+   * whose elements are initially zero.
+   */
+  external factory Int8List(int length);
+
+  /**
+   * Creates a [Int8List] with the same length as the [elements] list
+   * and copies over the elements.
+   *
+   * Values are truncated to fit in the list when they are copied,
+   * the same way storing values truncates them.
+   */
+  external factory Int8List.fromList(List<int> elements);
+
+  /**
+   * Creates an [Int8List] _view_ of the specified region in [buffer].
+   *
+   * Changes in the [Int8List] will be visible in the byte
+   * buffer and vice versa.
+   * If the [offsetInBytes] index of the region is not specified,
+   * it defaults to zero (the first byte in the byte buffer).
+   * If the length is not specified, it defaults to `null`,
+   * which indicates that the view extends to the end of the byte buffer.
+   *
+   * Throws [RangeError] if [offsetInBytes] or [length] are negative, or
+   * if [offsetInBytes] + ([length] * elementSizeInBytes) is greater than
+   * the length of [buffer].
+   */
+  factory Int8List.view(ByteBuffer buffer,
+      [int offsetInBytes = 0, int length]) {
+    return buffer.asInt8List(offsetInBytes, length);
+  }
+
+  /**
+   * Returns a new list containing the elements between [start] and [end].
+   *
+   * The new list is an `Int8List` containing the elements of this list at
+   * positions greater than or equal to [start] and less than [end] in the same
+   * order as they occur in this list.
+   *
+   * ```dart
+   * var numbers = Int8List.fromList([0, 1, 2, 3, 4]);
+   * print(numbers.sublist(1, 3)); // [1, 2]
+   * print(numbers.sublist(1, 3).runtimeType); // Int8List
+   * ```
+   *
+   * If [end] is omitted, it defaults to the [length] of this list.
+   *
+   * ```dart
+   * print(numbers.sublist(1)); // [1, 2, 3, 4]
+   * ```
+   *
+   * The `start` and `end` positions must satisfy the relations
+   * 0 ≤ `start` ≤ `end` ≤ `this.length`
+   * If `end` is equal to `start`, then the returned list is empty.
+   */
+  Int8List sublist(int start, [int end]);
+
+  static const int bytesPerElement = 1;
+}
+
+/**
+ * A fixed-length list of 8-bit unsigned integers.
+ *
+ * For long lists, this implementation can be considerably
+ * more space- and time-efficient than the default [List] implementation.
+ *
+ * Integers stored in the list are truncated to their low eight bits,
+ * interpreted as an unsigned 8-bit integer with values in the
+ * range 0 to 255.
+ */
+abstract class Uint8List implements List<int>, _TypedIntList {
+  /**
+   * Creates a [Uint8List] of the specified length (in elements), all of
+   * whose elements are initially zero.
+   */
+  external factory Uint8List(int length);
+
+  /**
+   * Creates a [Uint8List] with the same length as the [elements] list
+   * and copies over the elements.
+   *
+   * Values are truncated to fit in the list when they are copied,
+   * the same way storing values truncates them.
+   */
+  external factory Uint8List.fromList(List<int> elements);
+
+  /**
+   * Creates a [Uint8List] _view_ of the specified region in [buffer].
+   *
+   * Changes in the [Uint8List] will be visible in the byte
+   * buffer and vice versa.
+   * If the [offsetInBytes] index of the region is not specified,
+   * it defaults to zero (the first byte in the byte buffer).
+   * If the length is not specified, it defaults to `null`,
+   * which indicates that the view extends to the end of the byte buffer.
+   *
+   * Throws [RangeError] if [offsetInBytes] or [length] are negative, or
+   * if [offsetInBytes] + ([length] * elementSizeInBytes) is greater than
+   * the length of [buffer].
+   */
+  factory Uint8List.view(ByteBuffer buffer,
+      [int offsetInBytes = 0, int length]) {
+    return buffer.asUint8List(offsetInBytes, length);
+  }
+
+  /**
+   * Returns a concatenation of this list and [other].
+   *
+   * If [other] is also a typed-data list, then the return list will be a
+   * typed data list capable of holding both unsigned 8-bit integers and
+   * the elements of [other], otherwise it'll be a normal list of integers.
+   */
+  List<int> operator +(List<int> other);
+
+  /**
+   * Returns a new list containing the elements between [start] and [end].
+   *
+   * The new list is a `Uint8List` containing the elements of this list at
+   * positions greater than or equal to [start] and less than [end] in the same
+   * order as they occur in this list.
+   *
+   * ```dart
+   * var numbers = Uint8List.fromList([0, 1, 2, 3, 4]);
+   * print(numbers.sublist(1, 3)); // [1, 2]
+   * print(numbers.sublist(1, 3).runtimeType); // Uint8List
+   * ```
+   *
+   * If [end] is omitted, it defaults to the [length] of this list.
+   *
+   * ```dart
+   * print(numbers.sublist(1)); // [1, 2, 3, 4]
+   * ```
+   *
+   * The `start` and `end` positions must satisfy the relations
+   * 0 ≤ `start` ≤ `end` ≤ `this.length`
+   * If `end` is equal to `start`, then the returned list is empty.
+   */
+  Uint8List sublist(int start, [int end]);
+
+  static const int bytesPerElement = 1;
+}
+
+/**
+ * A fixed-length list of 8-bit unsigned integers.
+ *
+ * For long lists, this implementation can be considerably
+ * more space- and time-efficient than the default [List] implementation.
+ *
+ * Integers stored in the list are clamped to an unsigned eight bit value.
+ * That is, all values below zero are stored as zero
+ * and all values above 255 are stored as 255.
+ */
+abstract class Uint8ClampedList implements List<int>, _TypedIntList {
+  /**
+   * Creates a [Uint8ClampedList] of the specified length (in elements), all of
+   * whose elements are initially zero.
+   */
+  external factory Uint8ClampedList(int length);
+
+  /**
+   * Creates a [Uint8ClampedList] of the same size as the [elements]
+   * list and copies over the values clamping when needed.
+   *
+   * Values are clamped to fit in the list when they are copied,
+   * the same way storing values clamps them.
+   */
+  external factory Uint8ClampedList.fromList(List<int> elements);
+
+  /**
+   * Creates a [Uint8ClampedList] _view_ of the specified region in the
+   * specified byte [buffer].
+   *
+   * Changes in the [Uint8List] will be visible in the byte buffer
+   * and vice versa.
+   * If the [offsetInBytes] index of the region is not specified,
+   * it defaults to zero (the first byte in the byte buffer).
+   * If the length is not specified, it defaults to `null`,
+   * which indicates that the view extends to the end of the byte buffer.
+   *
+   * Throws [RangeError] if [offsetInBytes] or [length] are negative, or
+   * if [offsetInBytes] + ([length] * elementSizeInBytes) is greater than
+   * the length of [buffer].
+   */
+  factory Uint8ClampedList.view(ByteBuffer buffer,
+      [int offsetInBytes = 0, int length]) {
+    return buffer.asUint8ClampedList(offsetInBytes, length);
+  }
+
+  /**
+   * Returns a new list containing the elements between [start] and [end].
+   *
+   * The new list is a `Uint8ClampedList` containing the elements of this
+   * list at positions greater than or equal to [start] and less than [end] in
+   * the same order as they occur in this list.
+   *
+   * ```dart
+   * var numbers = Uint8ClampedList.fromList([0, 1, 2, 3, 4]);
+   * print(numbers.sublist(1, 3)); // [1, 2]
+   * print(numbers.sublist(1, 3).runtimeType); // Uint8ClampedList
+   * ```
+   *
+   * If [end] is omitted, it defaults to the [length] of this list.
+   *
+   * ```dart
+   * print(numbers.sublist(1)); // [1, 2, 3, 4]
+   * ```
+   *
+   * The `start` and `end` positions must satisfy the relations
+   * 0 ≤ `start` ≤ `end` ≤ `this.length`
+   * If `end` is equal to `start`, then the returned list is empty.
+   */
+  Uint8ClampedList sublist(int start, [int end]);
+
+  static const int bytesPerElement = 1;
+}
+
+/**
+ * A fixed-length list of 16-bit signed integers that is viewable as a
+ * [TypedData].
+ *
+ * For long lists, this implementation can be considerably
+ * more space- and time-efficient than the default [List] implementation.
+ *
+ * Integers stored in the list are truncated to their low 16 bits,
+ * interpreted as a signed 16-bit two's complement integer with values in the
+ * range -32768 to +32767.
+ */
+abstract class Int16List implements List<int>, _TypedIntList {
+  /**
+   * Creates an [Int16List] of the specified length (in elements), all of
+   * whose elements are initially zero.
+   */
+  external factory Int16List(int length);
+
+  /**
+   * Creates a [Int16List] with the same length as the [elements] list
+   * and copies over the elements.
+   *
+   * Values are truncated to fit in the list when they are copied,
+   * the same way storing values truncates them.
+   */
+  external factory Int16List.fromList(List<int> elements);
+
+  /**
+   * Creates an [Int16List] _view_ of the specified region in [buffer].
+   *
+   * Changes in the [Int16List] will be visible in the byte
+   * buffer and vice versa.
+   * If the [offsetInBytes] index of the region is not specified,
+   * it defaults to zero (the first byte in the byte buffer).
+   * If the length is not specified, it defaults to `null`,
+   * which indicates that the view extends to the end of the byte buffer.
+   *
+   * Throws [RangeError] if [offsetInBytes] or [length] are negative, or
+   * if [offsetInBytes] + ([length] * elementSizeInBytes) is greater than
+   * the length of [buffer].
+   *
+   * Throws [ArgumentError] if [offsetInBytes] is not a multiple of
+   * [bytesPerElement].
+   */
+  factory Int16List.view(ByteBuffer buffer,
+      [int offsetInBytes = 0, int length]) {
+    return buffer.asInt16List(offsetInBytes, length);
+  }
+
+  /**
+   * Returns a new list containing the elements between [start] and [end].
+   *
+   * The new list is an `Int16List` containing the elements of this
+   * list at positions greater than or equal to [start] and less than [end] in
+   * the same order as they occur in this list.
+   *
+   * ```dart
+   * var numbers = Int16List.fromList([0, 1, 2, 3, 4]);
+   * print(numbers.sublist(1, 3)); // [1, 2]
+   * print(numbers.sublist(1, 3).runtimeType); // Int16List
+   * ```
+   *
+   * If [end] is omitted, it defaults to the [length] of this list.
+   *
+   * ```dart
+   * print(numbers.sublist(1)); // [1, 2, 3, 4]
+   * ```
+   *
+   * The `start` and `end` positions must satisfy the relations
+   * 0 ≤ `start` ≤ `end` ≤ `this.length`
+   * If `end` is equal to `start`, then the returned list is empty.
+   */
+  Int16List sublist(int start, [int end]);
+
+  static const int bytesPerElement = 2;
+}
+
+/**
+ * A fixed-length list of 16-bit unsigned integers that is viewable as a
+ * [TypedData].
+ *
+ * For long lists, this implementation can be considerably
+ * more space- and time-efficient than the default [List] implementation.
+ *
+ * Integers stored in the list are truncated to their low 16 bits,
+ * interpreted as an unsigned 16-bit integer with values in the
+ * range 0 to 65535.
+ */
+abstract class Uint16List implements List<int>, _TypedIntList {
+  /**
+   * Creates a [Uint16List] of the specified length (in elements), all
+   * of whose elements are initially zero.
+   */
+  external factory Uint16List(int length);
+
+  /**
+   * Creates a [Uint16List] with the same length as the [elements] list
+   * and copies over the elements.
+   *
+   * Values are truncated to fit in the list when they are copied,
+   * the same way storing values truncates them.
+   */
+  external factory Uint16List.fromList(List<int> elements);
+
+  /**
+   * Creates a [Uint16List] _view_ of the specified region in
+   * the specified byte buffer.
+   *
+   * Changes in the [Uint16List] will be visible in the byte buffer
+   * and vice versa.
+   * If the [offsetInBytes] index of the region is not specified,
+   * it defaults to zero (the first byte in the byte buffer).
+   * If the length is not specified, it defaults to `null`,
+   * which indicates that the view extends to the end of the byte buffer.
+   *
+   * Throws [RangeError] if [offsetInBytes] or [length] are negative, or
+   * if [offsetInBytes] + ([length] * elementSizeInBytes) is greater than
+   * the length of [buffer].
+   *
+   * Throws [ArgumentError] if [offsetInBytes] is not a multiple of
+   * [bytesPerElement].
+   */
+  factory Uint16List.view(ByteBuffer buffer,
+      [int offsetInBytes = 0, int length]) {
+    return buffer.asUint16List(offsetInBytes, length);
+  }
+
+  /**
+   * Returns a new list containing the elements between [start] and [end].
+   *
+   * The new list is a `Uint16List` containing the elements of this
+   * list at positions greater than or equal to [start] and less than [end] in
+   * the same order as they occur in this list.
+   *
+   * ```dart
+   * var numbers = Uint16List.fromList([0, 1, 2, 3, 4]);
+   * print(numbers.sublist(1, 3)); // [1, 2]
+   * print(numbers.sublist(1, 3).runtimeType); // Uint16List
+   * ```
+   *
+   * If [end] is omitted, it defaults to the [length] of this list.
+   *
+   * ```dart
+   * print(numbers.sublist(1)); // [1, 2, 3, 4]
+   * ```
+   *
+   * The `start` and `end` positions must satisfy the relations
+   * 0 ≤ `start` ≤ `end` ≤ `this.length`
+   * If `end` is equal to `start`, then the returned list is empty.
+   */
+  Uint16List sublist(int start, [int end]);
+
+  static const int bytesPerElement = 2;
+}
+
+/**
+ * A fixed-length list of 32-bit signed integers that is viewable as a
+ * [TypedData].
+ *
+ * For long lists, this implementation can be considerably
+ * more space- and time-efficient than the default [List] implementation.
+ *
+ * Integers stored in the list are truncated to their low 32 bits,
+ * interpreted as a signed 32-bit two's complement integer with values in the
+ * range -2147483648 to 2147483647.
+ */
+abstract class Int32List implements List<int>, _TypedIntList {
+  /**
+   * Creates an [Int32List] of the specified length (in elements), all of
+   * whose elements are initially zero.
+   */
+  external factory Int32List(int length);
+
+  /**
+   * Creates a [Int32List] with the same length as the [elements] list
+   * and copies over the elements.
+   *
+   * Values are truncated to fit in the list when they are copied,
+   * the same way storing values truncates them.
+   */
+  external factory Int32List.fromList(List<int> elements);
+
+  /**
+   * Creates an [Int32List] _view_ of the specified region in [buffer].
+   *
+   * Changes in the [Int32List] will be visible in the byte
+   * buffer and vice versa.
+   * If the [offsetInBytes] index of the region is not specified,
+   * it defaults to zero (the first byte in the byte buffer).
+   * If the length is not specified, it defaults to `null`,
+   * which indicates that the view extends to the end of the byte buffer.
+   *
+   * Throws [RangeError] if [offsetInBytes] or [length] are negative, or
+   * if [offsetInBytes] + ([length] * elementSizeInBytes) is greater than
+   * the length of [buffer].
+   *
+   * Throws [ArgumentError] if [offsetInBytes] is not a multiple of
+   * [bytesPerElement].
+   */
+  factory Int32List.view(ByteBuffer buffer,
+      [int offsetInBytes = 0, int length]) {
+    return buffer.asInt32List(offsetInBytes, length);
+  }
+
+  /**
+   * Returns a new list containing the elements between [start] and [end].
+   *
+   * The new list is an `Int32List` containing the elements of this
+   * list at positions greater than or equal to [start] and less than [end] in
+   * the same order as they occur in this list.
+   *
+   * ```dart
+   * var numbers = Int32List.fromList([0, 1, 2, 3, 4]);
+   * print(numbers.sublist(1, 3)); // [1, 2]
+   * print(numbers.sublist(1, 3).runtimeType); // Int32List
+   * ```
+   *
+   * If [end] is omitted, it defaults to the [length] of this list.
+   *
+   * ```dart
+   * print(numbers.sublist(1)); // [1, 2, 3, 4]
+   * ```
+   *
+   * The `start` and `end` positions must satisfy the relations
+   * 0 ≤ `start` ≤ `end` ≤ `this.length`
+   * If `end` is equal to `start`, then the returned list is empty.
+   */
+  Int32List sublist(int start, [int end]);
+
+  static const int bytesPerElement = 4;
+}
+
+/**
+ * A fixed-length list of 32-bit unsigned integers that is viewable as a
+ * [TypedData].
+ *
+ * For long lists, this implementation can be considerably
+ * more space- and time-efficient than the default [List] implementation.
+ *
+ * Integers stored in the list are truncated to their low 32 bits,
+ * interpreted as an unsigned 32-bit integer with values in the
+ * range 0 to 4294967295.
+ */
+abstract class Uint32List implements List<int>, _TypedIntList {
+  /**
+   * Creates a [Uint32List] of the specified length (in elements), all
+   * of whose elements are initially zero.
+   */
+  external factory Uint32List(int length);
+
+  /**
+   * Creates a [Uint32List] with the same length as the [elements] list
+   * and copies over the elements.
+   *
+   * Values are truncated to fit in the list when they are copied,
+   * the same way storing values truncates them.
+   */
+  external factory Uint32List.fromList(List<int> elements);
+
+  /**
+   * Creates a [Uint32List] _view_ of the specified region in
+   * the specified byte buffer.
+   *
+   * Changes in the [Uint32List] will be visible in the byte buffer
+   * and vice versa.
+   * If the [offsetInBytes] index of the region is not specified,
+   * it defaults to zero (the first byte in the byte buffer).
+   * If the length is not specified, it defaults to `null`,
+   * which indicates that the view extends to the end of the byte buffer.
+   *
+   * Throws [RangeError] if [offsetInBytes] or [length] are negative, or
+   * if [offsetInBytes] + ([length] * elementSizeInBytes) is greater than
+   * the length of [buffer].
+   *
+   * Throws [ArgumentError] if [offsetInBytes] is not a multiple of
+   * [bytesPerElement].
+   */
+  factory Uint32List.view(ByteBuffer buffer,
+      [int offsetInBytes = 0, int length]) {
+    return buffer.asUint32List(offsetInBytes, length);
+  }
+
+  /**
+   * Returns a new list containing the elements between [start] and [end].
+   *
+   * The new list is a `Uint32List` containing the elements of this
+   * list at positions greater than or equal to [start] and less than [end] in
+   * the same order as they occur in this list.
+   *
+   * ```dart
+   * var numbers = Uint32List.fromList([0, 1, 2, 3, 4]);
+   * print(numbers.sublist(1, 3)); // [1, 2]
+   * print(numbers.sublist(1, 3).runtimeType); // Uint32List
+   * ```
+   *
+   * If [end] is omitted, it defaults to the [length] of this list.
+   *
+   * ```dart
+   * print(numbers.sublist(1)); // [1, 2, 3, 4]
+   * ```
+   *
+   * The `start` and `end` positions must satisfy the relations
+   * 0 ≤ `start` ≤ `end` ≤ `this.length`
+   * If `end` is equal to `start`, then the returned list is empty.
+   */
+  Uint32List sublist(int start, [int end]);
+
+  static const int bytesPerElement = 4;
+}
+
+/**
+ * A fixed-length list of 64-bit signed integers that is viewable as a
+ * [TypedData].
+ *
+ * For long lists, this implementation can be considerably
+ * more space- and time-efficient than the default [List] implementation.
+ *
+ * Integers stored in the list are truncated to their low 64 bits,
+ * interpreted as a signed 64-bit two's complement integer with values in the
+ * range -9223372036854775808 to +9223372036854775807.
+ */
+abstract class Int64List implements List<int>, _TypedIntList {
+  /**
+   * Creates an [Int64List] of the specified length (in elements), all of
+   * whose elements are initially zero.
+   */
+  external factory Int64List(int length);
+
+  /**
+   * Creates a [Int64List] with the same length as the [elements] list
+   * and copies over the elements.
+   *
+   * Values are truncated to fit in the list when they are copied,
+   * the same way storing values truncates them.
+   */
+  external factory Int64List.fromList(List<int> elements);
+
+  /**
+   * Creates an [Int64List] _view_ of the specified region in [buffer].
+   *
+   * Changes in the [Int64List] will be visible in the byte buffer
+   * and vice versa.
+   * If the [offsetInBytes] index of the region is not specified,
+   * it defaults to zero (the first byte in the byte buffer).
+   * If the length is not specified, it defaults to `null`,
+   * which indicates that the view extends to the end of the byte buffer.
+   *
+   * Throws [RangeError] if [offsetInBytes] or [length] are negative, or
+   * if [offsetInBytes] + ([length] * elementSizeInBytes) is greater than
+   * the length of [buffer].
+   *
+   * Throws [ArgumentError] if [offsetInBytes] is not a multiple of
+   * [bytesPerElement].
+   */
+  factory Int64List.view(ByteBuffer buffer,
+      [int offsetInBytes = 0, int length]) {
+    return buffer.asInt64List(offsetInBytes, length);
+  }
+
+  /**
+   * Returns a new list containing the elements between [start] and [end].
+   *
+   * The new list is an `Int64List` containing the elements of this
+   * list at positions greater than or equal to [start] and less than [end] in
+   * the same order as they occur in this list.
+   *
+   * ```dart
+   * var numbers = Int64List.fromList([0, 1, 2, 3, 4]);
+   * print(numbers.sublist(1, 3)); // [1, 2]
+   * print(numbers.sublist(1, 3).runtimeType); // Int64List
+   * ```
+   *
+   * If [end] is omitted, it defaults to the [length] of this list.
+   *
+   * ```dart
+   * print(numbers.sublist(1)); // [1, 2, 3, 4]
+   * ```
+   *
+   * The `start` and `end` positions must satisfy the relations
+   * 0 ≤ `start` ≤ `end` ≤ `this.length`
+   * If `end` is equal to `start`, then the returned list is empty.
+   */
+  Int64List sublist(int start, [int end]);
+
+  static const int bytesPerElement = 8;
+}
+
+/**
+ * A fixed-length list of 64-bit unsigned integers that is viewable as a
+ * [TypedData].
+ *
+ * For long lists, this implementation can be considerably
+ * more space- and time-efficient than the default [List] implementation.
+ *
+ * Integers stored in the list are truncated to their low 64 bits,
+ * interpreted as an unsigned 64-bit integer with values in the
+ * range 0 to 18446744073709551615.
+ */
+abstract class Uint64List implements List<int>, _TypedIntList {
+  /**
+   * Creates a [Uint64List] of the specified length (in elements), all
+   * of whose elements are initially zero.
+   */
+  external factory Uint64List(int length);
+
+  /**
+   * Creates a [Uint64List] with the same length as the [elements] list
+   * and copies over the elements.
+   *
+   * Values are truncated to fit in the list when they are copied,
+   * the same way storing values truncates them.
+   */
+  external factory Uint64List.fromList(List<int> elements);
+
+  /**
+   * Creates an [Uint64List] _view_ of the specified region in
+   * the specified byte buffer.
+   *
+   * Changes in the [Uint64List] will be visible in the byte buffer
+   * and vice versa.
+   * If the [offsetInBytes] index of the region is not specified,
+   * it defaults to zero (the first byte in the byte buffer).
+   * If the length is not specified, it defaults to `null`,
+   * which indicates that the view extends to the end of the byte buffer.
+   *
+   * Throws [RangeError] if [offsetInBytes] or [length] are negative, or
+   * if [offsetInBytes] + ([length] * elementSizeInBytes) is greater than
+   * the length of [buffer].
+   *
+   * Throws [ArgumentError] if [offsetInBytes] is not a multiple of
+   * [bytesPerElement].
+   */
+  factory Uint64List.view(ByteBuffer buffer,
+      [int offsetInBytes = 0, int length]) {
+    return buffer.asUint64List(offsetInBytes, length);
+  }
+
+  /**
+   * Returns a new list containing the elements between [start] and [end].
+   *
+   * The new list is a `Uint64List` containing the elements of this
+   * list at positions greater than or equal to [start] and less than [end] in
+   * the same order as they occur in this list.
+   *
+   * ```dart
+   * var numbers = Uint64List.fromList([0, 1, 2, 3, 4]);
+   * print(numbers.sublist(1, 3)); // [1, 2]
+   * print(numbers.sublist(1, 3).runtimeType); // Uint64List
+   * ```
+   *
+   * If [end] is omitted, it defaults to the [length] of this list.
+   *
+   * ```dart
+   * print(numbers.sublist(1)); // [1, 2, 3, 4]
+   * ```
+   *
+   * The `start` and `end` positions must satisfy the relations
+   * 0 ≤ `start` ≤ `end` ≤ `this.length`
+   * If `end` is equal to `start`, then the returned list is empty.
+   */
+  Uint64List sublist(int start, [int end]);
+
+  static const int bytesPerElement = 8;
+}
+
+/**
+ * A fixed-length list of IEEE 754 single-precision binary floating-point
+ * numbers that is viewable as a [TypedData].
+ *
+ * For long lists, this
+ * implementation can be considerably more space- and time-efficient than
+ * the default [List] implementation.
+ *
+ * Double values stored in the list are converted to the nearest
+ * single-precision value. Values read are converted to a double
+ * value with the same value.
+ */
+abstract class Float32List implements List<double>, _TypedFloatList {
+  /**
+   * Creates a [Float32List] of the specified length (in elements), all of
+   * whose elements are initially zero.
+   */
+  external factory Float32List(int length);
+
+  /**
+   * Creates a [Float32List] with the same length as the [elements] list
+   * and copies over the elements.
+   *
+   * Values are truncated to fit in the list when they are copied,
+   * the same way storing values truncates them.
+   */
+  external factory Float32List.fromList(List<double> elements);
+
+  /**
+   * Creates a [Float32List] _view_ of the specified region in [buffer].
+   *
+   * Changes in the [Float32List] will be visible in the byte
+   * buffer and vice versa.
+   * If the [offsetInBytes] index of the region is not specified,
+   * it defaults to zero (the first byte in the byte buffer).
+   * If the length is not specified, it defaults to `null`,
+   * which indicates that the view extends to the end of the byte buffer.
+   *
+   * Throws [RangeError] if [offsetInBytes] or [length] are negative, or
+   * if [offsetInBytes] + ([length] * elementSizeInBytes) is greater than
+   * the length of [buffer].
+   *
+   * Throws [ArgumentError] if [offsetInBytes] is not a multiple of
+   * [bytesPerElement].
+   */
+  factory Float32List.view(ByteBuffer buffer,
+      [int offsetInBytes = 0, int length]) {
+    return buffer.asFloat32List(offsetInBytes, length);
+  }
+
+  /**
+   * Returns a new list containing the elements between [start] and [end].
+   *
+   * The new list is a `Float32List` containing the elements of this
+   * list at positions greater than or equal to [start] and less than [end] in
+   * the same order as they occur in this list.
+   *
+   * ```dart
+   * var numbers = Float32List.fromList([0, 1, 2, 3, 4]);
+   * print(numbers.sublist(1, 3)); // [1, 2]
+   * print(numbers.sublist(1, 3).runtimeType); // Float32List
+   * ```
+   *
+   * If [end] is omitted, it defaults to the [length] of this list.
+   *
+   * ```dart
+   * print(numbers.sublist(1)); // [1, 2, 3, 4]
+   * ```
+   *
+   * The `start` and `end` positions must satisfy the relations
+   * 0 ≤ `start` ≤ `end` ≤ `this.length`
+   * If `end` is equal to `start`, then the returned list is empty.
+   */
+  Float32List sublist(int start, [int end]);
+
+  static const int bytesPerElement = 4;
+}
+
+/**
+ * A fixed-length list of IEEE 754 double-precision binary floating-point
+ * numbers  that is viewable as a [TypedData].
+ *
+ * For long lists, this
+ * implementation can be considerably more space- and time-efficient than
+ * the default [List] implementation.
+ */
+abstract class Float64List implements List<double>, _TypedFloatList {
+  /**
+   * Creates a [Float64List] of the specified length (in elements), all of
+   * whose elements are initially zero.
+   */
+  external factory Float64List(int length);
+
+  /**
+   * Creates a [Float64List] with the same length as the [elements] list
+   * and copies over the elements.
+   */
+  external factory Float64List.fromList(List<double> elements);
+
+  /**
+   * Creates a [Float64List] _view_ of the specified region in [buffer].
+   *
+   * Changes in the [Float64List] will be visible in the byte
+   * buffer and vice versa.
+   * If the [offsetInBytes] index of the region is not specified,
+   * it defaults to zero (the first byte in the byte buffer).
+   * If the length is not specified, it defaults to `null`,
+   * which indicates that the view extends to the end of the byte buffer.
+   *
+   * Throws [RangeError] if [offsetInBytes] or [length] are negative, or
+   * if [offsetInBytes] + ([length] * elementSizeInBytes) is greater than
+   * the length of [buffer].
+   *
+   * Throws [ArgumentError] if [offsetInBytes] is not a multiple of
+   * [bytesPerElement].
+   */
+  factory Float64List.view(ByteBuffer buffer,
+      [int offsetInBytes = 0, int length]) {
+    return buffer.asFloat64List(offsetInBytes, length);
+  }
+
+  /**
+   * Returns a new list containing the elements between [start] and [end].
+   *
+   * The new list is a `Float64List` containing the elements of this
+   * list at positions greater than or equal to [start] and less than [end] in
+   * the same order as they occur in this list.
+   *
+   * ```dart
+   * var numbers = Float64List.fromList([0, 1, 2, 3, 4]);
+   * print(numbers.sublist(1, 3)); // [1, 2]
+   * print(numbers.sublist(1, 3).runtimeType); // Float64List
+   * ```
+   *
+   * If [end] is omitted, it defaults to the [length] of this list.
+   *
+   * ```dart
+   * print(numbers.sublist(1)); // [1, 2, 3, 4]
+   * ```
+   *
+   * The `start` and `end` positions must satisfy the relations
+   * 0 ≤ `start` ≤ `end` ≤ `this.length`
+   * If `end` is equal to `start`, then the returned list is empty.
+   */
+  Float64List sublist(int start, [int end]);
+
+  static const int bytesPerElement = 8;
+}
+
+/**
+ * A fixed-length list of Float32x4 numbers that is viewable as a
+ * [TypedData].
+ *
+ * For long lists, this implementation will be considerably more
+ * space- and time-efficient than the default [List] implementation.
+ */
+abstract class Float32x4List implements List<Float32x4>, TypedData {
+  /**
+   * Creates a [Float32x4List] of the specified length (in elements),
+   * all of whose elements are initially zero.
+   */
+  external factory Float32x4List(int length);
+
+  /**
+   * Creates a [Float32x4List] with the same length as the [elements] list
+   * and copies over the elements.
+   */
+  external factory Float32x4List.fromList(List<Float32x4> elements);
+
+  /**
+   * Creates a [Float32x4List] _view_ of the specified region in [buffer].
+   *
+   * Changes in the [Float32x4List] will be visible in the byte
+   * buffer and vice versa.
+   * If the [offsetInBytes] index of the region is not specified,
+   * it defaults to zero (the first byte in the byte buffer).
+   * If the length is not specified, it defaults to `null`,
+   * which indicates that the view extends to the end of the byte buffer.
+   *
+   * Throws [RangeError] if [offsetInBytes] or [length] are negative, or
+   * if [offsetInBytes] + ([length] * elementSizeInBytes) is greater than
+   * the length of [buffer].
+   *
+   * Throws [ArgumentError] if [offsetInBytes] is not a multiple of
+   * [bytesPerElement].
+   */
+  factory Float32x4List.view(ByteBuffer buffer,
+      [int offsetInBytes = 0, int length]) {
+    return buffer.asFloat32x4List(offsetInBytes, length);
+  }
+
+  /**
+   * Returns the concatenation of this list and [other].
+   *
+   * If [other] is also a [Float32x4List], the result is a new [Float32x4List],
+   * otherwise the result is a normal growable `List<Float32x4>`.
+   */
+  List<Float32x4> operator +(List<Float32x4> other);
+
+  /**
+   * Returns a new list containing the elements between [start] and [end].
+   *
+   * The new list is a `Float32x4List` containing the elements of this
+   * list at positions greater than or equal to [start] and less than [end] in
+   * the same order as they occur in this list.
+   *
+   * ```dart
+   * var numbers = Float32x4List.fromList([0, 1, 2, 3, 4]);
+   * print(numbers.sublist(1, 3)); // [1, 2]
+   * print(numbers.sublist(1, 3).runtimeType); // Float32x4List
+   * ```
+   *
+   * If [end] is omitted, it defaults to the [length] of this list.
+   *
+   * ```dart
+   * print(numbers.sublist(1)); // [1, 2, 3, 4]
+   * ```
+   *
+   * The `start` and `end` positions must satisfy the relations
+   * 0 ≤ `start` ≤ `end` ≤ `this.length`
+   * If `end` is equal to `start`, then the returned list is empty.
+   */
+  Float32x4List sublist(int start, [int end]);
+
+  static const int bytesPerElement = 16;
+}
+
+/**
+ * A fixed-length list of Int32x4 numbers that is viewable as a
+ * [TypedData].
+ *
+ * For long lists, this implementation will be considerably more
+ * space- and time-efficient than the default [List] implementation.
+ */
+abstract class Int32x4List implements List<Int32x4>, TypedData {
+  /**
+   * Creates a [Int32x4List] of the specified length (in elements),
+   * all of whose elements are initially zero.
+   */
+  external factory Int32x4List(int length);
+
+  /**
+   * Creates a [Int32x4List] with the same length as the [elements] list
+   * and copies over the elements.
+   */
+  external factory Int32x4List.fromList(List<Int32x4> elements);
+
+  /**
+   * Creates a [Int32x4List] _view_ of the specified region in [buffer].
+   *
+   * Changes in the [Int32x4List] will be visible in the byte
+   * buffer and vice versa.
+   * If the [offsetInBytes] index of the region is not specified,
+   * it defaults to zero (the first byte in the byte buffer).
+   * If the length is not specified, it defaults to `null`,
+   * which indicates that the view extends to the end of the byte buffer.
+   *
+   * Throws [RangeError] if [offsetInBytes] or [length] are negative, or
+   * if [offsetInBytes] + ([length] * elementSizeInBytes) is greater than
+   * the length of [buffer].
+   *
+   * Throws [ArgumentError] if [offsetInBytes] is not a multiple of
+   * [bytesPerElement].
+   */
+  factory Int32x4List.view(ByteBuffer buffer,
+      [int offsetInBytes = 0, int length]) {
+    return buffer.asInt32x4List(offsetInBytes, length);
+  }
+
+  /**
+   * Returns the concatenation of this list and [other].
+   *
+   * If [other] is also a [Int32x4List], the result is a new [Int32x4List],
+   * otherwise the result is a normal growable `List<Int32x4>`.
+   */
+  List<Int32x4> operator +(List<Int32x4> other);
+
+  /**
+   * Returns a new list containing the elements between [start] and [end].
+   *
+   * The new list is an `Int32x4list` containing the elements of this
+   * list at positions greater than or equal to [start] and less than [end] in
+   * the same order as they occur in this list.
+   *
+   * ```dart
+   * var numbers = Int32x4list.fromList([0, 1, 2, 3, 4]);
+   * print(numbers.sublist(1, 3)); // [1, 2]
+   * print(numbers.sublist(1, 3).runtimeType); // Int32x4list
+   * ```
+   *
+   * If [end] is omitted, it defaults to the [length] of this list.
+   *
+   * ```dart
+   * print(numbers.sublist(1)); // [1, 2, 3, 4]
+   * ```
+   *
+   * The `start` and `end` positions must satisfy the relations
+   * 0 ≤ `start` ≤ `end` ≤ `this.length`
+   * If `end` is equal to `start`, then the returned list is empty.
+   */
+  Int32x4List sublist(int start, [int end]);
+
+  static const int bytesPerElement = 16;
+}
+
+/**
+ * A fixed-length list of Float64x2 numbers that is viewable as a
+ * [TypedData].
+ *
+ * For long lists, this implementation will be considerably more
+ * space- and time-efficient than the default [List] implementation.
+ */
+abstract class Float64x2List implements List<Float64x2>, TypedData {
+  /**
+   * Creates a [Float64x2List] of the specified length (in elements),
+   * all of whose elements have all lanes set to zero.
+   */
+  external factory Float64x2List(int length);
+
+  /**
+   * Creates a [Float64x2List] with the same length as the [elements] list
+   * and copies over the elements.
+   */
+  external factory Float64x2List.fromList(List<Float64x2> elements);
+
+  /**
+   * Returns the concatenation of this list and [other].
+   *
+   * If [other] is also a [Float64x2List], the result is a new [Float64x2List],
+   * otherwise the result is a normal growable `List<Float64x2>`.
+   */
+  List<Float64x2> operator +(List<Float64x2> other);
+
+  /**
+   * Creates a [Float64x2List] _view_ of the specified region in [buffer].
+   *
+   * Changes in the [Float64x2List] will be visible in the byte
+   * buffer and vice versa.
+   * If the [offsetInBytes] index of the region is not specified,
+   * it defaults to zero (the first byte in the byte buffer).
+   * If the length is not specified, it defaults to `null`,
+   * which indicates that the view extends to the end of the byte buffer.
+   *
+   * Throws [RangeError] if [offsetInBytes] or [length] are negative, or
+   * if [offsetInBytes] + ([length] * elementSizeInBytes) is greater than
+   * the length of [buffer].
+   *
+   * Throws [ArgumentError] if [offsetInBytes] is not a multiple of
+   * [bytesPerElement].
+   */
+  factory Float64x2List.view(ByteBuffer buffer,
+      [int offsetInBytes = 0, int length]) {
+    return buffer.asFloat64x2List(offsetInBytes, length);
+  }
+
+  /**
+   * Returns a new list containing the elements between [start] and [end].
+   *
+   * The new list is a `Float64x2List` containing the elements of this
+   * list at positions greater than or equal to [start] and less than [end] in
+   * the same order as they occur in this list.
+   *
+   * ```dart
+   * var numbers = Float64x2List.fromList([0, 1, 2, 3, 4]);
+   * print(numbers.sublist(1, 3)); // [1, 2]
+   * print(numbers.sublist(1, 3).runtimeType); // Float64x2List
+   * ```
+   *
+   * If [end] is omitted, it defaults to the [length] of this list.
+   *
+   * ```dart
+   * print(numbers.sublist(1)); // [1, 2, 3, 4]
+   * ```
+   *
+   * The `start` and `end` positions must satisfy the relations
+   * 0 ≤ `start` ≤ `end` ≤ `this.length`
+   * If `end` is equal to `start`, then the returned list is empty.
+   */
+  Float64x2List sublist(int start, [int end]);
+
+  static const int bytesPerElement = 16;
+}
+
+/**
+ * Float32x4 immutable value type and operations.
+ *
+ * Float32x4 stores 4 32-bit floating point values in "lanes".
+ * The lanes are "x", "y", "z", and "w" respectively.
+ */
+abstract class Float32x4 {
+  external factory Float32x4(double x, double y, double z, double w);
+  external factory Float32x4.splat(double v);
+  external factory Float32x4.zero();
+  external factory Float32x4.fromInt32x4Bits(Int32x4 x);
+
+  /// Sets the x and y lanes to their respective values in [v] and sets the z
+  /// and w lanes to 0.0.
+  external factory Float32x4.fromFloat64x2(Float64x2 v);
+
+  /// Addition operator.
+  Float32x4 operator +(Float32x4 other);
+
+  /// Negate operator.
+  Float32x4 operator -();
+
+  /// Subtraction operator.
+  Float32x4 operator -(Float32x4 other);
+
+  /// Multiplication operator.
+  Float32x4 operator *(Float32x4 other);
+
+  /// Division operator.
+  Float32x4 operator /(Float32x4 other);
+
+  /// Relational less than.
+  Int32x4 lessThan(Float32x4 other);
+
+  /// Relational less than or equal.
+  Int32x4 lessThanOrEqual(Float32x4 other);
+
+  /// Relational greater than.
+  Int32x4 greaterThan(Float32x4 other);
+
+  /// Relational greater than or equal.
+  Int32x4 greaterThanOrEqual(Float32x4 other);
+
+  /// Relational equal.
+  Int32x4 equal(Float32x4 other);
+
+  /// Relational not-equal.
+  Int32x4 notEqual(Float32x4 other);
+
+  /// Returns a copy of [this] each lane being scaled by [s].
+  /// Equivalent to this * new Float32x4.splat(s)
+  Float32x4 scale(double s);
+
+  /// Returns the lane-wise absolute value of this [Float32x4].
+  Float32x4 abs();
+
+  /// Lane-wise clamp [this] to be in the range [lowerLimit]-[upperLimit].
+  Float32x4 clamp(Float32x4 lowerLimit, Float32x4 upperLimit);
+
+  /// Extracted x value.
+  double get x;
+
+  /// Extracted y value.
+  double get y;
+
+  /// Extracted z value.
+  double get z;
+
+  /// Extracted w value.
+  double get w;
+
+  /// Extract the sign bits from each lane return them in the first 4 bits.
+  /// "x" lane is bit 0.
+  /// "y" lane is bit 1.
+  /// "z" lane is bit 2.
+  /// "w" lane is bit 3.
+  int get signMask;
+
+  /// Mask passed to [shuffle] or [shuffleMix].
+  static const int xxxx = 0x0;
+  static const int xxxy = 0x40;
+  static const int xxxz = 0x80;
+  static const int xxxw = 0xC0;
+  static const int xxyx = 0x10;
+  static const int xxyy = 0x50;
+  static const int xxyz = 0x90;
+  static const int xxyw = 0xD0;
+  static const int xxzx = 0x20;
+  static const int xxzy = 0x60;
+  static const int xxzz = 0xA0;
+  static const int xxzw = 0xE0;
+  static const int xxwx = 0x30;
+  static const int xxwy = 0x70;
+  static const int xxwz = 0xB0;
+  static const int xxww = 0xF0;
+  static const int xyxx = 0x4;
+  static const int xyxy = 0x44;
+  static const int xyxz = 0x84;
+  static const int xyxw = 0xC4;
+  static const int xyyx = 0x14;
+  static const int xyyy = 0x54;
+  static const int xyyz = 0x94;
+  static const int xyyw = 0xD4;
+  static const int xyzx = 0x24;
+  static const int xyzy = 0x64;
+  static const int xyzz = 0xA4;
+  static const int xyzw = 0xE4;
+  static const int xywx = 0x34;
+  static const int xywy = 0x74;
+  static const int xywz = 0xB4;
+  static const int xyww = 0xF4;
+  static const int xzxx = 0x8;
+  static const int xzxy = 0x48;
+  static const int xzxz = 0x88;
+  static const int xzxw = 0xC8;
+  static const int xzyx = 0x18;
+  static const int xzyy = 0x58;
+  static const int xzyz = 0x98;
+  static const int xzyw = 0xD8;
+  static const int xzzx = 0x28;
+  static const int xzzy = 0x68;
+  static const int xzzz = 0xA8;
+  static const int xzzw = 0xE8;
+  static const int xzwx = 0x38;
+  static const int xzwy = 0x78;
+  static const int xzwz = 0xB8;
+  static const int xzww = 0xF8;
+  static const int xwxx = 0xC;
+  static const int xwxy = 0x4C;
+  static const int xwxz = 0x8C;
+  static const int xwxw = 0xCC;
+  static const int xwyx = 0x1C;
+  static const int xwyy = 0x5C;
+  static const int xwyz = 0x9C;
+  static const int xwyw = 0xDC;
+  static const int xwzx = 0x2C;
+  static const int xwzy = 0x6C;
+  static const int xwzz = 0xAC;
+  static const int xwzw = 0xEC;
+  static const int xwwx = 0x3C;
+  static const int xwwy = 0x7C;
+  static const int xwwz = 0xBC;
+  static const int xwww = 0xFC;
+  static const int yxxx = 0x1;
+  static const int yxxy = 0x41;
+  static const int yxxz = 0x81;
+  static const int yxxw = 0xC1;
+  static const int yxyx = 0x11;
+  static const int yxyy = 0x51;
+  static const int yxyz = 0x91;
+  static const int yxyw = 0xD1;
+  static const int yxzx = 0x21;
+  static const int yxzy = 0x61;
+  static const int yxzz = 0xA1;
+  static const int yxzw = 0xE1;
+  static const int yxwx = 0x31;
+  static const int yxwy = 0x71;
+  static const int yxwz = 0xB1;
+  static const int yxww = 0xF1;
+  static const int yyxx = 0x5;
+  static const int yyxy = 0x45;
+  static const int yyxz = 0x85;
+  static const int yyxw = 0xC5;
+  static const int yyyx = 0x15;
+  static const int yyyy = 0x55;
+  static const int yyyz = 0x95;
+  static const int yyyw = 0xD5;
+  static const int yyzx = 0x25;
+  static const int yyzy = 0x65;
+  static const int yyzz = 0xA5;
+  static const int yyzw = 0xE5;
+  static const int yywx = 0x35;
+  static const int yywy = 0x75;
+  static const int yywz = 0xB5;
+  static const int yyww = 0xF5;
+  static const int yzxx = 0x9;
+  static const int yzxy = 0x49;
+  static const int yzxz = 0x89;
+  static const int yzxw = 0xC9;
+  static const int yzyx = 0x19;
+  static const int yzyy = 0x59;
+  static const int yzyz = 0x99;
+  static const int yzyw = 0xD9;
+  static const int yzzx = 0x29;
+  static const int yzzy = 0x69;
+  static const int yzzz = 0xA9;
+  static const int yzzw = 0xE9;
+  static const int yzwx = 0x39;
+  static const int yzwy = 0x79;
+  static const int yzwz = 0xB9;
+  static const int yzww = 0xF9;
+  static const int ywxx = 0xD;
+  static const int ywxy = 0x4D;
+  static const int ywxz = 0x8D;
+  static const int ywxw = 0xCD;
+  static const int ywyx = 0x1D;
+  static const int ywyy = 0x5D;
+  static const int ywyz = 0x9D;
+  static const int ywyw = 0xDD;
+  static const int ywzx = 0x2D;
+  static const int ywzy = 0x6D;
+  static const int ywzz = 0xAD;
+  static const int ywzw = 0xED;
+  static const int ywwx = 0x3D;
+  static const int ywwy = 0x7D;
+  static const int ywwz = 0xBD;
+  static const int ywww = 0xFD;
+  static const int zxxx = 0x2;
+  static const int zxxy = 0x42;
+  static const int zxxz = 0x82;
+  static const int zxxw = 0xC2;
+  static const int zxyx = 0x12;
+  static const int zxyy = 0x52;
+  static const int zxyz = 0x92;
+  static const int zxyw = 0xD2;
+  static const int zxzx = 0x22;
+  static const int zxzy = 0x62;
+  static const int zxzz = 0xA2;
+  static const int zxzw = 0xE2;
+  static const int zxwx = 0x32;
+  static const int zxwy = 0x72;
+  static const int zxwz = 0xB2;
+  static const int zxww = 0xF2;
+  static const int zyxx = 0x6;
+  static const int zyxy = 0x46;
+  static const int zyxz = 0x86;
+  static const int zyxw = 0xC6;
+  static const int zyyx = 0x16;
+  static const int zyyy = 0x56;
+  static const int zyyz = 0x96;
+  static const int zyyw = 0xD6;
+  static const int zyzx = 0x26;
+  static const int zyzy = 0x66;
+  static const int zyzz = 0xA6;
+  static const int zyzw = 0xE6;
+  static const int zywx = 0x36;
+  static const int zywy = 0x76;
+  static const int zywz = 0xB6;
+  static const int zyww = 0xF6;
+  static const int zzxx = 0xA;
+  static const int zzxy = 0x4A;
+  static const int zzxz = 0x8A;
+  static const int zzxw = 0xCA;
+  static const int zzyx = 0x1A;
+  static const int zzyy = 0x5A;
+  static const int zzyz = 0x9A;
+  static const int zzyw = 0xDA;
+  static const int zzzx = 0x2A;
+  static const int zzzy = 0x6A;
+  static const int zzzz = 0xAA;
+  static const int zzzw = 0xEA;
+  static const int zzwx = 0x3A;
+  static const int zzwy = 0x7A;
+  static const int zzwz = 0xBA;
+  static const int zzww = 0xFA;
+  static const int zwxx = 0xE;
+  static const int zwxy = 0x4E;
+  static const int zwxz = 0x8E;
+  static const int zwxw = 0xCE;
+  static const int zwyx = 0x1E;
+  static const int zwyy = 0x5E;
+  static const int zwyz = 0x9E;
+  static const int zwyw = 0xDE;
+  static const int zwzx = 0x2E;
+  static const int zwzy = 0x6E;
+  static const int zwzz = 0xAE;
+  static const int zwzw = 0xEE;
+  static const int zwwx = 0x3E;
+  static const int zwwy = 0x7E;
+  static const int zwwz = 0xBE;
+  static const int zwww = 0xFE;
+  static const int wxxx = 0x3;
+  static const int wxxy = 0x43;
+  static const int wxxz = 0x83;
+  static const int wxxw = 0xC3;
+  static const int wxyx = 0x13;
+  static const int wxyy = 0x53;
+  static const int wxyz = 0x93;
+  static const int wxyw = 0xD3;
+  static const int wxzx = 0x23;
+  static const int wxzy = 0x63;
+  static const int wxzz = 0xA3;
+  static const int wxzw = 0xE3;
+  static const int wxwx = 0x33;
+  static const int wxwy = 0x73;
+  static const int wxwz = 0xB3;
+  static const int wxww = 0xF3;
+  static const int wyxx = 0x7;
+  static const int wyxy = 0x47;
+  static const int wyxz = 0x87;
+  static const int wyxw = 0xC7;
+  static const int wyyx = 0x17;
+  static const int wyyy = 0x57;
+  static const int wyyz = 0x97;
+  static const int wyyw = 0xD7;
+  static const int wyzx = 0x27;
+  static const int wyzy = 0x67;
+  static const int wyzz = 0xA7;
+  static const int wyzw = 0xE7;
+  static const int wywx = 0x37;
+  static const int wywy = 0x77;
+  static const int wywz = 0xB7;
+  static const int wyww = 0xF7;
+  static const int wzxx = 0xB;
+  static const int wzxy = 0x4B;
+  static const int wzxz = 0x8B;
+  static const int wzxw = 0xCB;
+  static const int wzyx = 0x1B;
+  static const int wzyy = 0x5B;
+  static const int wzyz = 0x9B;
+  static const int wzyw = 0xDB;
+  static const int wzzx = 0x2B;
+  static const int wzzy = 0x6B;
+  static const int wzzz = 0xAB;
+  static const int wzzw = 0xEB;
+  static const int wzwx = 0x3B;
+  static const int wzwy = 0x7B;
+  static const int wzwz = 0xBB;
+  static const int wzww = 0xFB;
+  static const int wwxx = 0xF;
+  static const int wwxy = 0x4F;
+  static const int wwxz = 0x8F;
+  static const int wwxw = 0xCF;
+  static const int wwyx = 0x1F;
+  static const int wwyy = 0x5F;
+  static const int wwyz = 0x9F;
+  static const int wwyw = 0xDF;
+  static const int wwzx = 0x2F;
+  static const int wwzy = 0x6F;
+  static const int wwzz = 0xAF;
+  static const int wwzw = 0xEF;
+  static const int wwwx = 0x3F;
+  static const int wwwy = 0x7F;
+  static const int wwwz = 0xBF;
+  static const int wwww = 0xFF;
+
+  /// Shuffle the lane values. [mask] must be one of the 256 shuffle constants.
+  Float32x4 shuffle(int mask);
+
+  /// Shuffle the lane values in [this] and [other]. The returned
+  /// Float32x4 will have XY lanes from [this] and ZW lanes from [other].
+  /// Uses the same [mask] as [shuffle].
+  Float32x4 shuffleMix(Float32x4 other, int mask);
+
+  /// Returns a new [Float32x4] copied from [this] with a new x value.
+  Float32x4 withX(double x);
+
+  /// Returns a new [Float32x4] copied from [this] with a new y value.
+  Float32x4 withY(double y);
+
+  /// Returns a new [Float32x4] copied from [this] with a new z value.
+  Float32x4 withZ(double z);
+
+  /// Returns a new [Float32x4] copied from [this] with a new w value.
+  Float32x4 withW(double w);
+
+  /// Returns the lane-wise minimum value in [this] or [other].
+  Float32x4 min(Float32x4 other);
+
+  /// Returns the lane-wise maximum value in [this] or [other].
+  Float32x4 max(Float32x4 other);
+
+  /// Returns the square root of [this].
+  Float32x4 sqrt();
+
+  /// Returns the reciprocal of [this].
+  Float32x4 reciprocal();
+
+  /// Returns the square root of the reciprocal of [this].
+  Float32x4 reciprocalSqrt();
+}
+
+/**
+ * Int32x4 and operations.
+ *
+ * Int32x4 stores 4 32-bit bit-masks in "lanes".
+ * The lanes are "x", "y", "z", and "w" respectively.
+ */
+abstract class Int32x4 {
+  external factory Int32x4(int x, int y, int z, int w);
+  external factory Int32x4.bool(bool x, bool y, bool z, bool w);
+  external factory Int32x4.fromFloat32x4Bits(Float32x4 x);
+
+  /// The bit-wise or operator.
+  Int32x4 operator |(Int32x4 other);
+
+  /// The bit-wise and operator.
+  Int32x4 operator &(Int32x4 other);
+
+  /// The bit-wise xor operator.
+  Int32x4 operator ^(Int32x4 other);
+
+  /// Addition operator.
+  Int32x4 operator +(Int32x4 other);
+
+  /// Subtraction operator.
+  Int32x4 operator -(Int32x4 other);
+
+  /// Extract 32-bit mask from x lane.
+  int get x;
+
+  /// Extract 32-bit mask from y lane.
+  int get y;
+
+  /// Extract 32-bit mask from z lane.
+  int get z;
+
+  /// Extract 32-bit mask from w lane.
+  int get w;
+
+  /// Extract the top bit from each lane return them in the first 4 bits.
+  /// "x" lane is bit 0.
+  /// "y" lane is bit 1.
+  /// "z" lane is bit 2.
+  /// "w" lane is bit 3.
+  int get signMask;
+
+  /// Mask passed to [shuffle] or [shuffleMix].
+  static const int xxxx = 0x0;
+  static const int xxxy = 0x40;
+  static const int xxxz = 0x80;
+  static const int xxxw = 0xC0;
+  static const int xxyx = 0x10;
+  static const int xxyy = 0x50;
+  static const int xxyz = 0x90;
+  static const int xxyw = 0xD0;
+  static const int xxzx = 0x20;
+  static const int xxzy = 0x60;
+  static const int xxzz = 0xA0;
+  static const int xxzw = 0xE0;
+  static const int xxwx = 0x30;
+  static const int xxwy = 0x70;
+  static const int xxwz = 0xB0;
+  static const int xxww = 0xF0;
+  static const int xyxx = 0x4;
+  static const int xyxy = 0x44;
+  static const int xyxz = 0x84;
+  static const int xyxw = 0xC4;
+  static const int xyyx = 0x14;
+  static const int xyyy = 0x54;
+  static const int xyyz = 0x94;
+  static const int xyyw = 0xD4;
+  static const int xyzx = 0x24;
+  static const int xyzy = 0x64;
+  static const int xyzz = 0xA4;
+  static const int xyzw = 0xE4;
+  static const int xywx = 0x34;
+  static const int xywy = 0x74;
+  static const int xywz = 0xB4;
+  static const int xyww = 0xF4;
+  static const int xzxx = 0x8;
+  static const int xzxy = 0x48;
+  static const int xzxz = 0x88;
+  static const int xzxw = 0xC8;
+  static const int xzyx = 0x18;
+  static const int xzyy = 0x58;
+  static const int xzyz = 0x98;
+  static const int xzyw = 0xD8;
+  static const int xzzx = 0x28;
+  static const int xzzy = 0x68;
+  static const int xzzz = 0xA8;
+  static const int xzzw = 0xE8;
+  static const int xzwx = 0x38;
+  static const int xzwy = 0x78;
+  static const int xzwz = 0xB8;
+  static const int xzww = 0xF8;
+  static const int xwxx = 0xC;
+  static const int xwxy = 0x4C;
+  static const int xwxz = 0x8C;
+  static const int xwxw = 0xCC;
+  static const int xwyx = 0x1C;
+  static const int xwyy = 0x5C;
+  static const int xwyz = 0x9C;
+  static const int xwyw = 0xDC;
+  static const int xwzx = 0x2C;
+  static const int xwzy = 0x6C;
+  static const int xwzz = 0xAC;
+  static const int xwzw = 0xEC;
+  static const int xwwx = 0x3C;
+  static const int xwwy = 0x7C;
+  static const int xwwz = 0xBC;
+  static const int xwww = 0xFC;
+  static const int yxxx = 0x1;
+  static const int yxxy = 0x41;
+  static const int yxxz = 0x81;
+  static const int yxxw = 0xC1;
+  static const int yxyx = 0x11;
+  static const int yxyy = 0x51;
+  static const int yxyz = 0x91;
+  static const int yxyw = 0xD1;
+  static const int yxzx = 0x21;
+  static const int yxzy = 0x61;
+  static const int yxzz = 0xA1;
+  static const int yxzw = 0xE1;
+  static const int yxwx = 0x31;
+  static const int yxwy = 0x71;
+  static const int yxwz = 0xB1;
+  static const int yxww = 0xF1;
+  static const int yyxx = 0x5;
+  static const int yyxy = 0x45;
+  static const int yyxz = 0x85;
+  static const int yyxw = 0xC5;
+  static const int yyyx = 0x15;
+  static const int yyyy = 0x55;
+  static const int yyyz = 0x95;
+  static const int yyyw = 0xD5;
+  static const int yyzx = 0x25;
+  static const int yyzy = 0x65;
+  static const int yyzz = 0xA5;
+  static const int yyzw = 0xE5;
+  static const int yywx = 0x35;
+  static const int yywy = 0x75;
+  static const int yywz = 0xB5;
+  static const int yyww = 0xF5;
+  static const int yzxx = 0x9;
+  static const int yzxy = 0x49;
+  static const int yzxz = 0x89;
+  static const int yzxw = 0xC9;
+  static const int yzyx = 0x19;
+  static const int yzyy = 0x59;
+  static const int yzyz = 0x99;
+  static const int yzyw = 0xD9;
+  static const int yzzx = 0x29;
+  static const int yzzy = 0x69;
+  static const int yzzz = 0xA9;
+  static const int yzzw = 0xE9;
+  static const int yzwx = 0x39;
+  static const int yzwy = 0x79;
+  static const int yzwz = 0xB9;
+  static const int yzww = 0xF9;
+  static const int ywxx = 0xD;
+  static const int ywxy = 0x4D;
+  static const int ywxz = 0x8D;
+  static const int ywxw = 0xCD;
+  static const int ywyx = 0x1D;
+  static const int ywyy = 0x5D;
+  static const int ywyz = 0x9D;
+  static const int ywyw = 0xDD;
+  static const int ywzx = 0x2D;
+  static const int ywzy = 0x6D;
+  static const int ywzz = 0xAD;
+  static const int ywzw = 0xED;
+  static const int ywwx = 0x3D;
+  static const int ywwy = 0x7D;
+  static const int ywwz = 0xBD;
+  static const int ywww = 0xFD;
+  static const int zxxx = 0x2;
+  static const int zxxy = 0x42;
+  static const int zxxz = 0x82;
+  static const int zxxw = 0xC2;
+  static const int zxyx = 0x12;
+  static const int zxyy = 0x52;
+  static const int zxyz = 0x92;
+  static const int zxyw = 0xD2;
+  static const int zxzx = 0x22;
+  static const int zxzy = 0x62;
+  static const int zxzz = 0xA2;
+  static const int zxzw = 0xE2;
+  static const int zxwx = 0x32;
+  static const int zxwy = 0x72;
+  static const int zxwz = 0xB2;
+  static const int zxww = 0xF2;
+  static const int zyxx = 0x6;
+  static const int zyxy = 0x46;
+  static const int zyxz = 0x86;
+  static const int zyxw = 0xC6;
+  static const int zyyx = 0x16;
+  static const int zyyy = 0x56;
+  static const int zyyz = 0x96;
+  static const int zyyw = 0xD6;
+  static const int zyzx = 0x26;
+  static const int zyzy = 0x66;
+  static const int zyzz = 0xA6;
+  static const int zyzw = 0xE6;
+  static const int zywx = 0x36;
+  static const int zywy = 0x76;
+  static const int zywz = 0xB6;
+  static const int zyww = 0xF6;
+  static const int zzxx = 0xA;
+  static const int zzxy = 0x4A;
+  static const int zzxz = 0x8A;
+  static const int zzxw = 0xCA;
+  static const int zzyx = 0x1A;
+  static const int zzyy = 0x5A;
+  static const int zzyz = 0x9A;
+  static const int zzyw = 0xDA;
+  static const int zzzx = 0x2A;
+  static const int zzzy = 0x6A;
+  static const int zzzz = 0xAA;
+  static const int zzzw = 0xEA;
+  static const int zzwx = 0x3A;
+  static const int zzwy = 0x7A;
+  static const int zzwz = 0xBA;
+  static const int zzww = 0xFA;
+  static const int zwxx = 0xE;
+  static const int zwxy = 0x4E;
+  static const int zwxz = 0x8E;
+  static const int zwxw = 0xCE;
+  static const int zwyx = 0x1E;
+  static const int zwyy = 0x5E;
+  static const int zwyz = 0x9E;
+  static const int zwyw = 0xDE;
+  static const int zwzx = 0x2E;
+  static const int zwzy = 0x6E;
+  static const int zwzz = 0xAE;
+  static const int zwzw = 0xEE;
+  static const int zwwx = 0x3E;
+  static const int zwwy = 0x7E;
+  static const int zwwz = 0xBE;
+  static const int zwww = 0xFE;
+  static const int wxxx = 0x3;
+  static const int wxxy = 0x43;
+  static const int wxxz = 0x83;
+  static const int wxxw = 0xC3;
+  static const int wxyx = 0x13;
+  static const int wxyy = 0x53;
+  static const int wxyz = 0x93;
+  static const int wxyw = 0xD3;
+  static const int wxzx = 0x23;
+  static const int wxzy = 0x63;
+  static const int wxzz = 0xA3;
+  static const int wxzw = 0xE3;
+  static const int wxwx = 0x33;
+  static const int wxwy = 0x73;
+  static const int wxwz = 0xB3;
+  static const int wxww = 0xF3;
+  static const int wyxx = 0x7;
+  static const int wyxy = 0x47;
+  static const int wyxz = 0x87;
+  static const int wyxw = 0xC7;
+  static const int wyyx = 0x17;
+  static const int wyyy = 0x57;
+  static const int wyyz = 0x97;
+  static const int wyyw = 0xD7;
+  static const int wyzx = 0x27;
+  static const int wyzy = 0x67;
+  static const int wyzz = 0xA7;
+  static const int wyzw = 0xE7;
+  static const int wywx = 0x37;
+  static const int wywy = 0x77;
+  static const int wywz = 0xB7;
+  static const int wyww = 0xF7;
+  static const int wzxx = 0xB;
+  static const int wzxy = 0x4B;
+  static const int wzxz = 0x8B;
+  static const int wzxw = 0xCB;
+  static const int wzyx = 0x1B;
+  static const int wzyy = 0x5B;
+  static const int wzyz = 0x9B;
+  static const int wzyw = 0xDB;
+  static const int wzzx = 0x2B;
+  static const int wzzy = 0x6B;
+  static const int wzzz = 0xAB;
+  static const int wzzw = 0xEB;
+  static const int wzwx = 0x3B;
+  static const int wzwy = 0x7B;
+  static const int wzwz = 0xBB;
+  static const int wzww = 0xFB;
+  static const int wwxx = 0xF;
+  static const int wwxy = 0x4F;
+  static const int wwxz = 0x8F;
+  static const int wwxw = 0xCF;
+  static const int wwyx = 0x1F;
+  static const int wwyy = 0x5F;
+  static const int wwyz = 0x9F;
+  static const int wwyw = 0xDF;
+  static const int wwzx = 0x2F;
+  static const int wwzy = 0x6F;
+  static const int wwzz = 0xAF;
+  static const int wwzw = 0xEF;
+  static const int wwwx = 0x3F;
+  static const int wwwy = 0x7F;
+  static const int wwwz = 0xBF;
+  static const int wwww = 0xFF;
+
+  /// Shuffle the lane values. [mask] must be one of the 256 shuffle constants.
+  Int32x4 shuffle(int mask);
+
+  /// Shuffle the lane values in [this] and [other]. The returned
+  /// Int32x4 will have XY lanes from [this] and ZW lanes from [other].
+  /// Uses the same [mask] as [shuffle].
+  Int32x4 shuffleMix(Int32x4 other, int mask);
+
+  /// Returns a new [Int32x4] copied from [this] with a new x value.
+  Int32x4 withX(int x);
+
+  /// Returns a new [Int32x4] copied from [this] with a new y value.
+  Int32x4 withY(int y);
+
+  /// Returns a new [Int32x4] copied from [this] with a new z value.
+  Int32x4 withZ(int z);
+
+  /// Returns a new [Int32x4] copied from [this] with a new w value.
+  Int32x4 withW(int w);
+
+  /// Extracted x value. Returns false for 0, true for any other value.
+  bool get flagX;
+
+  /// Extracted y value. Returns false for 0, true for any other value.
+  bool get flagY;
+
+  /// Extracted z value. Returns false for 0, true for any other value.
+  bool get flagZ;
+
+  /// Extracted w value. Returns false for 0, true for any other value.
+  bool get flagW;
+
+  /// Returns a new [Int32x4] copied from [this] with a new x value.
+  Int32x4 withFlagX(bool x);
+
+  /// Returns a new [Int32x4] copied from [this] with a new y value.
+  Int32x4 withFlagY(bool y);
+
+  /// Returns a new [Int32x4] copied from [this] with a new z value.
+  Int32x4 withFlagZ(bool z);
+
+  /// Returns a new [Int32x4] copied from [this] with a new w value.
+  Int32x4 withFlagW(bool w);
+
+  /// Merge [trueValue] and [falseValue] based on [this]' bit mask:
+  /// Select bit from [trueValue] when bit in [this] is on.
+  /// Select bit from [falseValue] when bit in [this] is off.
+  Float32x4 select(Float32x4 trueValue, Float32x4 falseValue);
+}
+
+/**
+ * Float64x2 immutable value type and operations.
+ *
+ * Float64x2 stores 2 64-bit floating point values in "lanes".
+ * The lanes are "x" and "y" respectively.
+ */
+abstract class Float64x2 {
+  external factory Float64x2(double x, double y);
+  external factory Float64x2.splat(double v);
+  external factory Float64x2.zero();
+
+  /// Uses the "x" and "y" lanes from [v].
+  external factory Float64x2.fromFloat32x4(Float32x4 v);
+
+  /// Addition operator.
+  Float64x2 operator +(Float64x2 other);
+
+  /// Negate operator.
+  Float64x2 operator -();
+
+  /// Subtraction operator.
+  Float64x2 operator -(Float64x2 other);
+
+  /// Multiplication operator.
+  Float64x2 operator *(Float64x2 other);
+
+  /// Division operator.
+  Float64x2 operator /(Float64x2 other);
+
+  /// Returns a copy of [this] each lane being scaled by [s].
+  /// Equivalent to this * new Float64x2.splat(s)
+  Float64x2 scale(double s);
+
+  /// Returns the lane-wise absolute value of this [Float64x2].
+  Float64x2 abs();
+
+  /// Lane-wise clamp [this] to be in the range [lowerLimit]-[upperLimit].
+  Float64x2 clamp(Float64x2 lowerLimit, Float64x2 upperLimit);
+
+  /// Extracted x value.
+  double get x;
+
+  /// Extracted y value.
+  double get y;
+
+  /// Extract the sign bits from each lane return them in the first 2 bits.
+  /// "x" lane is bit 0.
+  /// "y" lane is bit 1.
+  int get signMask;
+
+  /// Returns a new [Float64x2] copied from [this] with a new x value.
+  Float64x2 withX(double x);
+
+  /// Returns a new [Float64x2] copied from [this] with a new y value.
+  Float64x2 withY(double y);
+
+  /// Returns the lane-wise minimum value in [this] or [other].
+  Float64x2 min(Float64x2 other);
+
+  /// Returns the lane-wise maximum value in [this] or [other].
+  Float64x2 max(Float64x2 other);
+
+  /// Returns the lane-wise square root of [this].
+  Float64x2 sqrt();
+}
diff --git a/sdk_nnbd/lib/typed_data/typed_data_sources.gni b/sdk_nnbd/lib/typed_data/typed_data_sources.gni
new file mode 100644
index 0000000..23ba0f0
--- /dev/null
+++ b/sdk_nnbd/lib/typed_data/typed_data_sources.gni
@@ -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.
+
+typed_data_sdk_sources = [
+  "typed_data.dart",
+  # The above file needs to be first if additional parts are added to the lib.
+  "unmodifiable_typed_data.dart",
+]
diff --git a/sdk_nnbd/lib/typed_data/unmodifiable_typed_data.dart b/sdk_nnbd/lib/typed_data/unmodifiable_typed_data.dart
new file mode 100644
index 0000000..3549041
--- /dev/null
+++ b/sdk_nnbd/lib/typed_data/unmodifiable_typed_data.dart
@@ -0,0 +1,341 @@
+// 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.
+
+part of dart.typed_data;
+
+/**
+ * A read-only view of a [ByteBuffer].
+ */
+class UnmodifiableByteBufferView implements ByteBuffer {
+  final ByteBuffer _data;
+
+  UnmodifiableByteBufferView(ByteBuffer data) : _data = data;
+
+  int get lengthInBytes => _data.lengthInBytes;
+
+  Uint8List asUint8List([int offsetInBytes = 0, int length]) =>
+      new UnmodifiableUint8ListView(_data.asUint8List(offsetInBytes, length));
+
+  Int8List asInt8List([int offsetInBytes = 0, int length]) =>
+      new UnmodifiableInt8ListView(_data.asInt8List(offsetInBytes, length));
+
+  Uint8ClampedList asUint8ClampedList([int offsetInBytes = 0, int length]) =>
+      new UnmodifiableUint8ClampedListView(
+          _data.asUint8ClampedList(offsetInBytes, length));
+
+  Uint16List asUint16List([int offsetInBytes = 0, int length]) =>
+      new UnmodifiableUint16ListView(_data.asUint16List(offsetInBytes, length));
+
+  Int16List asInt16List([int offsetInBytes = 0, int length]) =>
+      new UnmodifiableInt16ListView(_data.asInt16List(offsetInBytes, length));
+
+  Uint32List asUint32List([int offsetInBytes = 0, int length]) =>
+      new UnmodifiableUint32ListView(_data.asUint32List(offsetInBytes, length));
+
+  Int32List asInt32List([int offsetInBytes = 0, int length]) =>
+      new UnmodifiableInt32ListView(_data.asInt32List(offsetInBytes, length));
+
+  Uint64List asUint64List([int offsetInBytes = 0, int length]) =>
+      new UnmodifiableUint64ListView(_data.asUint64List(offsetInBytes, length));
+
+  Int64List asInt64List([int offsetInBytes = 0, int length]) =>
+      new UnmodifiableInt64ListView(_data.asInt64List(offsetInBytes, length));
+
+  Int32x4List asInt32x4List([int offsetInBytes = 0, int length]) =>
+      new UnmodifiableInt32x4ListView(
+          _data.asInt32x4List(offsetInBytes, length));
+
+  Float32List asFloat32List([int offsetInBytes = 0, int length]) =>
+      new UnmodifiableFloat32ListView(
+          _data.asFloat32List(offsetInBytes, length));
+
+  Float64List asFloat64List([int offsetInBytes = 0, int length]) =>
+      new UnmodifiableFloat64ListView(
+          _data.asFloat64List(offsetInBytes, length));
+
+  Float32x4List asFloat32x4List([int offsetInBytes = 0, int length]) =>
+      new UnmodifiableFloat32x4ListView(
+          _data.asFloat32x4List(offsetInBytes, length));
+
+  Float64x2List asFloat64x2List([int offsetInBytes = 0, int length]) =>
+      new UnmodifiableFloat64x2ListView(
+          _data.asFloat64x2List(offsetInBytes, length));
+
+  ByteData asByteData([int offsetInBytes = 0, int length]) =>
+      new UnmodifiableByteDataView(_data.asByteData(offsetInBytes, length));
+}
+
+/**
+ * A read-only view of a [ByteData].
+ */
+class UnmodifiableByteDataView implements ByteData {
+  final ByteData _data;
+
+  UnmodifiableByteDataView(ByteData data) : _data = data;
+
+  int getInt8(int byteOffset) => _data.getInt8(byteOffset);
+
+  void setInt8(int byteOffset, int value) => _unsupported();
+
+  int getUint8(int byteOffset) => _data.getUint8(byteOffset);
+
+  void setUint8(int byteOffset, int value) => _unsupported();
+
+  int getInt16(int byteOffset, [Endian endian = Endian.big]) =>
+      _data.getInt16(byteOffset, endian);
+
+  void setInt16(int byteOffset, int value, [Endian endian = Endian.big]) =>
+      _unsupported();
+
+  int getUint16(int byteOffset, [Endian endian = Endian.big]) =>
+      _data.getUint16(byteOffset, endian);
+
+  void setUint16(int byteOffset, int value, [Endian endian = Endian.big]) =>
+      _unsupported();
+
+  int getInt32(int byteOffset, [Endian endian = Endian.big]) =>
+      _data.getInt32(byteOffset, endian);
+
+  void setInt32(int byteOffset, int value, [Endian endian = Endian.big]) =>
+      _unsupported();
+
+  int getUint32(int byteOffset, [Endian endian = Endian.big]) =>
+      _data.getUint32(byteOffset, endian);
+
+  void setUint32(int byteOffset, int value, [Endian endian = Endian.big]) =>
+      _unsupported();
+
+  int getInt64(int byteOffset, [Endian endian = Endian.big]) =>
+      _data.getInt64(byteOffset, endian);
+
+  void setInt64(int byteOffset, int value, [Endian endian = Endian.big]) =>
+      _unsupported();
+
+  int getUint64(int byteOffset, [Endian endian = Endian.big]) =>
+      _data.getUint64(byteOffset, endian);
+
+  void setUint64(int byteOffset, int value, [Endian endian = Endian.big]) =>
+      _unsupported();
+
+  double getFloat32(int byteOffset, [Endian endian = Endian.big]) =>
+      _data.getFloat32(byteOffset, endian);
+
+  void setFloat32(int byteOffset, double value, [Endian endian = Endian.big]) =>
+      _unsupported();
+
+  double getFloat64(int byteOffset, [Endian endian = Endian.big]) =>
+      _data.getFloat64(byteOffset, endian);
+
+  void setFloat64(int byteOffset, double value, [Endian endian = Endian.big]) =>
+      _unsupported();
+
+  int get elementSizeInBytes => _data.elementSizeInBytes;
+
+  int get offsetInBytes => _data.offsetInBytes;
+
+  int get lengthInBytes => _data.lengthInBytes;
+
+  ByteBuffer get buffer => new UnmodifiableByteBufferView(_data.buffer);
+
+  void _unsupported() {
+    throw new UnsupportedError(
+        "An UnmodifiableByteDataView may not be modified");
+  }
+}
+
+abstract class _UnmodifiableListMixin<N, L extends List<N>,
+    TD extends TypedData> {
+  L get _list;
+  TD get _data => (_list as TD);
+
+  int get length => _list.length;
+
+  N operator [](int index) => _list[index];
+
+  int get elementSizeInBytes => _data.elementSizeInBytes;
+
+  int get offsetInBytes => _data.offsetInBytes;
+
+  int get lengthInBytes => _data.lengthInBytes;
+
+  ByteBuffer get buffer => new UnmodifiableByteBufferView(_data.buffer);
+
+  L _createList(int length);
+
+  L sublist(int start, [int end]) {
+    end = RangeError.checkValidRange(start, end, length);
+    int sublistLength = end - start;
+    L result = _createList(sublistLength);
+    result.setRange(0, sublistLength, _list, start);
+    return result;
+  }
+}
+
+/**
+ * View of a [Uint8List] that disallows modification.
+ */
+class UnmodifiableUint8ListView extends UnmodifiableListBase<int>
+    with _UnmodifiableListMixin<int, Uint8List, Uint8List>
+    implements Uint8List {
+  final Uint8List _list;
+  UnmodifiableUint8ListView(Uint8List list) : _list = list;
+
+  Uint8List _createList(int length) => Uint8List(length);
+}
+
+/**
+ * View of a [Int8List] that disallows modification.
+ */
+class UnmodifiableInt8ListView extends UnmodifiableListBase<int>
+    with _UnmodifiableListMixin<int, Int8List, Int8List>
+    implements Int8List {
+  final Int8List _list;
+  UnmodifiableInt8ListView(Int8List list) : _list = list;
+
+  Int8List _createList(int length) => Int8List(length);
+}
+
+/**
+ * View of a [Uint8ClampedList] that disallows modification.
+ */
+class UnmodifiableUint8ClampedListView extends UnmodifiableListBase<int>
+    with _UnmodifiableListMixin<int, Uint8ClampedList, Uint8ClampedList>
+    implements Uint8ClampedList {
+  final Uint8ClampedList _list;
+  UnmodifiableUint8ClampedListView(Uint8ClampedList list) : _list = list;
+
+  Uint8ClampedList _createList(int length) => Uint8ClampedList(length);
+}
+
+/**
+ * View of a [Uint16List] that disallows modification.
+ */
+class UnmodifiableUint16ListView extends UnmodifiableListBase<int>
+    with _UnmodifiableListMixin<int, Uint16List, Uint16List>
+    implements Uint16List {
+  final Uint16List _list;
+  UnmodifiableUint16ListView(Uint16List list) : _list = list;
+
+  Uint16List _createList(int length) => Uint16List(length);
+}
+
+/**
+ * View of a [Int16List] that disallows modification.
+ */
+class UnmodifiableInt16ListView extends UnmodifiableListBase<int>
+    with _UnmodifiableListMixin<int, Int16List, Int16List>
+    implements Int16List {
+  final Int16List _list;
+  UnmodifiableInt16ListView(Int16List list) : _list = list;
+
+  Int16List _createList(int length) => Int16List(length);
+}
+
+/**
+ * View of a [Uint32List] that disallows modification.
+ */
+class UnmodifiableUint32ListView extends UnmodifiableListBase<int>
+    with _UnmodifiableListMixin<int, Uint32List, Uint32List>
+    implements Uint32List {
+  final Uint32List _list;
+  UnmodifiableUint32ListView(Uint32List list) : _list = list;
+
+  Uint32List _createList(int length) => Uint32List(length);
+}
+
+/**
+ * View of a [Int32List] that disallows modification.
+ */
+class UnmodifiableInt32ListView extends UnmodifiableListBase<int>
+    with _UnmodifiableListMixin<int, Int32List, Int32List>
+    implements Int32List {
+  final Int32List _list;
+  UnmodifiableInt32ListView(Int32List list) : _list = list;
+
+  Int32List _createList(int length) => Int32List(length);
+}
+
+/**
+ * View of a [Uint64List] that disallows modification.
+ */
+class UnmodifiableUint64ListView extends UnmodifiableListBase<int>
+    with _UnmodifiableListMixin<int, Uint64List, Uint64List>
+    implements Uint64List {
+  final Uint64List _list;
+  UnmodifiableUint64ListView(Uint64List list) : _list = list;
+
+  Uint64List _createList(int length) => Uint64List(length);
+}
+
+/**
+ * View of a [Int64List] that disallows modification.
+ */
+class UnmodifiableInt64ListView extends UnmodifiableListBase<int>
+    with _UnmodifiableListMixin<int, Int64List, Int64List>
+    implements Int64List {
+  final Int64List _list;
+  UnmodifiableInt64ListView(Int64List list) : _list = list;
+
+  Int64List _createList(int length) => Int64List(length);
+}
+
+/**
+ * View of a [Int32x4List] that disallows modification.
+ */
+class UnmodifiableInt32x4ListView extends UnmodifiableListBase<Int32x4>
+    with _UnmodifiableListMixin<Int32x4, Int32x4List, Int32x4List>
+    implements Int32x4List {
+  final Int32x4List _list;
+  UnmodifiableInt32x4ListView(Int32x4List list) : _list = list;
+
+  Int32x4List _createList(int length) => Int32x4List(length);
+}
+
+/**
+ * View of a [Float32x4List] that disallows modification.
+ */
+class UnmodifiableFloat32x4ListView extends UnmodifiableListBase<Float32x4>
+    with _UnmodifiableListMixin<Float32x4, Float32x4List, Float32x4List>
+    implements Float32x4List {
+  final Float32x4List _list;
+  UnmodifiableFloat32x4ListView(Float32x4List list) : _list = list;
+
+  Float32x4List _createList(int length) => Float32x4List(length);
+}
+
+/**
+ * View of a [Float64x2List] that disallows modification.
+ */
+class UnmodifiableFloat64x2ListView extends UnmodifiableListBase<Float64x2>
+    with _UnmodifiableListMixin<Float64x2, Float64x2List, Float64x2List>
+    implements Float64x2List {
+  final Float64x2List _list;
+  UnmodifiableFloat64x2ListView(Float64x2List list) : _list = list;
+
+  Float64x2List _createList(int length) => Float64x2List(length);
+}
+
+/**
+ * View of a [Float32List] that disallows modification.
+ */
+class UnmodifiableFloat32ListView extends UnmodifiableListBase<double>
+    with _UnmodifiableListMixin<double, Float32List, Float32List>
+    implements Float32List {
+  final Float32List _list;
+  UnmodifiableFloat32ListView(Float32List list) : _list = list;
+
+  Float32List _createList(int length) => Float32List(length);
+}
+
+/**
+ * View of a [Float64List] that disallows modification.
+ */
+class UnmodifiableFloat64ListView extends UnmodifiableListBase<double>
+    with _UnmodifiableListMixin<double, Float64List, Float64List>
+    implements Float64List {
+  final Float64List _list;
+  UnmodifiableFloat64ListView(Float64List list) : _list = list;
+
+  Float64List _createList(int length) => Float64List(length);
+}
diff --git a/sdk_nnbd/lib/vmservice/asset.dart b/sdk_nnbd/lib/vmservice/asset.dart
new file mode 100644
index 0000000..d5772e2
--- /dev/null
+++ b/sdk_nnbd/lib/vmservice/asset.dart
@@ -0,0 +1,69 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart._vmservice;
+
+class Asset {
+  final String name;
+  final Uint8List data;
+
+  Asset(this.name, this.data);
+
+  String get mimeType {
+    var extensionStart = name.lastIndexOf('.');
+    var extension = name.substring(extensionStart + 1);
+    switch (extension) {
+      case 'html':
+        return 'text/html; charset=UTF-8';
+      case 'dart':
+        return 'application/dart; charset=UTF-8';
+      case 'js':
+        return 'application/javascript; charset=UTF-8';
+      case 'css':
+        return 'text/css; charset=UTF-8';
+      case 'gif':
+        return 'image/gif';
+      case 'png':
+        return 'image/png';
+      case 'jpg':
+        return 'image/jpeg';
+      case 'jpeg':
+        return 'image/jpeg';
+      case 'svg':
+        return 'image/svg+xml';
+      default:
+        return 'text/plain';
+    }
+  }
+
+  static Map<String, Asset> request() {
+    Uint8List tarBytes = _requestAssets();
+    if (tarBytes == null) {
+      return null;
+    }
+    List assetList = _decodeAssets(tarBytes);
+    Map<String, Asset> assets = new HashMap<String, Asset>();
+    for (int i = 0; i < assetList.length; i += 2) {
+      var a = new Asset(assetList[i], assetList[i + 1]);
+      assets[a.name] = a;
+    }
+    return assets;
+  }
+
+  String toString() => '$name ($mimeType)';
+}
+
+List _decodeAssets(Uint8List data) native "VMService_DecodeAssets";
+
+Map<String, Asset> _assets;
+Map<String, Asset> get assets {
+  if (_assets == null) {
+    try {
+      _assets = Asset.request();
+    } catch (e) {
+      print('Could not load Observatory assets: $e');
+    }
+  }
+  return _assets;
+}
diff --git a/sdk_nnbd/lib/vmservice/client.dart b/sdk_nnbd/lib/vmservice/client.dart
new file mode 100644
index 0000000..efe33c0
--- /dev/null
+++ b/sdk_nnbd/lib/vmservice/client.dart
@@ -0,0 +1,65 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart._vmservice;
+
+typedef void ClientServiceHandle(Message response);
+
+// A service client.
+abstract class Client {
+  final VMService service;
+  final bool sendEvents;
+
+  /// A set streamIds which describes the streams the client is connected to
+  final Set<String> streams = new Set<String>();
+
+  /// Services registered and their aliases
+  /// key: service
+  /// value: alias
+  final Map<String, String> services = new Map<String, String>();
+
+  /// Callbacks registered for service invocations set to the client
+  /// key: RPC id used for the request
+  /// value: callback that should be invoked
+  final Map<String, ClientServiceHandle> serviceHandles =
+      new Map<String, ClientServiceHandle>();
+
+  Client(this.service, {bool sendEvents: true}) : this.sendEvents = sendEvents {
+    service._addClient(this);
+  }
+
+  // Disconnects the client.
+  disconnect();
+
+  /// When implementing, call [close] when the network connection closes.
+  void close() {
+    service._removeClient(this);
+  }
+
+  /// Call to process a request. Response will be posted with 'seq'.
+  void onRequest(Message message) {
+    // In JSON-RPC 2.0 messages with and id are Request and must be answered
+    // http://www.jsonrpc.org/specification#notification
+    service.routeRequest(service, message).then(post);
+  }
+
+  void onResponse(Message message) {
+    service.routeResponse(message);
+  }
+
+  /// Call to process a notification. Response will not be posted.
+  void onNotification(Message message) {
+    // In JSON-RPC 2.0 messages without an id are Notification
+    // and should not be answered
+    // http://www.jsonrpc.org/specification#notification
+    service.routeRequest(service, message);
+  }
+
+  // Sends a result to the client.  Implemented in subclasses.
+  void post(Response result);
+
+  dynamic toJson() {
+    return {};
+  }
+}
diff --git a/sdk_nnbd/lib/vmservice/constants.dart b/sdk_nnbd/lib/vmservice/constants.dart
new file mode 100644
index 0000000..914576b
--- /dev/null
+++ b/sdk_nnbd/lib/vmservice/constants.dart
@@ -0,0 +1,22 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart._vmservice;
+
+// These must be kept in sync with runtime/vm/service.cc.
+class Constants {
+  static const int SERVICE_EXIT_MESSAGE_ID = 0;
+  static const int ISOLATE_STARTUP_MESSAGE_ID = 1;
+  static const int ISOLATE_SHUTDOWN_MESSAGE_ID = 2;
+  static const int WEB_SERVER_CONTROL_MESSAGE_ID = 3;
+  static const int SERVER_INFO_MESSAGE_ID = 4;
+
+  /// Signals an RPC coming from native code (instead of from a websocket
+  /// connection).  These calls are limited to simple request-response and do
+  /// not allow arbitrary json-rpc messages.
+  ///
+  /// The messages are an array of length 3:
+  ///   (METHOD_CALL_FROM_NATIVE, String jsonRequest, PortId replyPort).
+  static const int METHOD_CALL_FROM_NATIVE = 5;
+}
diff --git a/sdk_nnbd/lib/vmservice/devfs.dart b/sdk_nnbd/lib/vmservice/devfs.dart
new file mode 100644
index 0000000..20e0573
--- /dev/null
+++ b/sdk_nnbd/lib/vmservice/devfs.dart
@@ -0,0 +1,399 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart._vmservice;
+
+String _encodeDevFSDisabledError(Message message) {
+  return encodeRpcError(message, kFeatureDisabled,
+      details: "DevFS is not supported by this Dart implementation");
+}
+
+String _encodeFileSystemAlreadyExistsError(Message message, String fsName) {
+  return encodeRpcError(message, kFileSystemAlreadyExists,
+      details: "${message.method}: file system '${fsName}' already exists");
+}
+
+String _encodeFileSystemDoesNotExistError(Message message, String fsName) {
+  return encodeRpcError(message, kFileSystemDoesNotExist,
+      details: "${message.method}: file system '${fsName}' does not exist");
+}
+
+class _FileSystem {
+  _FileSystem(this.name, this.uri);
+
+  final String name;
+  final Uri uri;
+
+  Uri resolvePath(String path) {
+    if (path.startsWith('/')) {
+      path = path.substring(1);
+    }
+    if (path.isEmpty) {
+      return null;
+    }
+    Uri pathUri;
+    try {
+      pathUri = new Uri.file(path);
+    } on FormatException catch (e) {
+      return null;
+    }
+
+    return resolve(pathUri);
+  }
+
+  Uri resolve(Uri pathUri) {
+    try {
+      // Make sure that this pathUri can be converted to a file path.
+      pathUri.toFilePath();
+    } on UnsupportedError catch (e) {
+      return null;
+    }
+
+    Uri resolvedUri = uri.resolveUri(pathUri);
+    if (!resolvedUri.toString().startsWith(uri.toString())) {
+      // Resolved uri must be within the filesystem's base uri.
+      return null;
+    }
+    return resolvedUri;
+  }
+
+  Map toMap() {
+    return {
+      'type': 'FileSystem',
+      'name': name,
+      'uri': uri.toString(),
+    };
+  }
+}
+
+class DevFS {
+  DevFS();
+
+  Map<String, _FileSystem> _fsMap = {};
+
+  final Set _rpcNames = new Set.from([
+    '_listDevFS',
+    '_createDevFS',
+    '_deleteDevFS',
+    '_readDevFSFile',
+    '_writeDevFSFile',
+    '_writeDevFSFiles',
+    '_listDevFSFiles',
+  ]);
+
+  void cleanup() {
+    var deleteDir = VMServiceEmbedderHooks.deleteDir;
+    if (deleteDir == null) {
+      return;
+    }
+    var deletions = <Future>[];
+    for (var fs in _fsMap.values) {
+      deletions.add(deleteDir(fs.uri));
+    }
+    Future.wait(deletions);
+    _fsMap.clear();
+  }
+
+  bool shouldHandleMessage(Message message) {
+    return _rpcNames.contains(message.method);
+  }
+
+  Future<String> handleMessage(Message message) async {
+    switch (message.method) {
+      case '_listDevFS':
+        return _listDevFS(message);
+      case '_createDevFS':
+        return _createDevFS(message);
+      case '_deleteDevFS':
+        return _deleteDevFS(message);
+      case '_readDevFSFile':
+        return _readDevFSFile(message);
+      case '_writeDevFSFile':
+        return _writeDevFSFile(message);
+      case '_writeDevFSFiles':
+        return _writeDevFSFiles(message);
+      case '_listDevFSFiles':
+        return _listDevFSFiles(message);
+      default:
+        return encodeRpcError(message, kInternalError,
+            details: 'Unexpected rpc ${message.method}');
+    }
+  }
+
+  Future<String> handlePutStream(
+      Object fsName, Object path, Uri fsUri, Stream<List<int>> bytes) async {
+    // A dummy Message for error message construction.
+    Message message = new Message.forMethod('_writeDevFSFile');
+    var writeStreamFile = VMServiceEmbedderHooks.writeStreamFile;
+    if (writeStreamFile == null) {
+      return _encodeDevFSDisabledError(message);
+    }
+    if (fsName == null) {
+      return encodeMissingParamError(message, 'fsName');
+    }
+    if (fsName is! String) {
+      return encodeInvalidParamError(message, 'fsName');
+    }
+    var fs = _fsMap[fsName];
+    if (fs == null) {
+      return _encodeFileSystemDoesNotExistError(message, fsName);
+    }
+    Uri uri = fsUri;
+    if (uri == null) {
+      if (path == null) {
+        return encodeMissingParamError(message, 'path');
+      }
+      if (path is! String) {
+        return encodeInvalidParamError(message, 'path');
+      }
+      uri = fs.resolvePath(path);
+      if (uri == null) {
+        return encodeInvalidParamError(message, 'path');
+      }
+    } else {
+      uri = fs.resolve(uri);
+      if (uri == null) {
+        return encodeInvalidParamError(message, 'uri');
+      }
+    }
+    await writeStreamFile(uri, bytes);
+    return encodeSuccess(message);
+  }
+
+  Future<String> _listDevFS(Message message) async {
+    var result = {};
+    result['type'] = 'FileSystemList';
+    result['fsNames'] = _fsMap.keys.toList();
+    return encodeResult(message, result);
+  }
+
+  Future<String> _createDevFS(Message message) async {
+    var createTempDir = VMServiceEmbedderHooks.createTempDir;
+    if (createTempDir == null) {
+      return _encodeDevFSDisabledError(message);
+    }
+    var fsName = message.params['fsName'];
+    if (fsName == null) {
+      return encodeMissingParamError(message, 'fsName');
+    }
+    if (fsName is! String) {
+      return encodeInvalidParamError(message, 'fsName');
+    }
+    var fs = _fsMap[fsName];
+    if (fs != null) {
+      return _encodeFileSystemAlreadyExistsError(message, fsName);
+    }
+    var tempDir = await createTempDir(fsName);
+    fs = new _FileSystem(fsName, tempDir);
+    _fsMap[fsName] = fs;
+    return encodeResult(message, fs.toMap());
+  }
+
+  Future<String> _deleteDevFS(Message message) async {
+    var deleteDir = VMServiceEmbedderHooks.deleteDir;
+    if (deleteDir == null) {
+      return _encodeDevFSDisabledError(message);
+    }
+    var fsName = message.params['fsName'];
+    if (fsName == null) {
+      return encodeMissingParamError(message, 'fsName');
+    }
+    if (fsName is! String) {
+      return encodeInvalidParamError(message, 'fsName');
+    }
+    var fs = _fsMap.remove(fsName);
+    if (fs == null) {
+      return _encodeFileSystemDoesNotExistError(message, fsName);
+    }
+    await deleteDir(fs.uri);
+    return encodeSuccess(message);
+  }
+
+  Future<String> _readDevFSFile(Message message) async {
+    var readFile = VMServiceEmbedderHooks.readFile;
+    if (readFile == null) {
+      return _encodeDevFSDisabledError(message);
+    }
+    var fsName = message.params['fsName'];
+    if (fsName == null) {
+      return encodeMissingParamError(message, 'fsName');
+    }
+    if (fsName is! String) {
+      return encodeInvalidParamError(message, 'fsName');
+    }
+    var fs = _fsMap[fsName];
+    if (fs == null) {
+      return _encodeFileSystemDoesNotExistError(message, fsName);
+    }
+    Uri uri;
+    if (message.params['uri'] != null) {
+      try {
+        var uriParam = message.params['uri'];
+        if (uriParam is! String) {
+          return encodeInvalidParamError(message, 'uri');
+        }
+        Uri parsedUri = Uri.parse(uriParam);
+        uri = fs.resolve(parsedUri);
+        if (uri == null) {
+          return encodeInvalidParamError(message, 'uri');
+        }
+      } catch (e) {
+        return encodeInvalidParamError(message, 'uri');
+      }
+    } else {
+      var path = message.params['path'];
+      if (path == null) {
+        return encodeMissingParamError(message, 'path');
+      }
+      if (path is! String) {
+        return encodeInvalidParamError(message, 'path');
+      }
+      uri = fs.resolvePath(path);
+      if (uri == null) {
+        return encodeInvalidParamError(message, 'path');
+      }
+    }
+    try {
+      List<int> bytes = await readFile(uri);
+      var result = {'type': 'FSFile', 'fileContents': base64.encode(bytes)};
+      return encodeResult(message, result);
+    } catch (e) {
+      return encodeRpcError(message, kFileDoesNotExist,
+          details: "_readDevFSFile: $e");
+    }
+  }
+
+  Future<String> _writeDevFSFile(Message message) async {
+    var writeFile = VMServiceEmbedderHooks.writeFile;
+    if (writeFile == null) {
+      return _encodeDevFSDisabledError(message);
+    }
+    var fsName = message.params['fsName'];
+    if (fsName == null) {
+      return encodeMissingParamError(message, 'fsName');
+    }
+    if (fsName is! String) {
+      return encodeInvalidParamError(message, 'fsName');
+    }
+    var fs = _fsMap[fsName];
+    if (fs == null) {
+      return _encodeFileSystemDoesNotExistError(message, fsName);
+    }
+    Uri uri;
+    if (message.params['uri'] != null) {
+      try {
+        var uriParam = message.params['uri'];
+        if (uriParam is! String) {
+          return encodeInvalidParamError(message, 'uri');
+        }
+        Uri parsedUri = Uri.parse(uriParam);
+        uri = fs.resolve(parsedUri);
+        if (uri == null) {
+          return encodeInvalidParamError(message, 'uri');
+        }
+      } catch (e) {
+        return encodeInvalidParamError(message, 'uri');
+      }
+    } else {
+      var path = message.params['path'];
+      if (path == null) {
+        return encodeMissingParamError(message, 'path');
+      }
+      if (path is! String) {
+        return encodeInvalidParamError(message, 'path');
+      }
+      uri = fs.resolvePath(path);
+      if (uri == null) {
+        return encodeInvalidParamError(message, 'path');
+      }
+    }
+    var fileContents = message.params['fileContents'];
+    if (fileContents == null) {
+      return encodeMissingParamError(message, 'fileContents');
+    }
+    if (fileContents is! String) {
+      return encodeInvalidParamError(message, 'fileContents');
+    }
+    List<int> decodedFileContents = base64.decode(fileContents);
+
+    await writeFile(uri, decodedFileContents);
+    return encodeSuccess(message);
+  }
+
+  Future<String> _writeDevFSFiles(Message message) async {
+    var writeFile = VMServiceEmbedderHooks.writeFile;
+    if (writeFile == null) {
+      return _encodeDevFSDisabledError(message);
+    }
+    var fsName = message.params['fsName'];
+    if (fsName == null) {
+      return encodeMissingParamError(message, 'fsName');
+    }
+    if (fsName is! String) {
+      return encodeInvalidParamError(message, 'fsName');
+    }
+    var fs = _fsMap[fsName];
+    if (fs == null) {
+      return _encodeFileSystemDoesNotExistError(message, fsName);
+    }
+    var files = message.params['files'];
+    if (files == null) {
+      return encodeMissingParamError(message, 'files');
+    }
+    if (files is! List) {
+      return encodeInvalidParamError(message, 'files');
+    }
+    var uris = [];
+    for (int i = 0; i < files.length; i++) {
+      var fileInfo = files[i];
+      if (fileInfo is! List ||
+          fileInfo.length != 2 ||
+          fileInfo[0] is! String ||
+          fileInfo[1] is! String) {
+        return encodeRpcError(message, kInvalidParams,
+            details: "${message.method}: invalid 'files' parameter "
+                "at index ${i}: ${fileInfo}");
+      }
+      var uri = fs.resolvePath(fileInfo[0]);
+      if (uri == null) {
+        return encodeRpcError(message, kInvalidParams,
+            details: "${message.method}: invalid 'files' parameter "
+                "at index ${i}: ${fileInfo}");
+      }
+      uris.add(uri);
+    }
+    var pendingWrites = <Future>[];
+    for (int i = 0; i < uris.length; i++) {
+      List<int> decodedFileContents = base64.decode(files[i][1]);
+      pendingWrites.add(writeFile(uris[i], decodedFileContents));
+    }
+    await Future.wait(pendingWrites);
+    return encodeSuccess(message);
+  }
+
+  Future<String> _listDevFSFiles(Message message) async {
+    var listFiles = VMServiceEmbedderHooks.listFiles;
+    if (listFiles == null) {
+      return _encodeDevFSDisabledError(message);
+    }
+    var fsName = message.params['fsName'];
+    if (fsName == null) {
+      return encodeMissingParamError(message, 'fsName');
+    }
+    if (fsName is! String) {
+      return encodeInvalidParamError(message, 'fsName');
+    }
+    var fs = _fsMap[fsName];
+    if (fs == null) {
+      return _encodeFileSystemDoesNotExistError(message, fsName);
+    }
+    var fileList = await listFiles(fs.uri);
+    // Remove any url-encoding in the filenames.
+    for (int i = 0; i < fileList.length; i++) {
+      fileList[i]['name'] = Uri.decodeFull(fileList[i]['name']);
+    }
+    var result = {'type': 'FSFileList', 'files': fileList};
+    return encodeResult(message, result);
+  }
+}
diff --git a/sdk_nnbd/lib/vmservice/message.dart b/sdk_nnbd/lib/vmservice/message.dart
new file mode 100644
index 0000000..9e4375a
--- /dev/null
+++ b/sdk_nnbd/lib/vmservice/message.dart
@@ -0,0 +1,267 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart._vmservice;
+
+enum MessageType { Request, Notification, Response }
+
+class Message {
+  final Completer<Response> _completer = new Completer<Response>.sync();
+  bool get completed => _completer.isCompleted;
+
+  /// Future of response.
+  Future<Response> get response => _completer.future;
+  Client client;
+
+  // Is a notification message (no serial)
+  final MessageType type;
+
+  // Client-side identifier for this message.
+  final serial;
+
+  final String method;
+
+  final Map params = new Map();
+  final Map result = new Map();
+  final Map error = new Map();
+
+  factory Message.fromJsonRpc(Client client, Map map) {
+    if (map.containsKey('id')) {
+      final id = map['id'];
+      if (id != null && id is! num && id is! String) {
+        throw new Exception('"id" must be a number, string, or null.');
+      }
+      if (map.containsKey('method')) {
+        return new Message._fromJsonRpcRequest(client, map);
+      }
+      if (map.containsKey('result')) {
+        return new Message._fromJsonRpcResult(client, map);
+      }
+      if (map.containsKey('error')) {
+        return new Message._fromJsonRpcError(client, map);
+      }
+    } else if (map.containsKey('method')) {
+      return new Message._fromJsonRpcNotification(client, map);
+    }
+    throw new Exception('Invalid message format');
+  }
+
+  // http://www.jsonrpc.org/specification#request_object
+  Message._fromJsonRpcRequest(Client client, Map map)
+      : client = client,
+        type = MessageType.Request,
+        serial = map['id'],
+        method = map['method'] {
+    if (map['params'] != null) {
+      params.addAll(map['params']);
+    }
+  }
+
+  // http://www.jsonrpc.org/specification#notification
+  Message._fromJsonRpcNotification(Client client, Map map)
+      : client = client,
+        type = MessageType.Notification,
+        method = map['method'],
+        serial = null {
+    if (map['params'] != null) {
+      params.addAll(map['params']);
+    }
+  }
+
+  // http://www.jsonrpc.org/specification#response_object
+  Message._fromJsonRpcResult(Client client, Map map)
+      : client = client,
+        type = MessageType.Response,
+        serial = map['id'],
+        method = null {
+    result.addAll(map['result']);
+  }
+
+  // http://www.jsonrpc.org/specification#response_object
+  Message._fromJsonRpcError(Client client, Map map)
+      : client = client,
+        type = MessageType.Response,
+        serial = map['id'],
+        method = null {
+    error.addAll(map['error']);
+  }
+
+  static String _methodNameFromUri(Uri uri) {
+    if (uri == null) {
+      return '';
+    }
+    if (uri.pathSegments.length == 0) {
+      return '';
+    }
+    return uri.pathSegments[0];
+  }
+
+  Message.forMethod(String method)
+      : client = null,
+        method = method,
+        type = MessageType.Request,
+        serial = '';
+
+  Message.fromUri(this.client, Uri uri)
+      : type = MessageType.Request,
+        serial = '',
+        method = _methodNameFromUri(uri) {
+    params.addAll(uri.queryParameters);
+  }
+
+  Message.forIsolate(this.client, Uri uri, RunningIsolate isolate)
+      : type = MessageType.Request,
+        serial = '',
+        method = _methodNameFromUri(uri) {
+    params.addAll(uri.queryParameters);
+    params['isolateId'] = isolate.serviceId;
+  }
+
+  Uri toUri() {
+    return new Uri(path: method, queryParameters: params);
+  }
+
+  dynamic toJson() {
+    throw 'unsupported';
+  }
+
+  dynamic forwardToJson([Map overloads]) {
+    Map<dynamic, dynamic> json = {'jsonrpc': '2.0', 'id': serial};
+    switch (type) {
+      case MessageType.Request:
+      case MessageType.Notification:
+        json['method'] = method;
+        if (params.isNotEmpty) {
+          json['params'] = params;
+        }
+        break;
+      case MessageType.Response:
+        if (result.isNotEmpty) {
+          json['result'] = result;
+        }
+        if (error.isNotEmpty) {
+          json['error'] = error;
+        }
+    }
+    if (overloads != null) {
+      json.addAll(overloads);
+    }
+    return json;
+  }
+
+  // Calls toString on all non-String elements of [list]. We do this so all
+  // elements in the list are strings, making consumption by C++ simpler.
+  // This has a side effect that boolean literal values like true become 'true'
+  // and thus indistinguishable from the string literal 'true'.
+  List<String> _makeAllString(List list) {
+    if (list == null) {
+      return null;
+    }
+    var new_list = new List<String>(list.length);
+    for (var i = 0; i < list.length; i++) {
+      new_list[i] = list[i].toString();
+    }
+    return new_list;
+  }
+
+  Future<Response> sendToIsolate(SendPort sendPort) {
+    final receivePort = new RawReceivePort();
+    receivePort.handler = (value) {
+      receivePort.close();
+      _setResponseFromPort(value);
+    };
+    var keys = _makeAllString(params.keys.toList(growable: false));
+    var values = _makeAllString(params.values.toList(growable: false));
+    var request = new List(6)
+      ..[0] = 0 // Make room for OOB message type.
+      ..[1] = receivePort.sendPort
+      ..[2] = serial
+      ..[3] = method
+      ..[4] = keys
+      ..[5] = values;
+    if (!sendIsolateServiceMessage(sendPort, request)) {
+      receivePort.close();
+      _completer.complete(new Response.internalError(
+          'could not send message [${serial}] to isolate'));
+    }
+    return _completer.future;
+  }
+
+  // We currently support two ways of passing parameters from Dart code to C
+  // code. The original way always converts the parameters to strings before
+  // passing them over. Our goal is to convert all C handlers to take the
+  // parameters as Dart objects but until the conversion is complete, we
+  // maintain the list of supported methods below.
+  bool _methodNeedsObjectParameters(String method) {
+    switch (method) {
+      case '_listDevFS':
+      case '_listDevFSFiles':
+      case '_createDevFS':
+      case '_deleteDevFS':
+      case '_writeDevFSFile':
+      case '_writeDevFSFiles':
+      case '_readDevFSFile':
+      case '_spawnUri':
+        return true;
+      default:
+        return false;
+    }
+  }
+
+  Future<Response> sendToVM() {
+    final receivePort = new RawReceivePort();
+    receivePort.handler = (value) {
+      receivePort.close();
+      _setResponseFromPort(value);
+    };
+    var keys = params.keys.toList(growable: false);
+    var values = params.values.toList(growable: false);
+    if (!_methodNeedsObjectParameters(method)) {
+      keys = _makeAllString(keys);
+      values = _makeAllString(values);
+    }
+
+    final request = new List(6)
+      ..[0] = 0 // Make room for OOB message type.
+      ..[1] = receivePort.sendPort
+      ..[2] = serial
+      ..[3] = method
+      ..[4] = keys
+      ..[5] = values;
+
+    if (_methodNeedsObjectParameters(method)) {
+      // We use a different method invocation path here.
+      sendObjectRootServiceMessage(request);
+    } else {
+      sendRootServiceMessage(request);
+    }
+
+    return _completer.future;
+  }
+
+  void _setResponseFromPort(dynamic response) {
+    if (response == null) {
+      // We should only have a null response for Notifications.
+      assert(type == MessageType.Notification);
+      return null;
+    }
+    _completer.complete(Response.from(response));
+  }
+
+  void setResponse(String response) {
+    _completer.complete(new Response(ResponsePayloadKind.String, response));
+  }
+
+  void setErrorResponse(int code, String details) {
+    setResponse(encodeRpcError(this, code, details: '$method: $details'));
+  }
+}
+
+bool sendIsolateServiceMessage(SendPort sp, List m)
+    native "VMService_SendIsolateServiceMessage";
+
+void sendRootServiceMessage(List m) native "VMService_SendRootServiceMessage";
+
+void sendObjectRootServiceMessage(List m)
+    native "VMService_SendObjectRootServiceMessage";
diff --git a/sdk_nnbd/lib/vmservice/message_router.dart b/sdk_nnbd/lib/vmservice/message_router.dart
new file mode 100644
index 0000000..4c1b307
--- /dev/null
+++ b/sdk_nnbd/lib/vmservice/message_router.dart
@@ -0,0 +1,85 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart._vmservice;
+
+abstract class MessageRouter {
+  Future<Response> routeRequest(VMService service, Message message);
+  void routeResponse(Message message);
+}
+
+enum ResponsePayloadKind {
+  /// Response payload is a Dart string.
+  String,
+
+  /// Response payload is a binary (Uint8List).
+  Binary,
+
+  /// Response payload is a string encoded as UTF8 bytes (Uint8List).
+  Utf8String,
+}
+
+class Response {
+  final ResponsePayloadKind kind;
+  final payload;
+
+  /// Construct response object with the given [payload] and [kind].
+  Response(this.kind, this.payload) {
+    assert(() {
+      switch (kind) {
+        case ResponsePayloadKind.String:
+          return payload is String;
+        case ResponsePayloadKind.Binary:
+        case ResponsePayloadKind.Utf8String:
+          return payload is Uint8List;
+      }
+    }());
+  }
+
+  /// Construct a string response from the given [value] by encoding it
+  /// as JSON.
+  Response.json(Object value)
+      : this(ResponsePayloadKind.String, json.encode(value));
+
+  factory Response.internalError(String message) {
+    return new Response.json({
+      'type': 'ServiceError',
+      'id': '',
+      'kind': 'InternalError',
+      'message': message,
+    });
+  }
+
+  /// Construct response from the response [value] which can be either:
+  ///     String: a string
+  ///     Binary: a Uint8List
+  ///     Utf8String: a single element list containing Uint8List
+  factory Response.from(Object value) {
+    if (value is String) {
+      return new Response(ResponsePayloadKind.String, value);
+    } else if (value is Uint8List) {
+      return new Response(ResponsePayloadKind.Binary, value);
+    } else if (value is List) {
+      assert(value.length == 1);
+      return new Response(
+          ResponsePayloadKind.Utf8String, value[0] as Uint8List);
+    } else if (value is Response) {
+      return value;
+    } else {
+      throw 'Unrecognized response: ${value}';
+    }
+  }
+
+  /// Decode JSON contained in this response.
+  dynamic decodeJson() {
+    switch (kind) {
+      case ResponsePayloadKind.String:
+        return json.decode(payload);
+      case ResponsePayloadKind.Utf8String:
+        return json.fuse(utf8).decode(payload);
+      case ResponsePayloadKind.Binary:
+        throw 'Binary responses can not be decoded';
+    }
+  }
+}
diff --git a/sdk_nnbd/lib/vmservice/named_lookup.dart b/sdk_nnbd/lib/vmservice/named_lookup.dart
new file mode 100644
index 0000000..7087c94
--- /dev/null
+++ b/sdk_nnbd/lib/vmservice/named_lookup.dart
@@ -0,0 +1,68 @@
+// 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.
+
+part of dart._vmservice;
+
+/// Set like containes which automatically generated String ids for its items
+class NamedLookup<E> extends Object with IterableMixin<E> {
+  final IdGenerator _generator;
+  final Map<String, E> _elements = new Map<String, E>();
+  final Map<E, String> _ids = new Map<E, String>();
+
+  NamedLookup({String prologue = ''})
+      : _generator = new IdGenerator(prologue: prologue);
+
+  void add(E e) {
+    final id = _generator.newId();
+    _elements[id] = e;
+    _ids[e] = id;
+  }
+
+  void remove(E e) {
+    final id = _ids.remove(e);
+    _elements.remove(id);
+    _generator.release(id);
+  }
+
+  E operator [](String id) => _elements[id];
+  String keyOf(E e) => _ids[e];
+
+  Iterator<E> get iterator => _ids.keys.iterator;
+}
+
+/// Generator for unique ids which recycles expired ones
+class IdGenerator {
+  /// Fixed initial part of the id
+  final String prologue;
+  // Ids in use
+  final Set<String> _used = new Set<String>();
+
+  /// Ids that has been released (use these before generate new ones)
+  final Set<String> _free = new Set<String>();
+
+  /// Next id to generate if no one can be recycled (first use _free);
+  int _next = 0;
+
+  IdGenerator({this.prologue = ''});
+
+  /// Returns a new Id (possibly recycled)
+  String newId() {
+    var id;
+    if (_free.isEmpty) {
+      id = prologue + (_next++).toString();
+    } else {
+      id = _free.first;
+    }
+    _free.remove(id);
+    _used.add(id);
+    return id;
+  }
+
+  /// Releases the id and mark it for recycle
+  void release(String id) {
+    if (_used.remove(id)) {
+      _free.add(id);
+    }
+  }
+}
diff --git a/sdk_nnbd/lib/vmservice/running_isolate.dart b/sdk_nnbd/lib/vmservice/running_isolate.dart
new file mode 100644
index 0000000..8a6dd36
--- /dev/null
+++ b/sdk_nnbd/lib/vmservice/running_isolate.dart
@@ -0,0 +1,24 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart._vmservice;
+
+class RunningIsolate implements MessageRouter {
+  final int portId;
+  final SendPort sendPort;
+  final String name;
+
+  RunningIsolate(this.portId, this.sendPort, this.name);
+
+  String get serviceId => 'isolates/$portId';
+
+  @override
+  Future<Response> routeRequest(VMService service, Message message) {
+    // Send message to isolate.
+    return message.sendToIsolate(sendPort);
+  }
+
+  @override
+  void routeResponse(Message message) {}
+}
diff --git a/sdk_nnbd/lib/vmservice/running_isolates.dart b/sdk_nnbd/lib/vmservice/running_isolates.dart
new file mode 100644
index 0000000..24b155c
--- /dev/null
+++ b/sdk_nnbd/lib/vmservice/running_isolates.dart
@@ -0,0 +1,214 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart._vmservice;
+
+class RunningIsolates implements MessageRouter {
+  final Map<int, RunningIsolate> isolates = new Map<int, RunningIsolate>();
+  int _rootPortId;
+
+  RunningIsolates();
+
+  void isolateStartup(int portId, SendPort sp, String name) {
+    if (_rootPortId == null) {
+      _rootPortId = portId;
+    }
+    var ri = new RunningIsolate(portId, sp, name);
+    isolates[portId] = ri;
+  }
+
+  void isolateShutdown(int portId, SendPort sp) {
+    if (_rootPortId == portId) {
+      _rootPortId = null;
+    }
+    isolates.remove(portId);
+  }
+
+  @override
+  Future<Response> routeRequest(VMService service, Message message) {
+    String isolateParam = message.params['isolateId'];
+    int isolateId;
+    if (!isolateParam.startsWith('isolates/')) {
+      message.setErrorResponse(
+          kInvalidParams, "invalid 'isolateId' parameter: $isolateParam");
+      return message.response;
+    }
+    isolateParam = isolateParam.substring('isolates/'.length);
+    if (isolateParam == 'root') {
+      isolateId = _rootPortId;
+    } else {
+      try {
+        isolateId = int.parse(isolateParam);
+      } catch (e) {
+        message.setErrorResponse(
+            kInvalidParams, "invalid 'isolateId' parameter: $isolateParam");
+        return message.response;
+      }
+    }
+    var isolate = isolates[isolateId];
+    if (isolate == null) {
+      // There is some chance that this isolate may have lived before,
+      // so return a sentinel rather than an error.
+      var result = {
+        'type': 'Sentinel',
+        'kind': 'Collected',
+        'valueAsString': '<collected>',
+      };
+      message.setResponse(encodeResult(message, result));
+      return message.response;
+    }
+
+    if (message.method == 'evaluateInFrame' || message.method == 'evaluate') {
+      return new _Evaluator(message, isolate, service).run();
+    } else {
+      return isolate.routeRequest(service, message);
+    }
+  }
+
+  @override
+  void routeResponse(Message message) {}
+}
+
+/// Class that knows how to orchestrate expression evaluation in dart2 world.
+class _Evaluator {
+  _Evaluator(this._message, this._isolate, this._service);
+
+  Future<Response> run() async {
+    Response buildScopeResponse = await _buildScope();
+    Map<String, dynamic> responseJson = buildScopeResponse.decodeJson();
+
+    if (responseJson.containsKey('error')) {
+      return new Response.from(encodeCompilationError(
+          _message, responseJson['error']['data']['details']));
+    }
+
+    String kernelBase64;
+    try {
+      kernelBase64 = await _compileExpression(responseJson['result']);
+    } catch (e) {
+      return new Response.from(encodeCompilationError(_message, e.toString()));
+    }
+    return _evaluateCompiledExpression(kernelBase64);
+  }
+
+  Message _message;
+  RunningIsolate _isolate;
+  VMService _service;
+
+  Future<Response> _buildScope() {
+    Map<String, dynamic> params = _setupParams();
+    params['isolateId'] = _message.params['isolateId'];
+    Map buildScopeParams = {
+      'method': '_buildExpressionEvaluationScope',
+      'id': _message.serial,
+      'params': params,
+    };
+    if (_message.params['scope'] != null) {
+      buildScopeParams['params']['scope'] = _message.params['scope'];
+    }
+    var buildScope =
+        new Message._fromJsonRpcRequest(_message.client, buildScopeParams);
+
+    // Decode the JSON and and insert it into the map. The map key
+    // is the request Uri.
+    return _isolate.routeRequest(_service, buildScope);
+  }
+
+  Future<String> _compileExpression(
+      Map<String, dynamic> buildScopeResponseResult) {
+    Client externalClient =
+        _service._findFirstClientThatHandlesService('compileExpression');
+
+    Map compileParams = {
+      'isolateId': _message.params['isolateId'],
+      'expression': _message.params['expression'],
+      'definitions': buildScopeResponseResult['param_names'],
+      'typeDefinitions': buildScopeResponseResult['type_params_names'],
+      'libraryUri': buildScopeResponseResult['libraryUri'],
+      'isStatic': buildScopeResponseResult['isStatic'],
+    };
+    dynamic klass = buildScopeResponseResult['klass'];
+    if (klass != null) {
+      compileParams['klass'] = klass;
+    }
+    if (externalClient != null) {
+      var compileExpression = new Message.forMethod('compileExpression');
+      compileExpression.client = externalClient;
+      compileExpression.params.addAll(compileParams);
+
+      final id = _service._serviceRequests.newId();
+      final oldId = _message.serial;
+      final completer = new Completer<String>();
+      externalClient.serviceHandles[id] = (Message m) {
+        if (m != null) {
+          completer.complete(json.encode(m.forwardToJson({'id': oldId})));
+        } else {
+          completer.complete(encodeRpcError(_message, kServiceDisappeared));
+        }
+      };
+      externalClient.post(new Response.json(compileExpression
+          .forwardToJson({'id': id, 'method': 'compileExpression'})));
+      return completer.future
+          .then((String s) => jsonDecode(s))
+          .then((dynamic json) {
+        Map<String, dynamic> jsonMap = json;
+        if (jsonMap.containsKey('error')) {
+          throw jsonMap['error'];
+        }
+        return jsonMap['result']['result']['kernelBytes'];
+      });
+    } else {
+      // fallback to compile using kernel service
+      Map compileExpressionParams = {
+        'method': '_compileExpression',
+        'id': _message.serial,
+        'params': compileParams,
+      };
+      var compileExpression = new Message._fromJsonRpcRequest(
+          _message.client, compileExpressionParams);
+
+      return _isolate
+          .routeRequest(_service, compileExpression)
+          .then((Response response) => response.decodeJson())
+          .then((dynamic json) {
+        if (json['result'] != null) {
+          return json['result']['kernelBytes'];
+        }
+        throw json['error']['data']['details'];
+      });
+    }
+  }
+
+  Future<Response> _evaluateCompiledExpression(String kernelBase64) {
+    if (kernelBase64.isNotEmpty) {
+      Map<String, dynamic> params = _setupParams();
+      params['isolateId'] = _message.params['isolateId'];
+      params['kernelBytes'] = kernelBase64;
+      params['disableBreakpoints'] = _message.params['disableBreakpoints'];
+      Map runParams = {
+        'method': '_evaluateCompiledExpression',
+        'id': _message.serial,
+        'params': params,
+      };
+      if (_message.params['scope'] != null) {
+        runParams['params']['scope'] = _message.params['scope'];
+      }
+      var runExpression =
+          new Message._fromJsonRpcRequest(_message.client, runParams);
+      return _isolate.routeRequest(_service, runExpression); // _message
+    } else {
+      // empty kernel indicates dart1 mode
+      return _isolate.routeRequest(_service, _message);
+    }
+  }
+
+  Map<String, dynamic> _setupParams() {
+    if (_message.method == 'evaluateInFrame') {
+      return <String, dynamic>{'frameIndex': _message.params['frameIndex']};
+    } else {
+      assert(_message.method == 'evaluate');
+      return <String, dynamic>{'targetId': _message.params['targetId']};
+    }
+  }
+}
diff --git a/sdk_nnbd/lib/vmservice/vmservice.dart b/sdk_nnbd/lib/vmservice/vmservice.dart
new file mode 100644
index 0000000..0c340ee
--- /dev/null
+++ b/sdk_nnbd/lib/vmservice/vmservice.dart
@@ -0,0 +1,683 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library dart._vmservice;
+
+import 'dart:async';
+import 'dart:collection';
+import 'dart:convert';
+import 'dart:isolate';
+import 'dart:math';
+import 'dart:typed_data';
+
+part 'asset.dart';
+part 'client.dart';
+part 'devfs.dart';
+part 'constants.dart';
+part 'running_isolate.dart';
+part 'running_isolates.dart';
+part 'message.dart';
+part 'message_router.dart';
+part 'named_lookup.dart';
+
+final RawReceivePort isolateControlPort = new RawReceivePort();
+final RawReceivePort scriptLoadPort = new RawReceivePort();
+
+abstract class IsolateEmbedderData {
+  void cleanup();
+}
+
+String _makeAuthToken() {
+  final kTokenByteSize = 8;
+  Uint8List bytes = new Uint8List(kTokenByteSize);
+  Random random = new Random.secure();
+  for (int i = 0; i < kTokenByteSize; i++) {
+    bytes[i] = random.nextInt(256);
+  }
+  return base64Url.encode(bytes);
+}
+
+// The randomly generated auth token used to access the VM service.
+final String serviceAuthToken = _makeAuthToken();
+
+// This is for use by the embedder. It is a map from the isolateId to
+// anything implementing IsolateEmbedderData. When an isolate goes away,
+// the cleanup method will be invoked after being removed from the map.
+final Map<int, IsolateEmbedderData> isolateEmbedderData =
+    new Map<int, IsolateEmbedderData>();
+
+// These must be kept in sync with the declarations in vm/json_stream.h.
+const kParseError = -32700;
+const kInvalidRequest = -32600;
+const kMethodNotFound = -32601;
+const kInvalidParams = -32602;
+const kInternalError = -32603;
+
+const kExtensionError = -32000;
+
+const kFeatureDisabled = 100;
+const kCannotAddBreakpoint = 102;
+const kStreamAlreadySubscribed = 103;
+const kStreamNotSubscribed = 104;
+const kIsolateMustBeRunnable = 105;
+const kIsolateMustBePaused = 106;
+const kCannotResume = 107;
+const kIsolateIsReloading = 108;
+const kIsolateReloadBarred = 109;
+const kIsolateMustHaveReloaded = 110;
+const kServiceAlreadyRegistered = 111;
+const kServiceDisappeared = 112;
+const kExpressionCompilationError = 113;
+const kInvalidTimelineRequest = 114;
+
+// Experimental (used in private rpcs).
+const kFileSystemAlreadyExists = 1001;
+const kFileSystemDoesNotExist = 1002;
+const kFileDoesNotExist = 1003;
+
+var _errorMessages = {
+  kInvalidParams: 'Invalid params',
+  kInternalError: 'Internal error',
+  kFeatureDisabled: 'Feature is disabled',
+  kStreamAlreadySubscribed: 'Stream already subscribed',
+  kStreamNotSubscribed: 'Stream not subscribed',
+  kFileSystemAlreadyExists: 'File system already exists',
+  kFileSystemDoesNotExist: 'File system does not exist',
+  kFileDoesNotExist: 'File does not exist',
+  kServiceAlreadyRegistered: 'Service already registered',
+  kServiceDisappeared: 'Service has disappeared',
+  kExpressionCompilationError: 'Expression compilation error',
+  kInvalidTimelineRequest: 'The timeline related request could not be completed'
+      'due to the current configuration',
+};
+
+String encodeRpcError(Message message, int code, {String details}) {
+  var response = {
+    'jsonrpc': '2.0',
+    'id': message.serial,
+    'error': {
+      'code': code,
+      'message': _errorMessages[code],
+    },
+  };
+  if (details != null) {
+    response['error']['data'] = {
+      'details': details,
+    };
+  }
+  return json.encode(response);
+}
+
+String encodeMissingParamError(Message message, String param) {
+  return encodeRpcError(message, kInvalidParams,
+      details: "${message.method} expects the '${param}' parameter");
+}
+
+String encodeInvalidParamError(Message message, String param) {
+  var value = message.params[param];
+  return encodeRpcError(message, kInvalidParams,
+      details: "${message.method}: invalid '${param}' parameter: ${value}");
+}
+
+String encodeCompilationError(Message message, String diagnostic) {
+  return encodeRpcError(message, kExpressionCompilationError,
+      details: diagnostic);
+}
+
+String encodeResult(Message message, Map result) {
+  var response = {
+    'jsonrpc': '2.0',
+    'id': message.serial,
+    'result': result,
+  };
+  return json.encode(response);
+}
+
+String encodeSuccess(Message message) {
+  return encodeResult(message, {'type': 'Success'});
+}
+
+const shortDelay = const Duration(milliseconds: 10);
+
+/// Called when the server should be started.
+typedef Future ServerStartCallback();
+
+/// Called when the server should be stopped.
+typedef Future ServerStopCallback();
+
+/// Called when the service is exiting.
+typedef Future CleanupCallback();
+
+/// Called to create a temporary directory
+typedef Future<Uri> CreateTempDirCallback(String base);
+
+/// Called to delete a directory
+typedef Future DeleteDirCallback(Uri path);
+
+/// Called to write a file.
+typedef Future WriteFileCallback(Uri path, List<int> bytes);
+
+/// Called to write a stream into a file.
+typedef Future WriteStreamFileCallback(Uri path, Stream<List<int>> bytes);
+
+/// Called to read a file.
+typedef Future<List<int>> ReadFileCallback(Uri path);
+
+/// Called to list all files under some path.
+typedef Future<List<Map<String, dynamic>>> ListFilesCallback(Uri path);
+
+/// Called when we need information about the server.
+typedef Future<Uri> ServerInformamessage_routertionCallback();
+
+/// Called when we need information about the server.
+typedef Future<Uri> ServerInformationCallback();
+
+/// Called when we want to [enable] or disable the web server.
+typedef Future<Uri> WebServerControlCallback(bool enable);
+
+/// Hooks that are setup by the embedder.
+class VMServiceEmbedderHooks {
+  static ServerStartCallback serverStart;
+  static ServerStopCallback serverStop;
+  static CleanupCallback cleanup;
+  static CreateTempDirCallback createTempDir;
+  static DeleteDirCallback deleteDir;
+  static WriteFileCallback writeFile;
+  static WriteStreamFileCallback writeStreamFile;
+  static ReadFileCallback readFile;
+  static ListFilesCallback listFiles;
+  static ServerInformationCallback serverInformation;
+  static WebServerControlCallback webServerControl;
+}
+
+class VMService extends MessageRouter {
+  static VMService _instance;
+
+  static const serviceNamespace = 's';
+
+  /// Collection of currently connected clients.
+  final NamedLookup<Client> clients =
+      new NamedLookup<Client>(prologue: serviceNamespace);
+  final IdGenerator _serviceRequests = new IdGenerator(prologue: 'sr');
+
+  /// Collection of currently running isolates.
+  RunningIsolates runningIsolates = new RunningIsolates();
+
+  /// Flag to indicate VM service is exiting.
+  bool isExiting = false;
+
+  /// A port used to receive events from the VM.
+  final RawReceivePort eventPort;
+
+  final devfs = new DevFS();
+
+  void _addClient(Client client) {
+    assert(client.streams.isEmpty);
+    assert(client.services.isEmpty);
+    clients.add(client);
+  }
+
+  void _removeClient(Client client) {
+    final namespace = clients.keyOf(client);
+    clients.remove(client);
+    for (var streamId in client.streams) {
+      if (!_isAnyClientSubscribed(streamId)) {
+        _vmCancelStream(streamId);
+      }
+    }
+    for (var service in client.services.keys) {
+      _eventMessageHandler(
+          'Service',
+          new Response.json({
+            'jsonrpc': '2.0',
+            'method': 'streamNotify',
+            'params': {
+              'streamId': 'Service',
+              'event': {
+                "type": "Event",
+                "kind": "ServiceUnregistered",
+                'timestamp': new DateTime.now().millisecondsSinceEpoch,
+                'service': service,
+                'method': namespace + '.' + service,
+              }
+            }
+          }));
+    }
+    // Complete all requests as failed
+    for (var handle in client.serviceHandles.values) {
+      handle(null);
+    }
+  }
+
+  void _eventMessageHandler(String streamId, Response event) {
+    for (var client in clients) {
+      if (client.sendEvents && client.streams.contains(streamId)) {
+        client.post(event);
+      }
+    }
+  }
+
+  void _controlMessageHandler(int code, int portId, SendPort sp, String name) {
+    switch (code) {
+      case Constants.ISOLATE_STARTUP_MESSAGE_ID:
+        runningIsolates.isolateStartup(portId, sp, name);
+        break;
+      case Constants.ISOLATE_SHUTDOWN_MESSAGE_ID:
+        runningIsolates.isolateShutdown(portId, sp);
+        IsolateEmbedderData ied = isolateEmbedderData.remove(portId);
+        if (ied != null) {
+          ied.cleanup();
+        }
+        break;
+    }
+  }
+
+  Future<Null> _serverMessageHandler(int code, SendPort sp, bool enable) async {
+    switch (code) {
+      case Constants.WEB_SERVER_CONTROL_MESSAGE_ID:
+        if (VMServiceEmbedderHooks.webServerControl == null) {
+          sp.send(null);
+          return;
+        }
+        Uri uri = await VMServiceEmbedderHooks.webServerControl(enable);
+        sp.send(uri);
+        break;
+      case Constants.SERVER_INFO_MESSAGE_ID:
+        if (VMServiceEmbedderHooks.serverInformation == null) {
+          sp.send(null);
+          return;
+        }
+        Uri uri = await VMServiceEmbedderHooks.serverInformation();
+        sp.send(uri);
+        break;
+    }
+  }
+
+  Future<Null> _handleNativeRpcCall(message, SendPort replyPort) async {
+    // Keep in sync with "runtime/vm/service_isolate.cc:InvokeServiceRpc".
+    Response response;
+
+    try {
+      final Message rpc = new Message.fromJsonRpc(
+          null, json.decode(utf8.decode(message as List<int>)));
+      if (rpc.type != MessageType.Request) {
+        response = new Response.internalError(
+            'The client sent a non-request json-rpc message.');
+      } else {
+        response = await routeRequest(this, rpc);
+      }
+    } catch (exception) {
+      response = new Response.internalError(
+          'The rpc call resulted in exception: $exception.');
+    }
+    List<int> bytes;
+    switch (response.kind) {
+      case ResponsePayloadKind.String:
+        bytes = utf8.encode(response.payload);
+        bytes = bytes is Uint8List ? bytes : new Uint8List.fromList(bytes);
+        break;
+      case ResponsePayloadKind.Binary:
+      case ResponsePayloadKind.Utf8String:
+        bytes = response.payload as Uint8List;
+        break;
+    }
+    replyPort.send(bytes);
+  }
+
+  Future _exit() async {
+    isExiting = true;
+
+    // Stop the server.
+    if (VMServiceEmbedderHooks.serverStop != null) {
+      await VMServiceEmbedderHooks.serverStop();
+    }
+
+    // Close receive ports.
+    isolateControlPort.close();
+    scriptLoadPort.close();
+
+    // Create a copy of the set as a list because client.disconnect() will
+    // alter the connected clients set.
+    var clientsList = clients.toList();
+    for (var client in clientsList) {
+      client.disconnect();
+    }
+    devfs.cleanup();
+    if (VMServiceEmbedderHooks.cleanup != null) {
+      await VMServiceEmbedderHooks.cleanup();
+    }
+
+    // Notify the VM that we have exited.
+    _onExit();
+  }
+
+  void messageHandler(message) {
+    if (message is List) {
+      if (message.length == 2) {
+        // This is an event.
+        _eventMessageHandler(message[0], new Response.from(message[1]));
+        return;
+      }
+      if (message.length == 1) {
+        // This is a control message directing the vm service to exit.
+        assert(message[0] == Constants.SERVICE_EXIT_MESSAGE_ID);
+        _exit();
+        return;
+      }
+      if (message.length == 3) {
+        final opcode = message[0];
+        if (opcode == Constants.METHOD_CALL_FROM_NATIVE) {
+          _handleNativeRpcCall(message[1], message[2]);
+          return;
+        } else {
+          // This is a message interacting with the web server.
+          assert((opcode == Constants.WEB_SERVER_CONTROL_MESSAGE_ID) ||
+              (opcode == Constants.SERVER_INFO_MESSAGE_ID));
+          _serverMessageHandler(message[0], message[1], message[2]);
+          return;
+        }
+      }
+      if (message.length == 4) {
+        // This is a message informing us of the birth or death of an
+        // isolate.
+        _controlMessageHandler(message[0], message[1], message[2], message[3]);
+        return;
+      }
+    }
+    print('Internal vm-service error: ignoring illegal message: $message');
+  }
+
+  VMService._internal() : eventPort = isolateControlPort {
+    eventPort.handler = messageHandler;
+  }
+
+  factory VMService() {
+    if (VMService._instance == null) {
+      VMService._instance = new VMService._internal();
+      _onStart();
+    }
+    return _instance;
+  }
+
+  bool _isAnyClientSubscribed(String streamId) {
+    for (var client in clients) {
+      if (client.streams.contains(streamId)) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  Client _findFirstClientThatHandlesService(String service) {
+    if (clients != null) {
+      for (Client c in clients) {
+        if (c.services.containsKey(service)) {
+          return c;
+        }
+      }
+    }
+    return null;
+  }
+
+  static const kServiceStream = 'Service';
+  static const serviceStreams = const [kServiceStream];
+
+  Future<String> _streamListen(Message message) async {
+    var client = message.client;
+    var streamId = message.params['streamId'];
+
+    if (client.streams.contains(streamId)) {
+      return encodeRpcError(message, kStreamAlreadySubscribed);
+    }
+    if (!_isAnyClientSubscribed(streamId)) {
+      if (!serviceStreams.contains(streamId) && !_vmListenStream(streamId)) {
+        return encodeRpcError(message, kInvalidParams,
+            details: "streamListen: invalid 'streamId' parameter: ${streamId}");
+      }
+    }
+
+    // Some streams can generate events or side effects after registration
+    switch (streamId) {
+      case kServiceStream:
+        for (Client c in clients) {
+          if (c == client) continue;
+          for (String service in c.services.keys) {
+            _sendServiceRegisteredEvent(c, service, target: client);
+          }
+        }
+        ;
+        break;
+    }
+
+    client.streams.add(streamId);
+    return encodeSuccess(message);
+  }
+
+  Future<String> _streamCancel(Message message) async {
+    var client = message.client;
+    var streamId = message.params['streamId'];
+
+    if (!client.streams.contains(streamId)) {
+      return encodeRpcError(message, kStreamNotSubscribed);
+    }
+    client.streams.remove(streamId);
+    if (!serviceStreams.contains(streamId) &&
+        !_isAnyClientSubscribed(streamId)) {
+      _vmCancelStream(streamId);
+    }
+
+    return encodeSuccess(message);
+  }
+
+  static bool _hasNamespace(String method) =>
+      method.contains('.') &&
+      _getNamespace(method).startsWith(serviceNamespace);
+  static String _getNamespace(String method) => method.split('.').first;
+  static String _getMethod(String method) => method.split('.').last;
+
+  Future<String> _registerService(Message message) async {
+    final client = message.client;
+    final service = message.params['service'];
+    final alias = message.params['alias'];
+
+    if (service is! String || service == '') {
+      return encodeRpcError(message, kInvalidParams,
+          details: "registerService: invalid 'service' parameter: ${service}");
+    }
+    if (alias is! String || alias == '') {
+      return encodeRpcError(message, kInvalidParams,
+          details: "registerService: invalid 'alias' parameter: ${alias}");
+    }
+    if (client.services.containsKey(service)) {
+      return encodeRpcError(message, kServiceAlreadyRegistered);
+    }
+    client.services[service] = alias;
+
+    bool removed;
+    try {
+      // Do not send streaming events to the client which registers the service
+      removed = client.streams.remove(kServiceStream);
+      await _sendServiceRegisteredEvent(client, service);
+    } finally {
+      if (removed) client.streams.add(kServiceStream);
+    }
+
+    return encodeSuccess(message);
+  }
+
+  _sendServiceRegisteredEvent(Client client, String service,
+      {Client target}) async {
+    final namespace = clients.keyOf(client);
+    final alias = client.services[service];
+    final event = new Response.json({
+      'jsonrpc': '2.0',
+      'method': 'streamNotify',
+      'params': {
+        'streamId': kServiceStream,
+        'event': {
+          "type": "Event",
+          "kind": "ServiceRegistered",
+          'timestamp': new DateTime.now().millisecondsSinceEpoch,
+          'service': service,
+          'method': namespace + '.' + service,
+          'alias': alias
+        }
+      }
+    });
+    if (target == null) {
+      _eventMessageHandler(kServiceStream, event);
+    } else {
+      target.post(event);
+    }
+  }
+
+  Future<String> _handleService(Message message) async {
+    final namespace = _getNamespace(message.method);
+    final method = _getMethod(message.method);
+    final client = clients[namespace];
+    if (client != null) {
+      if (client.services.containsKey(method)) {
+        final id = _serviceRequests.newId();
+        final oldId = message.serial;
+        final completer = new Completer<String>();
+        client.serviceHandles[id] = (Message m) {
+          if (m != null) {
+            completer.complete(json.encode(m.forwardToJson({'id': oldId})));
+          } else {
+            completer.complete(encodeRpcError(message, kServiceDisappeared));
+          }
+        };
+        client.post(new Response.json(
+            message.forwardToJson({'id': id, 'method': method})));
+        return completer.future;
+      }
+    }
+    return encodeRpcError(message, kMethodNotFound,
+        details: "Unknown service: ${message.method}");
+  }
+
+  Future<String> _spawnUri(Message message) async {
+    var token = message.params['token'];
+    if (token == null) {
+      return encodeMissingParamError(message, 'token');
+    }
+    if (token is! String) {
+      return encodeInvalidParamError(message, 'token');
+    }
+    var uri = message.params['uri'];
+    if (uri == null) {
+      return encodeMissingParamError(message, 'uri');
+    }
+    if (uri is! String) {
+      return encodeInvalidParamError(message, 'uri');
+    }
+    var args = message.params['args'];
+    var argsOfString = new List<String>();
+    if (args != null) {
+      if (args is! List) {
+        return encodeInvalidParamError(message, 'args');
+      }
+      for (var arg in args) {
+        if (arg is! String) {
+          return encodeInvalidParamError(message, 'args');
+        }
+        argsOfString.add(arg);
+      }
+    }
+    var msg = message.params['message'];
+
+    Isolate.spawnUri(Uri.parse(uri), argsOfString, msg).then((isolate) {
+      _spawnUriNotify(isolate.controlPort, token);
+    }).catchError((e) {
+      _spawnUriNotify(e.toString(), token);
+    });
+
+    return encodeSuccess(message);
+  }
+
+  Future<Response> routeRequest(VMService _, Message message) async {
+    final response = await _routeRequestImpl(message);
+    if (response == null) {
+      // We should only have a null response for Notifications.
+      assert(message.type == MessageType.Notification);
+      return null;
+    }
+    return new Response.from(response);
+  }
+
+  Future _routeRequestImpl(Message message) async {
+    try {
+      if (message.completed) {
+        return await message.response;
+      }
+      if (message.method == 'streamListen') {
+        return await _streamListen(message);
+      }
+      if (message.method == 'streamCancel') {
+        return await _streamCancel(message);
+      }
+      if (message.method == 'registerService') {
+        return await _registerService(message);
+      }
+      if (message.method == '_spawnUri') {
+        return await _spawnUri(message);
+      }
+      if (devfs.shouldHandleMessage(message)) {
+        return await devfs.handleMessage(message);
+      }
+      if (_hasNamespace(message.method)) {
+        return await _handleService(message);
+      }
+      if (message.params['isolateId'] != null) {
+        return await runningIsolates.routeRequest(this, message);
+      }
+      return await message.sendToVM();
+    } catch (e, st) {
+      message.setErrorResponse(kInternalError, 'Unexpected exception:$e\n$st');
+      return message.response;
+    }
+  }
+
+  void routeResponse(message) {
+    final client = message.client;
+    if (client.serviceHandles.containsKey(message.serial)) {
+      client.serviceHandles.remove(message.serial)(message);
+      _serviceRequests.release(message.serial);
+    }
+  }
+}
+
+@pragma("vm:entry-point", "call")
+RawReceivePort boot() {
+  // Return the port we expect isolate control messages on.
+  return isolateControlPort;
+}
+
+@pragma("vm:entry-point", !const bool.fromEnvironment("dart.vm.product"))
+void _registerIsolate(int port_id, SendPort sp, String name) {
+  var service = new VMService();
+  service.runningIsolates.isolateStartup(port_id, sp, name);
+}
+
+/// Notify the VM that the service is running.
+void _onStart() native "VMService_OnStart";
+
+/// Notify the VM that the service is no longer running.
+void _onExit() native "VMService_OnExit";
+
+/// Notify the VM that the server's address has changed.
+void onServerAddressChange(String address)
+    native "VMService_OnServerAddressChange";
+
+/// Subscribe to a service stream.
+bool _vmListenStream(String streamId) native "VMService_ListenStream";
+
+/// Cancel a subscription to a service stream.
+void _vmCancelStream(String streamId) native "VMService_CancelStream";
+
+/// Get the bytes to the tar archive.
+Uint8List _requestAssets() native "VMService_RequestAssets";
+
+/// Notify the vm service that an isolate has been spawned via rpc.
+void _spawnUriNotify(obj, String token) native "VMService_spawnUriNotify";
diff --git a/sdk_nnbd/lib/vmservice/vmservice_sources.gni b/sdk_nnbd/lib/vmservice/vmservice_sources.gni
new file mode 100644
index 0000000..b8cf5bf
--- /dev/null
+++ b/sdk_nnbd/lib/vmservice/vmservice_sources.gni
@@ -0,0 +1,19 @@
+# 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.
+
+# Sources that make up the library "dart:_vmservice".
+vmservice_sdk_sources = [
+  "vmservice.dart",
+
+  # The above file needs to be first as it imports required libraries.
+  "asset.dart",
+  "client.dart",
+  "constants.dart",
+  "devfs.dart",
+  "running_isolate.dart",
+  "running_isolates.dart",
+  "message.dart",
+  "message_router.dart",
+  "named_lookup.dart",
+]
diff --git a/sdk_nnbd/lib/vmservice_libraries.json b/sdk_nnbd/lib/vmservice_libraries.json
new file mode 100644
index 0000000..c25ffe5
--- /dev/null
+++ b/sdk_nnbd/lib/vmservice_libraries.json
@@ -0,0 +1,12 @@
+{
+  "vm": {
+    "libraries": {
+      "vmservice_io": {
+        "uri": "../../runtime/bin/vmservice/vmservice_io.dart"
+      },
+      "_vmservice": {
+        "uri": "vmservice/vmservice.dart"
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/sdk_nnbd/lib/vmservice_libraries.yaml b/sdk_nnbd/lib/vmservice_libraries.yaml
new file mode 100644
index 0000000..737e361
--- /dev/null
+++ b/sdk_nnbd/lib/vmservice_libraries.yaml
@@ -0,0 +1,20 @@
+# 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.
+
+# Note: if you edit this file, you must also edit libraries.json in this
+# directory:
+#
+#     python ./tools/yaml2json.py sdk/lib/vmservice_libraries.yaml sdk/lib/vmservice_libraries.json
+#
+# We currently have several different files that needs to be updated when
+# changing libraries, sources, and patch files.  See
+# https://github.com/dart-lang/sdk/issues/28836.
+
+vm:
+  libraries:
+    _vmservice:
+      uri: "vmservice/vmservice.dart"
+
+    vmservice_io:
+      uri: "../../runtime/bin/vmservice/vmservice_io.dart"
diff --git a/sdk_nnbd/lib/wasm/wasm.dart b/sdk_nnbd/lib/wasm/wasm.dart
new file mode 100644
index 0000000..edf0887
--- /dev/null
+++ b/sdk_nnbd/lib/wasm/wasm.dart
@@ -0,0 +1,13 @@
+// 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.
+
+/// {@category VM}
+/// {@nodoc}
+library dart.wasm;
+
+int callWasm(String name, int arg) {
+  return _callWasm(name, arg);
+}
+
+external int _callWasm(String name, int arg);
diff --git a/sdk_nnbd/lib/wasm/wasm_sources.gni b/sdk_nnbd/lib/wasm/wasm_sources.gni
new file mode 100644
index 0000000..dcd359a
--- /dev/null
+++ b/sdk_nnbd/lib/wasm/wasm_sources.gni
@@ -0,0 +1,7 @@
+# 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.
+
+wasm_sdk_sources = [
+  "wasm.dart",
+]
diff --git a/sdk_nnbd/lib/web_audio/dart2js/web_audio_dart2js.dart b/sdk_nnbd/lib/web_audio/dart2js/web_audio_dart2js.dart
new file mode 100644
index 0000000..ef2ee67
--- /dev/null
+++ b/sdk_nnbd/lib/web_audio/dart2js/web_audio_dart2js.dart
@@ -0,0 +1,1246 @@
+/**
+ * High-fidelity audio programming in the browser.
+ *
+ * {@category Web}
+ */
+library dart.dom.web_audio;
+
+import 'dart:async';
+import 'dart:collection' hide LinkedList, LinkedListEntry;
+import 'dart:_internal' show FixedLengthListMixin;
+import 'dart:html';
+import 'dart:html_common';
+import 'dart:_native_typed_data';
+import 'dart:typed_data';
+import 'dart:_foreign_helper' show JS;
+import 'dart:_interceptors' show Interceptor;
+// DO NOT EDIT - unless you are editing documentation as per:
+// https://code.google.com/p/dart/wiki/ContributingHTMLDocumentation
+// Auto-generated dart:audio library.
+
+import 'dart:_js_helper'
+    show
+        Creates,
+        JavaScriptIndexingBehavior,
+        JSName,
+        Native,
+        Returns,
+        convertDartClosureToJS;
+
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("AnalyserNode,RealtimeAnalyserNode")
+class AnalyserNode extends AudioNode {
+  // To suppress missing implicit constructor warnings.
+  factory AnalyserNode._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory AnalyserNode(BaseAudioContext context, [Map options]) {
+    if (options != null) {
+      var options_1 = convertDartToNative_Dictionary(options);
+      return AnalyserNode._create_1(context, options_1);
+    }
+    return AnalyserNode._create_2(context);
+  }
+  static AnalyserNode _create_1(context, options) =>
+      JS('AnalyserNode', 'new AnalyserNode(#,#)', context, options);
+  static AnalyserNode _create_2(context) =>
+      JS('AnalyserNode', 'new AnalyserNode(#)', context);
+
+  int fftSize;
+
+  final int frequencyBinCount;
+
+  num maxDecibels;
+
+  num minDecibels;
+
+  num smoothingTimeConstant;
+
+  void getByteFrequencyData(Uint8List array) native;
+
+  void getByteTimeDomainData(Uint8List array) native;
+
+  void getFloatFrequencyData(Float32List array) native;
+
+  void getFloatTimeDomainData(Float32List array) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("AudioBuffer")
+class AudioBuffer extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory AudioBuffer._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory AudioBuffer(Map options) {
+    var options_1 = convertDartToNative_Dictionary(options);
+    return AudioBuffer._create_1(options_1);
+  }
+  static AudioBuffer _create_1(options) =>
+      JS('AudioBuffer', 'new AudioBuffer(#)', options);
+
+  final num duration;
+
+  final int length;
+
+  final int numberOfChannels;
+
+  final num sampleRate;
+
+  void copyFromChannel(Float32List destination, int channelNumber,
+      [int startInChannel]) native;
+
+  void copyToChannel(Float32List source, int channelNumber,
+      [int startInChannel]) native;
+
+  Float32List getChannelData(int channelIndex) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.FIREFOX)
+@Native("AudioBufferSourceNode")
+class AudioBufferSourceNode extends AudioScheduledSourceNode {
+  // To suppress missing implicit constructor warnings.
+  factory AudioBufferSourceNode._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory AudioBufferSourceNode(BaseAudioContext context, [Map options]) {
+    if (options != null) {
+      var options_1 = convertDartToNative_Dictionary(options);
+      return AudioBufferSourceNode._create_1(context, options_1);
+    }
+    return AudioBufferSourceNode._create_2(context);
+  }
+  static AudioBufferSourceNode _create_1(context, options) => JS(
+      'AudioBufferSourceNode',
+      'new AudioBufferSourceNode(#,#)',
+      context,
+      options);
+  static AudioBufferSourceNode _create_2(context) =>
+      JS('AudioBufferSourceNode', 'new AudioBufferSourceNode(#)', context);
+
+  AudioBuffer buffer;
+
+  final AudioParam detune;
+
+  bool loop;
+
+  num loopEnd;
+
+  num loopStart;
+
+  final AudioParam playbackRate;
+
+  void start([num when, num grainOffset, num grainDuration]) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.FIREFOX)
+@Native("AudioContext,webkitAudioContext")
+class AudioContext extends BaseAudioContext {
+  // To suppress missing implicit constructor warnings.
+  factory AudioContext._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  /// Checks if this type is supported on the current platform.
+  static bool get supported =>
+      JS('bool', '!!(window.AudioContext || window.webkitAudioContext)');
+
+  final num baseLatency;
+
+  Future close() => promiseToFuture(JS("", "#.close()", this));
+
+  Map getOutputTimestamp() {
+    return convertNativeToDart_Dictionary(_getOutputTimestamp_1());
+  }
+
+  @JSName('getOutputTimestamp')
+  _getOutputTimestamp_1() native;
+
+  Future suspend() => promiseToFuture(JS("", "#.suspend()", this));
+
+  factory AudioContext() => JS('AudioContext',
+      'new (window.AudioContext || window.webkitAudioContext)()');
+
+  GainNode createGain() {
+    if (JS('bool', '#.createGain !== undefined', this)) {
+      return JS('GainNode', '#.createGain()', this);
+    } else {
+      return JS('GainNode', '#.createGainNode()', this);
+    }
+  }
+
+  ScriptProcessorNode createScriptProcessor(
+      [int bufferSize, int numberOfInputChannels, int numberOfOutputChannels]) {
+    var function = JS(
+        '=Object',
+        '#.createScriptProcessor || '
+            '#.createJavaScriptNode',
+        this,
+        this);
+    if (numberOfOutputChannels != null) {
+      return JS('ScriptProcessorNode', '#.call(#, #, #, #)', function, this,
+          bufferSize, numberOfInputChannels, numberOfOutputChannels);
+    } else if (numberOfInputChannels != null) {
+      return JS('ScriptProcessorNode', '#.call(#, #, #)', function, this,
+          bufferSize, numberOfInputChannels);
+    } else if (bufferSize != null) {
+      return JS(
+          'ScriptProcessorNode', '#.call(#, #)', function, this, bufferSize);
+    } else {
+      return JS('ScriptProcessorNode', '#.call(#)', function, this);
+    }
+  }
+
+  @JSName('decodeAudioData')
+  Future _decodeAudioData(ByteBuffer audioData,
+      [DecodeSuccessCallback successCallback,
+      DecodeErrorCallback errorCallback]) native;
+
+  Future<AudioBuffer> decodeAudioData(ByteBuffer audioData,
+      [DecodeSuccessCallback successCallback,
+      DecodeErrorCallback errorCallback]) {
+    if (successCallback != null && errorCallback != null) {
+      return _decodeAudioData(audioData, successCallback, errorCallback);
+    }
+
+    var completer = new Completer<AudioBuffer>();
+    _decodeAudioData(audioData, (value) {
+      completer.complete(value);
+    }, (error) {
+      if (error == null) {
+        completer.completeError('');
+      } else {
+        completer.completeError(error);
+      }
+    });
+    return completer.future;
+  }
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("AudioDestinationNode")
+class AudioDestinationNode extends AudioNode {
+  // To suppress missing implicit constructor warnings.
+  factory AudioDestinationNode._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final int maxChannelCount;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("AudioListener")
+class AudioListener extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory AudioListener._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final AudioParam forwardX;
+
+  final AudioParam forwardY;
+
+  final AudioParam forwardZ;
+
+  final AudioParam positionX;
+
+  final AudioParam positionY;
+
+  final AudioParam positionZ;
+
+  final AudioParam upX;
+
+  final AudioParam upY;
+
+  final AudioParam upZ;
+
+  void setOrientation(num x, num y, num z, num xUp, num yUp, num zUp) native;
+
+  void setPosition(num x, num y, num z) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("AudioNode")
+class AudioNode extends EventTarget {
+  // To suppress missing implicit constructor warnings.
+  factory AudioNode._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  int channelCount;
+
+  String channelCountMode;
+
+  String channelInterpretation;
+
+  final BaseAudioContext context;
+
+  final int numberOfInputs;
+
+  final int numberOfOutputs;
+
+  @JSName('connect')
+  AudioNode _connect(destination, [int output, int input]) native;
+
+  void disconnect([destination_OR_output, int output, int input]) native;
+
+  void connectNode(AudioNode destination, [int output = 0, int input = 0]) {
+    _connect(destination, output, input);
+  }
+
+  void connectParam(AudioParam destination, [int output = 0]) {
+    _connect(destination, output);
+  }
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("AudioParam")
+class AudioParam extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory AudioParam._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final num defaultValue;
+
+  final num maxValue;
+
+  final num minValue;
+
+  num value;
+
+  AudioParam cancelAndHoldAtTime(num startTime) native;
+
+  AudioParam cancelScheduledValues(num startTime) native;
+
+  AudioParam exponentialRampToValueAtTime(num value, num time) native;
+
+  AudioParam linearRampToValueAtTime(num value, num time) native;
+
+  AudioParam setTargetAtTime(num target, num time, num timeConstant) native;
+
+  AudioParam setValueAtTime(num value, num time) native;
+
+  AudioParam setValueCurveAtTime(List<num> values, num time, num duration)
+      native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("AudioParamMap")
+class AudioParamMap extends Interceptor with MapMixin<String, dynamic> {
+  // To suppress missing implicit constructor warnings.
+  factory AudioParamMap._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  Map _getItem(String key) =>
+      convertNativeToDart_Dictionary(JS('', '#.get(#)', this, key));
+
+  void addAll(Map<String, dynamic> other) {
+    throw new UnsupportedError("Not supported");
+  }
+
+  bool containsValue(dynamic value) => values.any((e) => e == value);
+
+  bool containsKey(dynamic key) => _getItem(key) != null;
+
+  Map operator [](dynamic key) => _getItem(key);
+
+  void forEach(void f(String key, dynamic value)) {
+    var entries = JS('', '#.entries()', this);
+    while (true) {
+      var entry = JS('', '#.next()', entries);
+      if (JS('bool', '#.done', entry)) return;
+      f(JS('String', '#.value[0]', entry),
+          convertNativeToDart_Dictionary(JS('', '#.value[1]', entry)));
+    }
+  }
+
+  Iterable<String> get keys {
+    final keys = <String>[];
+    forEach((k, v) => keys.add(k));
+    return keys;
+  }
+
+  Iterable<Map> get values {
+    final values = <Map>[];
+    forEach((k, v) => values.add(v));
+    return values;
+  }
+
+  int get length => JS('int', '#.size', this);
+
+  bool get isEmpty => length == 0;
+
+  bool get isNotEmpty => !isEmpty;
+
+  void operator []=(String key, dynamic value) {
+    throw new UnsupportedError("Not supported");
+  }
+
+  dynamic putIfAbsent(String key, dynamic ifAbsent()) {
+    throw new UnsupportedError("Not supported");
+  }
+
+  String remove(dynamic key) {
+    throw new UnsupportedError("Not supported");
+  }
+
+  void clear() {
+    throw new UnsupportedError("Not supported");
+  }
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("AudioProcessingEvent")
+class AudioProcessingEvent extends Event {
+  // To suppress missing implicit constructor warnings.
+  factory AudioProcessingEvent._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory AudioProcessingEvent(String type, Map eventInitDict) {
+    var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+    return AudioProcessingEvent._create_1(type, eventInitDict_1);
+  }
+  static AudioProcessingEvent _create_1(type, eventInitDict) => JS(
+      'AudioProcessingEvent',
+      'new AudioProcessingEvent(#,#)',
+      type,
+      eventInitDict);
+
+  final AudioBuffer inputBuffer;
+
+  final AudioBuffer outputBuffer;
+
+  final num playbackTime;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("AudioScheduledSourceNode")
+class AudioScheduledSourceNode extends AudioNode {
+  // To suppress missing implicit constructor warnings.
+  factory AudioScheduledSourceNode._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  static const EventStreamProvider<Event> endedEvent =
+      const EventStreamProvider<Event>('ended');
+
+  @JSName('start')
+  void start2([num when]) native;
+
+  void stop([num when]) native;
+
+  Stream<Event> get onEnded => endedEvent.forTarget(this);
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("AudioTrack")
+class AudioTrack extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory AudioTrack._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  bool enabled;
+
+  final String id;
+
+  final String kind;
+
+  final String label;
+
+  final String language;
+
+  final SourceBuffer sourceBuffer;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("AudioTrackList")
+class AudioTrackList extends EventTarget {
+  // To suppress missing implicit constructor warnings.
+  factory AudioTrackList._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  static const EventStreamProvider<Event> changeEvent =
+      const EventStreamProvider<Event>('change');
+
+  final int length;
+
+  AudioTrack __getter__(int index) native;
+
+  AudioTrack getTrackById(String id) native;
+
+  Stream<Event> get onChange => changeEvent.forTarget(this);
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("AudioWorkletGlobalScope")
+class AudioWorkletGlobalScope extends WorkletGlobalScope {
+  // To suppress missing implicit constructor warnings.
+  factory AudioWorkletGlobalScope._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final num currentTime;
+
+  final num sampleRate;
+
+  void registerProcessor(String name, Object processorConstructor) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("AudioWorkletNode")
+class AudioWorkletNode extends AudioNode {
+  // To suppress missing implicit constructor warnings.
+  factory AudioWorkletNode._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory AudioWorkletNode(BaseAudioContext context, String name,
+      [Map options]) {
+    if (options != null) {
+      var options_1 = convertDartToNative_Dictionary(options);
+      return AudioWorkletNode._create_1(context, name, options_1);
+    }
+    return AudioWorkletNode._create_2(context, name);
+  }
+  static AudioWorkletNode _create_1(context, name, options) => JS(
+      'AudioWorkletNode',
+      'new AudioWorkletNode(#,#,#)',
+      context,
+      name,
+      options);
+  static AudioWorkletNode _create_2(context, name) =>
+      JS('AudioWorkletNode', 'new AudioWorkletNode(#,#)', context, name);
+
+  final AudioParamMap parameters;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("AudioWorkletProcessor")
+class AudioWorkletProcessor extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory AudioWorkletProcessor._() {
+    throw new UnsupportedError("Not supported");
+  }
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("BaseAudioContext")
+class BaseAudioContext extends EventTarget {
+  // To suppress missing implicit constructor warnings.
+  factory BaseAudioContext._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final num currentTime;
+
+  final AudioDestinationNode destination;
+
+  final AudioListener listener;
+
+  final num sampleRate;
+
+  final String state;
+
+  AnalyserNode createAnalyser() native;
+
+  BiquadFilterNode createBiquadFilter() native;
+
+  AudioBuffer createBuffer(
+      int numberOfChannels, int numberOfFrames, num sampleRate) native;
+
+  AudioBufferSourceNode createBufferSource() native;
+
+  ChannelMergerNode createChannelMerger([int numberOfInputs]) native;
+
+  ChannelSplitterNode createChannelSplitter([int numberOfOutputs]) native;
+
+  ConstantSourceNode createConstantSource() native;
+
+  ConvolverNode createConvolver() native;
+
+  DelayNode createDelay([num maxDelayTime]) native;
+
+  DynamicsCompressorNode createDynamicsCompressor() native;
+
+  GainNode createGain() native;
+
+  @JSName('createIIRFilter')
+  IirFilterNode createIirFilter(List<num> feedForward, List<num> feedBack)
+      native;
+
+  MediaElementAudioSourceNode createMediaElementSource(
+      MediaElement mediaElement) native;
+
+  MediaStreamAudioDestinationNode createMediaStreamDestination() native;
+
+  MediaStreamAudioSourceNode createMediaStreamSource(MediaStream mediaStream)
+      native;
+
+  OscillatorNode createOscillator() native;
+
+  PannerNode createPanner() native;
+
+  PeriodicWave createPeriodicWave(List<num> real, List<num> imag,
+      [Map options]) {
+    if (options != null) {
+      var options_1 = convertDartToNative_Dictionary(options);
+      return _createPeriodicWave_1(real, imag, options_1);
+    }
+    return _createPeriodicWave_2(real, imag);
+  }
+
+  @JSName('createPeriodicWave')
+  PeriodicWave _createPeriodicWave_1(List<num> real, List<num> imag, options)
+      native;
+  @JSName('createPeriodicWave')
+  PeriodicWave _createPeriodicWave_2(List<num> real, List<num> imag) native;
+
+  ScriptProcessorNode createScriptProcessor(
+      [int bufferSize,
+      int numberOfInputChannels,
+      int numberOfOutputChannels]) native;
+
+  StereoPannerNode createStereoPanner() native;
+
+  WaveShaperNode createWaveShaper() native;
+
+  Future<AudioBuffer> decodeAudioData(ByteBuffer audioData,
+          [DecodeSuccessCallback successCallback,
+          DecodeErrorCallback errorCallback]) =>
+      promiseToFuture<AudioBuffer>(JS("", "#.decodeAudioData(#, #, #)", this,
+          audioData, successCallback, errorCallback));
+
+  Future resume() => promiseToFuture(JS("", "#.resume()", this));
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("BiquadFilterNode")
+class BiquadFilterNode extends AudioNode {
+  // To suppress missing implicit constructor warnings.
+  factory BiquadFilterNode._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory BiquadFilterNode(BaseAudioContext context, [Map options]) {
+    if (options != null) {
+      var options_1 = convertDartToNative_Dictionary(options);
+      return BiquadFilterNode._create_1(context, options_1);
+    }
+    return BiquadFilterNode._create_2(context);
+  }
+  static BiquadFilterNode _create_1(context, options) =>
+      JS('BiquadFilterNode', 'new BiquadFilterNode(#,#)', context, options);
+  static BiquadFilterNode _create_2(context) =>
+      JS('BiquadFilterNode', 'new BiquadFilterNode(#)', context);
+
+  final AudioParam Q;
+
+  final AudioParam detune;
+
+  final AudioParam frequency;
+
+  final AudioParam gain;
+
+  String type;
+
+  void getFrequencyResponse(Float32List frequencyHz, Float32List magResponse,
+      Float32List phaseResponse) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("ChannelMergerNode,AudioChannelMerger")
+class ChannelMergerNode extends AudioNode {
+  // To suppress missing implicit constructor warnings.
+  factory ChannelMergerNode._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory ChannelMergerNode(BaseAudioContext context, [Map options]) {
+    if (options != null) {
+      var options_1 = convertDartToNative_Dictionary(options);
+      return ChannelMergerNode._create_1(context, options_1);
+    }
+    return ChannelMergerNode._create_2(context);
+  }
+  static ChannelMergerNode _create_1(context, options) =>
+      JS('ChannelMergerNode', 'new ChannelMergerNode(#,#)', context, options);
+  static ChannelMergerNode _create_2(context) =>
+      JS('ChannelMergerNode', 'new ChannelMergerNode(#)', context);
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("ChannelSplitterNode,AudioChannelSplitter")
+class ChannelSplitterNode extends AudioNode {
+  // To suppress missing implicit constructor warnings.
+  factory ChannelSplitterNode._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory ChannelSplitterNode(BaseAudioContext context, [Map options]) {
+    if (options != null) {
+      var options_1 = convertDartToNative_Dictionary(options);
+      return ChannelSplitterNode._create_1(context, options_1);
+    }
+    return ChannelSplitterNode._create_2(context);
+  }
+  static ChannelSplitterNode _create_1(context, options) => JS(
+      'ChannelSplitterNode', 'new ChannelSplitterNode(#,#)', context, options);
+  static ChannelSplitterNode _create_2(context) =>
+      JS('ChannelSplitterNode', 'new ChannelSplitterNode(#)', context);
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("ConstantSourceNode")
+class ConstantSourceNode extends AudioScheduledSourceNode {
+  // To suppress missing implicit constructor warnings.
+  factory ConstantSourceNode._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory ConstantSourceNode(BaseAudioContext context, [Map options]) {
+    if (options != null) {
+      var options_1 = convertDartToNative_Dictionary(options);
+      return ConstantSourceNode._create_1(context, options_1);
+    }
+    return ConstantSourceNode._create_2(context);
+  }
+  static ConstantSourceNode _create_1(context, options) =>
+      JS('ConstantSourceNode', 'new ConstantSourceNode(#,#)', context, options);
+  static ConstantSourceNode _create_2(context) =>
+      JS('ConstantSourceNode', 'new ConstantSourceNode(#)', context);
+
+  final AudioParam offset;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("ConvolverNode")
+class ConvolverNode extends AudioNode {
+  // To suppress missing implicit constructor warnings.
+  factory ConvolverNode._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory ConvolverNode(BaseAudioContext context, [Map options]) {
+    if (options != null) {
+      var options_1 = convertDartToNative_Dictionary(options);
+      return ConvolverNode._create_1(context, options_1);
+    }
+    return ConvolverNode._create_2(context);
+  }
+  static ConvolverNode _create_1(context, options) =>
+      JS('ConvolverNode', 'new ConvolverNode(#,#)', context, options);
+  static ConvolverNode _create_2(context) =>
+      JS('ConvolverNode', 'new ConvolverNode(#)', context);
+
+  AudioBuffer buffer;
+
+  bool normalize;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("DelayNode")
+class DelayNode extends AudioNode {
+  // To suppress missing implicit constructor warnings.
+  factory DelayNode._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory DelayNode(BaseAudioContext context, [Map options]) {
+    if (options != null) {
+      var options_1 = convertDartToNative_Dictionary(options);
+      return DelayNode._create_1(context, options_1);
+    }
+    return DelayNode._create_2(context);
+  }
+  static DelayNode _create_1(context, options) =>
+      JS('DelayNode', 'new DelayNode(#,#)', context, options);
+  static DelayNode _create_2(context) =>
+      JS('DelayNode', 'new DelayNode(#)', context);
+
+  final AudioParam delayTime;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("DynamicsCompressorNode")
+class DynamicsCompressorNode extends AudioNode {
+  // To suppress missing implicit constructor warnings.
+  factory DynamicsCompressorNode._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory DynamicsCompressorNode(BaseAudioContext context, [Map options]) {
+    if (options != null) {
+      var options_1 = convertDartToNative_Dictionary(options);
+      return DynamicsCompressorNode._create_1(context, options_1);
+    }
+    return DynamicsCompressorNode._create_2(context);
+  }
+  static DynamicsCompressorNode _create_1(context, options) => JS(
+      'DynamicsCompressorNode',
+      'new DynamicsCompressorNode(#,#)',
+      context,
+      options);
+  static DynamicsCompressorNode _create_2(context) =>
+      JS('DynamicsCompressorNode', 'new DynamicsCompressorNode(#)', context);
+
+  final AudioParam attack;
+
+  final AudioParam knee;
+
+  final AudioParam ratio;
+
+  final num reduction;
+
+  final AudioParam release;
+
+  final AudioParam threshold;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("GainNode,AudioGainNode")
+class GainNode extends AudioNode {
+  // To suppress missing implicit constructor warnings.
+  factory GainNode._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory GainNode(BaseAudioContext context, [Map options]) {
+    if (options != null) {
+      var options_1 = convertDartToNative_Dictionary(options);
+      return GainNode._create_1(context, options_1);
+    }
+    return GainNode._create_2(context);
+  }
+  static GainNode _create_1(context, options) =>
+      JS('GainNode', 'new GainNode(#,#)', context, options);
+  static GainNode _create_2(context) =>
+      JS('GainNode', 'new GainNode(#)', context);
+
+  final AudioParam gain;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("IIRFilterNode")
+class IirFilterNode extends AudioNode {
+  // To suppress missing implicit constructor warnings.
+  factory IirFilterNode._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory IirFilterNode(BaseAudioContext context, Map options) {
+    var options_1 = convertDartToNative_Dictionary(options);
+    return IirFilterNode._create_1(context, options_1);
+  }
+  static IirFilterNode _create_1(context, options) =>
+      JS('IirFilterNode', 'new IIRFilterNode(#,#)', context, options);
+
+  void getFrequencyResponse(Float32List frequencyHz, Float32List magResponse,
+      Float32List phaseResponse) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("MediaElementAudioSourceNode")
+class MediaElementAudioSourceNode extends AudioNode {
+  // To suppress missing implicit constructor warnings.
+  factory MediaElementAudioSourceNode._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory MediaElementAudioSourceNode(BaseAudioContext context, Map options) {
+    var options_1 = convertDartToNative_Dictionary(options);
+    return MediaElementAudioSourceNode._create_1(context, options_1);
+  }
+  static MediaElementAudioSourceNode _create_1(context, options) => JS(
+      'MediaElementAudioSourceNode',
+      'new MediaElementAudioSourceNode(#,#)',
+      context,
+      options);
+
+  final MediaElement mediaElement;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("MediaStreamAudioDestinationNode")
+class MediaStreamAudioDestinationNode extends AudioNode {
+  // To suppress missing implicit constructor warnings.
+  factory MediaStreamAudioDestinationNode._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory MediaStreamAudioDestinationNode(BaseAudioContext context,
+      [Map options]) {
+    if (options != null) {
+      var options_1 = convertDartToNative_Dictionary(options);
+      return MediaStreamAudioDestinationNode._create_1(context, options_1);
+    }
+    return MediaStreamAudioDestinationNode._create_2(context);
+  }
+  static MediaStreamAudioDestinationNode _create_1(context, options) => JS(
+      'MediaStreamAudioDestinationNode',
+      'new MediaStreamAudioDestinationNode(#,#)',
+      context,
+      options);
+  static MediaStreamAudioDestinationNode _create_2(context) => JS(
+      'MediaStreamAudioDestinationNode',
+      'new MediaStreamAudioDestinationNode(#)',
+      context);
+
+  final MediaStream stream;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("MediaStreamAudioSourceNode")
+class MediaStreamAudioSourceNode extends AudioNode {
+  // To suppress missing implicit constructor warnings.
+  factory MediaStreamAudioSourceNode._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory MediaStreamAudioSourceNode(BaseAudioContext context, Map options) {
+    var options_1 = convertDartToNative_Dictionary(options);
+    return MediaStreamAudioSourceNode._create_1(context, options_1);
+  }
+  static MediaStreamAudioSourceNode _create_1(context, options) => JS(
+      'MediaStreamAudioSourceNode',
+      'new MediaStreamAudioSourceNode(#,#)',
+      context,
+      options);
+
+  final MediaStream mediaStream;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("OfflineAudioCompletionEvent")
+class OfflineAudioCompletionEvent extends Event {
+  // To suppress missing implicit constructor warnings.
+  factory OfflineAudioCompletionEvent._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory OfflineAudioCompletionEvent(String type, Map eventInitDict) {
+    var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+    return OfflineAudioCompletionEvent._create_1(type, eventInitDict_1);
+  }
+  static OfflineAudioCompletionEvent _create_1(type, eventInitDict) => JS(
+      'OfflineAudioCompletionEvent',
+      'new OfflineAudioCompletionEvent(#,#)',
+      type,
+      eventInitDict);
+
+  final AudioBuffer renderedBuffer;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("OfflineAudioContext")
+class OfflineAudioContext extends BaseAudioContext {
+  // To suppress missing implicit constructor warnings.
+  factory OfflineAudioContext._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory OfflineAudioContext(numberOfChannels_OR_options,
+      [int numberOfFrames, num sampleRate]) {
+    if ((sampleRate is num) &&
+        (numberOfFrames is int) &&
+        (numberOfChannels_OR_options is int)) {
+      return OfflineAudioContext._create_1(
+          numberOfChannels_OR_options, numberOfFrames, sampleRate);
+    }
+    if ((numberOfChannels_OR_options is Map) &&
+        numberOfFrames == null &&
+        sampleRate == null) {
+      var options_1 =
+          convertDartToNative_Dictionary(numberOfChannels_OR_options);
+      return OfflineAudioContext._create_2(options_1);
+    }
+    throw new ArgumentError("Incorrect number or type of arguments");
+  }
+  static OfflineAudioContext _create_1(
+          numberOfChannels_OR_options, numberOfFrames, sampleRate) =>
+      JS('OfflineAudioContext', 'new OfflineAudioContext(#,#,#)',
+          numberOfChannels_OR_options, numberOfFrames, sampleRate);
+  static OfflineAudioContext _create_2(numberOfChannels_OR_options) => JS(
+      'OfflineAudioContext',
+      'new OfflineAudioContext(#)',
+      numberOfChannels_OR_options);
+
+  final int length;
+
+  Future<AudioBuffer> startRendering() =>
+      promiseToFuture<AudioBuffer>(JS("", "#.startRendering()", this));
+
+  @JSName('suspend')
+  Future suspendFor(num suspendTime) =>
+      promiseToFuture(JS("", "#.suspendFor(#)", this, suspendTime));
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("OscillatorNode,Oscillator")
+class OscillatorNode extends AudioScheduledSourceNode {
+  // To suppress missing implicit constructor warnings.
+  factory OscillatorNode._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory OscillatorNode(BaseAudioContext context, [Map options]) {
+    if (options != null) {
+      var options_1 = convertDartToNative_Dictionary(options);
+      return OscillatorNode._create_1(context, options_1);
+    }
+    return OscillatorNode._create_2(context);
+  }
+  static OscillatorNode _create_1(context, options) =>
+      JS('OscillatorNode', 'new OscillatorNode(#,#)', context, options);
+  static OscillatorNode _create_2(context) =>
+      JS('OscillatorNode', 'new OscillatorNode(#)', context);
+
+  final AudioParam detune;
+
+  final AudioParam frequency;
+
+  String type;
+
+  void setPeriodicWave(PeriodicWave periodicWave) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("PannerNode,AudioPannerNode,webkitAudioPannerNode")
+class PannerNode extends AudioNode {
+  // To suppress missing implicit constructor warnings.
+  factory PannerNode._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory PannerNode(BaseAudioContext context, [Map options]) {
+    if (options != null) {
+      var options_1 = convertDartToNative_Dictionary(options);
+      return PannerNode._create_1(context, options_1);
+    }
+    return PannerNode._create_2(context);
+  }
+  static PannerNode _create_1(context, options) =>
+      JS('PannerNode', 'new PannerNode(#,#)', context, options);
+  static PannerNode _create_2(context) =>
+      JS('PannerNode', 'new PannerNode(#)', context);
+
+  num coneInnerAngle;
+
+  num coneOuterAngle;
+
+  num coneOuterGain;
+
+  String distanceModel;
+
+  num maxDistance;
+
+  final AudioParam orientationX;
+
+  final AudioParam orientationY;
+
+  final AudioParam orientationZ;
+
+  String panningModel;
+
+  final AudioParam positionX;
+
+  final AudioParam positionY;
+
+  final AudioParam positionZ;
+
+  num refDistance;
+
+  num rolloffFactor;
+
+  void setOrientation(num x, num y, num z) native;
+
+  void setPosition(num x, num y, num z) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("PeriodicWave")
+class PeriodicWave extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory PeriodicWave._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory PeriodicWave(BaseAudioContext context, [Map options]) {
+    if (options != null) {
+      var options_1 = convertDartToNative_Dictionary(options);
+      return PeriodicWave._create_1(context, options_1);
+    }
+    return PeriodicWave._create_2(context);
+  }
+  static PeriodicWave _create_1(context, options) =>
+      JS('PeriodicWave', 'new PeriodicWave(#,#)', context, options);
+  static PeriodicWave _create_2(context) =>
+      JS('PeriodicWave', 'new PeriodicWave(#)', context);
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("ScriptProcessorNode,JavaScriptAudioNode")
+class ScriptProcessorNode extends AudioNode {
+  // To suppress missing implicit constructor warnings.
+  factory ScriptProcessorNode._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  /**
+   * Static factory designed to expose `audioprocess` events to event
+   * handlers that are not necessarily instances of [ScriptProcessorNode].
+   *
+   * See [EventStreamProvider] for usage information.
+   */
+  static const EventStreamProvider<AudioProcessingEvent> audioProcessEvent =
+      const EventStreamProvider<AudioProcessingEvent>('audioprocess');
+
+  final int bufferSize;
+
+  void setEventListener(EventListener eventListener) native;
+
+  /// Stream of `audioprocess` events handled by this [ScriptProcessorNode].
+/**
+   * Get a Stream that fires events when AudioProcessingEvents occur.
+   * This particular stream is special in that it only allows one listener to a
+   * given stream. Converting the returned Stream [asBroadcast] will likely ruin
+   * the soft-real-time properties which which these events are fired and can
+   * be processed.
+   */
+  Stream<AudioProcessingEvent> get onAudioProcess =>
+      audioProcessEvent.forTarget(this);
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("StereoPannerNode")
+class StereoPannerNode extends AudioNode {
+  // To suppress missing implicit constructor warnings.
+  factory StereoPannerNode._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory StereoPannerNode(BaseAudioContext context, [Map options]) {
+    if (options != null) {
+      var options_1 = convertDartToNative_Dictionary(options);
+      return StereoPannerNode._create_1(context, options_1);
+    }
+    return StereoPannerNode._create_2(context);
+  }
+  static StereoPannerNode _create_1(context, options) =>
+      JS('StereoPannerNode', 'new StereoPannerNode(#,#)', context, options);
+  static StereoPannerNode _create_2(context) =>
+      JS('StereoPannerNode', 'new StereoPannerNode(#)', context);
+
+  final AudioParam pan;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("WaveShaperNode")
+class WaveShaperNode extends AudioNode {
+  // To suppress missing implicit constructor warnings.
+  factory WaveShaperNode._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory WaveShaperNode(BaseAudioContext context, [Map options]) {
+    if (options != null) {
+      var options_1 = convertDartToNative_Dictionary(options);
+      return WaveShaperNode._create_1(context, options_1);
+    }
+    return WaveShaperNode._create_2(context);
+  }
+  static WaveShaperNode _create_1(context, options) =>
+      JS('WaveShaperNode', 'new WaveShaperNode(#,#)', context, options);
+  static WaveShaperNode _create_2(context) =>
+      JS('WaveShaperNode', 'new WaveShaperNode(#)', context);
+
+  Float32List curve;
+
+  String oversample;
+}
diff --git a/sdk_nnbd/lib/web_gl/dart2js/web_gl_dart2js.dart b/sdk_nnbd/lib/web_gl/dart2js/web_gl_dart2js.dart
new file mode 100644
index 0000000..80e36b1
--- /dev/null
+++ b/sdk_nnbd/lib/web_gl/dart2js/web_gl_dart2js.dart
@@ -0,0 +1,4174 @@
+/**
+ * 3D programming in the browser.
+ *
+ * {@category Web}
+ */
+library dart.dom.web_gl;
+
+import 'dart:async';
+import 'dart:collection' hide LinkedList, LinkedListEntry;
+import 'dart:_internal' show FixedLengthListMixin;
+import 'dart:html';
+import 'dart:html_common';
+import 'dart:_native_typed_data';
+import 'dart:typed_data';
+import 'dart:_js_helper'
+    show Creates, JSName, Native, Returns, convertDartClosureToJS;
+import 'dart:_foreign_helper' show JS;
+import 'dart:_interceptors' show Interceptor, JSExtendableArray;
+// DO NOT EDIT - unless you are editing documentation as per:
+// https://code.google.com/p/dart/wiki/ContributingHTMLDocumentation
+// Auto-generated dart:web_gl library.
+
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("WebGLActiveInfo")
+class ActiveInfo extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory ActiveInfo._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final String name;
+
+  final int size;
+
+  final int type;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("ANGLEInstancedArrays,ANGLE_instanced_arrays")
+class AngleInstancedArrays extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory AngleInstancedArrays._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  static const int VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE = 0x88FE;
+
+  @JSName('drawArraysInstancedANGLE')
+  void drawArraysInstancedAngle(int mode, int first, int count, int primcount)
+      native;
+
+  @JSName('drawElementsInstancedANGLE')
+  void drawElementsInstancedAngle(
+      int mode, int count, int type, int offset, int primcount) native;
+
+  @JSName('vertexAttribDivisorANGLE')
+  void vertexAttribDivisorAngle(int index, int divisor) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("WebGLBuffer")
+class Buffer extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory Buffer._() {
+    throw new UnsupportedError("Not supported");
+  }
+}
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("WebGLCanvas")
+class Canvas extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory Canvas._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  @JSName('canvas')
+  final CanvasElement canvas;
+
+  @JSName('canvas')
+  final OffscreenCanvas offscreenCanvas;
+}
+
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("WebGLColorBufferFloat")
+class ColorBufferFloat extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory ColorBufferFloat._() {
+    throw new UnsupportedError("Not supported");
+  }
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("WebGLCompressedTextureASTC")
+class CompressedTextureAstc extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory CompressedTextureAstc._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  static const int COMPRESSED_RGBA_ASTC_10x10_KHR = 0x93BB;
+
+  static const int COMPRESSED_RGBA_ASTC_10x5_KHR = 0x93B8;
+
+  static const int COMPRESSED_RGBA_ASTC_10x6_KHR = 0x93B9;
+
+  static const int COMPRESSED_RGBA_ASTC_10x8_KHR = 0x93BA;
+
+  static const int COMPRESSED_RGBA_ASTC_12x10_KHR = 0x93BC;
+
+  static const int COMPRESSED_RGBA_ASTC_12x12_KHR = 0x93BD;
+
+  static const int COMPRESSED_RGBA_ASTC_4x4_KHR = 0x93B0;
+
+  static const int COMPRESSED_RGBA_ASTC_5x4_KHR = 0x93B1;
+
+  static const int COMPRESSED_RGBA_ASTC_5x5_KHR = 0x93B2;
+
+  static const int COMPRESSED_RGBA_ASTC_6x5_KHR = 0x93B3;
+
+  static const int COMPRESSED_RGBA_ASTC_6x6_KHR = 0x93B4;
+
+  static const int COMPRESSED_RGBA_ASTC_8x5_KHR = 0x93B5;
+
+  static const int COMPRESSED_RGBA_ASTC_8x6_KHR = 0x93B6;
+
+  static const int COMPRESSED_RGBA_ASTC_8x8_KHR = 0x93B7;
+
+  static const int COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR = 0x93DB;
+
+  static const int COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR = 0x93D8;
+
+  static const int COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR = 0x93D9;
+
+  static const int COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR = 0x93DA;
+
+  static const int COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR = 0x93DC;
+
+  static const int COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR = 0x93DD;
+
+  static const int COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR = 0x93D0;
+
+  static const int COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR = 0x93D1;
+
+  static const int COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR = 0x93D2;
+
+  static const int COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR = 0x93D3;
+
+  static const int COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR = 0x93D4;
+
+  static const int COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR = 0x93D5;
+
+  static const int COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR = 0x93D6;
+
+  static const int COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR = 0x93D7;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("WebGLCompressedTextureATC,WEBGL_compressed_texture_atc")
+class CompressedTextureAtc extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory CompressedTextureAtc._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  static const int COMPRESSED_RGBA_ATC_EXPLICIT_ALPHA_WEBGL = 0x8C93;
+
+  static const int COMPRESSED_RGBA_ATC_INTERPOLATED_ALPHA_WEBGL = 0x87EE;
+
+  static const int COMPRESSED_RGB_ATC_WEBGL = 0x8C92;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("WebGLCompressedTextureETC1,WEBGL_compressed_texture_etc1")
+class CompressedTextureETC1 extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory CompressedTextureETC1._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  static const int COMPRESSED_RGB_ETC1_WEBGL = 0x8D64;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("WebGLCompressedTextureETC")
+class CompressedTextureEtc extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory CompressedTextureEtc._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  static const int COMPRESSED_R11_EAC = 0x9270;
+
+  static const int COMPRESSED_RG11_EAC = 0x9272;
+
+  static const int COMPRESSED_RGB8_ETC2 = 0x9274;
+
+  static const int COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 = 0x9276;
+
+  static const int COMPRESSED_RGBA8_ETC2_EAC = 0x9278;
+
+  static const int COMPRESSED_SIGNED_R11_EAC = 0x9271;
+
+  static const int COMPRESSED_SIGNED_RG11_EAC = 0x9273;
+
+  static const int COMPRESSED_SRGB8_ALPHA8_ETC2_EAC = 0x9279;
+
+  static const int COMPRESSED_SRGB8_ETC2 = 0x9275;
+
+  static const int COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2 = 0x9277;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("WebGLCompressedTexturePVRTC,WEBGL_compressed_texture_pvrtc")
+class CompressedTexturePvrtc extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory CompressedTexturePvrtc._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  static const int COMPRESSED_RGBA_PVRTC_2BPPV1_IMG = 0x8C03;
+
+  static const int COMPRESSED_RGBA_PVRTC_4BPPV1_IMG = 0x8C02;
+
+  static const int COMPRESSED_RGB_PVRTC_2BPPV1_IMG = 0x8C01;
+
+  static const int COMPRESSED_RGB_PVRTC_4BPPV1_IMG = 0x8C00;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("WebGLCompressedTextureS3TC,WEBGL_compressed_texture_s3tc")
+class CompressedTextureS3TC extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory CompressedTextureS3TC._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  static const int COMPRESSED_RGBA_S3TC_DXT1_EXT = 0x83F1;
+
+  static const int COMPRESSED_RGBA_S3TC_DXT3_EXT = 0x83F2;
+
+  static const int COMPRESSED_RGBA_S3TC_DXT5_EXT = 0x83F3;
+
+  static const int COMPRESSED_RGB_S3TC_DXT1_EXT = 0x83F0;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("WebGLCompressedTextureS3TCsRGB")
+class CompressedTextureS3TCsRgb extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory CompressedTextureS3TCsRgb._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  static const int COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT = 0x8C4D;
+
+  static const int COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT = 0x8C4E;
+
+  static const int COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT = 0x8C4F;
+
+  static const int COMPRESSED_SRGB_S3TC_DXT1_EXT = 0x8C4C;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("WebGLContextEvent")
+class ContextEvent extends Event {
+  // To suppress missing implicit constructor warnings.
+  factory ContextEvent._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  factory ContextEvent(String type, [Map eventInit]) {
+    if (eventInit != null) {
+      var eventInit_1 = convertDartToNative_Dictionary(eventInit);
+      return ContextEvent._create_1(type, eventInit_1);
+    }
+    return ContextEvent._create_2(type);
+  }
+  static ContextEvent _create_1(type, eventInit) =>
+      JS('ContextEvent', 'new WebGLContextEvent(#,#)', type, eventInit);
+  static ContextEvent _create_2(type) =>
+      JS('ContextEvent', 'new WebGLContextEvent(#)', type);
+
+  final String statusMessage;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("WebGLDebugRendererInfo,WEBGL_debug_renderer_info")
+class DebugRendererInfo extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory DebugRendererInfo._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  static const int UNMASKED_RENDERER_WEBGL = 0x9246;
+
+  static const int UNMASKED_VENDOR_WEBGL = 0x9245;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("WebGLDebugShaders,WEBGL_debug_shaders")
+class DebugShaders extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory DebugShaders._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  String getTranslatedShaderSource(Shader shader) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("WebGLDepthTexture,WEBGL_depth_texture")
+class DepthTexture extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory DepthTexture._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  static const int UNSIGNED_INT_24_8_WEBGL = 0x84FA;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("WebGLDrawBuffers,WEBGL_draw_buffers")
+class DrawBuffers extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory DrawBuffers._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  @JSName('drawBuffersWEBGL')
+  void drawBuffersWebgl(List<int> buffers) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("EXTsRGB,EXT_sRGB")
+class EXTsRgb extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory EXTsRgb._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  static const int FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING_EXT = 0x8210;
+
+  static const int SRGB8_ALPHA8_EXT = 0x8C43;
+
+  static const int SRGB_ALPHA_EXT = 0x8C42;
+
+  static const int SRGB_EXT = 0x8C40;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("EXTBlendMinMax,EXT_blend_minmax")
+class ExtBlendMinMax extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory ExtBlendMinMax._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  static const int MAX_EXT = 0x8008;
+
+  static const int MIN_EXT = 0x8007;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("EXTColorBufferFloat")
+class ExtColorBufferFloat extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory ExtColorBufferFloat._() {
+    throw new UnsupportedError("Not supported");
+  }
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("EXTColorBufferHalfFloat")
+class ExtColorBufferHalfFloat extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory ExtColorBufferHalfFloat._() {
+    throw new UnsupportedError("Not supported");
+  }
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("EXTDisjointTimerQuery")
+class ExtDisjointTimerQuery extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory ExtDisjointTimerQuery._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  static const int CURRENT_QUERY_EXT = 0x8865;
+
+  static const int GPU_DISJOINT_EXT = 0x8FBB;
+
+  static const int QUERY_COUNTER_BITS_EXT = 0x8864;
+
+  static const int QUERY_RESULT_AVAILABLE_EXT = 0x8867;
+
+  static const int QUERY_RESULT_EXT = 0x8866;
+
+  static const int TIMESTAMP_EXT = 0x8E28;
+
+  static const int TIME_ELAPSED_EXT = 0x88BF;
+
+  @JSName('beginQueryEXT')
+  void beginQueryExt(int target, TimerQueryExt query) native;
+
+  @JSName('createQueryEXT')
+  TimerQueryExt createQueryExt() native;
+
+  @JSName('deleteQueryEXT')
+  void deleteQueryExt(TimerQueryExt query) native;
+
+  @JSName('endQueryEXT')
+  void endQueryExt(int target) native;
+
+  @JSName('getQueryEXT')
+  Object getQueryExt(int target, int pname) native;
+
+  @JSName('getQueryObjectEXT')
+  Object getQueryObjectExt(TimerQueryExt query, int pname) native;
+
+  @JSName('isQueryEXT')
+  bool isQueryExt(TimerQueryExt query) native;
+
+  @JSName('queryCounterEXT')
+  void queryCounterExt(TimerQueryExt query, int target) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("EXTDisjointTimerQueryWebGL2")
+class ExtDisjointTimerQueryWebGL2 extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory ExtDisjointTimerQueryWebGL2._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  static const int GPU_DISJOINT_EXT = 0x8FBB;
+
+  static const int QUERY_COUNTER_BITS_EXT = 0x8864;
+
+  static const int TIMESTAMP_EXT = 0x8E28;
+
+  static const int TIME_ELAPSED_EXT = 0x88BF;
+
+  @JSName('queryCounterEXT')
+  void queryCounterExt(Query query, int target) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("EXTFragDepth,EXT_frag_depth")
+class ExtFragDepth extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory ExtFragDepth._() {
+    throw new UnsupportedError("Not supported");
+  }
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("EXTShaderTextureLOD,EXT_shader_texture_lod")
+class ExtShaderTextureLod extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory ExtShaderTextureLod._() {
+    throw new UnsupportedError("Not supported");
+  }
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("EXTTextureFilterAnisotropic,EXT_texture_filter_anisotropic")
+class ExtTextureFilterAnisotropic extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory ExtTextureFilterAnisotropic._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  static const int MAX_TEXTURE_MAX_ANISOTROPY_EXT = 0x84FF;
+
+  static const int TEXTURE_MAX_ANISOTROPY_EXT = 0x84FE;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("WebGLFramebuffer")
+class Framebuffer extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory Framebuffer._() {
+    throw new UnsupportedError("Not supported");
+  }
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("WebGLGetBufferSubDataAsync")
+class GetBufferSubDataAsync extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory GetBufferSubDataAsync._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  Future getBufferSubDataAsync(int target, int srcByteOffset, TypedData dstData,
+          [int dstOffset, int length]) =>
+      promiseToFuture(JS("", "#.getBufferSubDataAsync(#, #, #, #, #)", this,
+          target, srcByteOffset, dstData, dstOffset, length));
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("WebGLLoseContext,WebGLExtensionLoseContext,WEBGL_lose_context")
+class LoseContext extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory LoseContext._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  void loseContext() native;
+
+  void restoreContext() native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("OESElementIndexUint,OES_element_index_uint")
+class OesElementIndexUint extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory OesElementIndexUint._() {
+    throw new UnsupportedError("Not supported");
+  }
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("OESStandardDerivatives,OES_standard_derivatives")
+class OesStandardDerivatives extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory OesStandardDerivatives._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  static const int FRAGMENT_SHADER_DERIVATIVE_HINT_OES = 0x8B8B;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("OESTextureFloat,OES_texture_float")
+class OesTextureFloat extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory OesTextureFloat._() {
+    throw new UnsupportedError("Not supported");
+  }
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("OESTextureFloatLinear,OES_texture_float_linear")
+class OesTextureFloatLinear extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory OesTextureFloatLinear._() {
+    throw new UnsupportedError("Not supported");
+  }
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("OESTextureHalfFloat,OES_texture_half_float")
+class OesTextureHalfFloat extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory OesTextureHalfFloat._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  static const int HALF_FLOAT_OES = 0x8D61;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("OESTextureHalfFloatLinear,OES_texture_half_float_linear")
+class OesTextureHalfFloatLinear extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory OesTextureHalfFloatLinear._() {
+    throw new UnsupportedError("Not supported");
+  }
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("OESVertexArrayObject,OES_vertex_array_object")
+class OesVertexArrayObject extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory OesVertexArrayObject._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  static const int VERTEX_ARRAY_BINDING_OES = 0x85B5;
+
+  @JSName('bindVertexArrayOES')
+  void bindVertexArray(VertexArrayObjectOes arrayObject) native;
+
+  @JSName('createVertexArrayOES')
+  VertexArrayObjectOes createVertexArray() native;
+
+  @JSName('deleteVertexArrayOES')
+  void deleteVertexArray(VertexArrayObjectOes arrayObject) native;
+
+  @JSName('isVertexArrayOES')
+  bool isVertexArray(VertexArrayObjectOes arrayObject) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("WebGLProgram")
+class Program extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory Program._() {
+    throw new UnsupportedError("Not supported");
+  }
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("WebGLQuery")
+class Query extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory Query._() {
+    throw new UnsupportedError("Not supported");
+  }
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("WebGLRenderbuffer")
+class Renderbuffer extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory Renderbuffer._() {
+    throw new UnsupportedError("Not supported");
+  }
+}
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.FIREFOX)
+@Unstable()
+@Native("WebGLRenderingContext")
+class RenderingContext extends Interceptor implements CanvasRenderingContext {
+  // To suppress missing implicit constructor warnings.
+  factory RenderingContext._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  /// Checks if this type is supported on the current platform.
+  static bool get supported => JS('bool', '!!(window.WebGLRenderingContext)');
+
+  final CanvasElement canvas;
+
+  // From WebGLRenderingContextBase
+
+  final int drawingBufferHeight;
+
+  final int drawingBufferWidth;
+
+  void activeTexture(int texture) native;
+
+  void attachShader(Program program, Shader shader) native;
+
+  void bindAttribLocation(Program program, int index, String name) native;
+
+  void bindBuffer(int target, Buffer buffer) native;
+
+  void bindFramebuffer(int target, Framebuffer framebuffer) native;
+
+  void bindRenderbuffer(int target, Renderbuffer renderbuffer) native;
+
+  void bindTexture(int target, Texture texture) native;
+
+  void blendColor(num red, num green, num blue, num alpha) native;
+
+  void blendEquation(int mode) native;
+
+  void blendEquationSeparate(int modeRGB, int modeAlpha) native;
+
+  void blendFunc(int sfactor, int dfactor) native;
+
+  void blendFuncSeparate(int srcRGB, int dstRGB, int srcAlpha, int dstAlpha)
+      native;
+
+  void bufferData(int target, data_OR_size, int usage) native;
+
+  void bufferSubData(int target, int offset, data) native;
+
+  int checkFramebufferStatus(int target) native;
+
+  void clear(int mask) native;
+
+  void clearColor(num red, num green, num blue, num alpha) native;
+
+  void clearDepth(num depth) native;
+
+  void clearStencil(int s) native;
+
+  void colorMask(bool red, bool green, bool blue, bool alpha) native;
+
+  Future commit() => promiseToFuture(JS("", "#.commit()", this));
+
+  void compileShader(Shader shader) native;
+
+  void compressedTexImage2D(int target, int level, int internalformat,
+      int width, int height, int border, TypedData data) native;
+
+  void compressedTexSubImage2D(int target, int level, int xoffset, int yoffset,
+      int width, int height, int format, TypedData data) native;
+
+  void copyTexImage2D(int target, int level, int internalformat, int x, int y,
+      int width, int height, int border) native;
+
+  void copyTexSubImage2D(int target, int level, int xoffset, int yoffset, int x,
+      int y, int width, int height) native;
+
+  Buffer createBuffer() native;
+
+  Framebuffer createFramebuffer() native;
+
+  Program createProgram() native;
+
+  Renderbuffer createRenderbuffer() native;
+
+  Shader createShader(int type) native;
+
+  Texture createTexture() native;
+
+  void cullFace(int mode) native;
+
+  void deleteBuffer(Buffer buffer) native;
+
+  void deleteFramebuffer(Framebuffer framebuffer) native;
+
+  void deleteProgram(Program program) native;
+
+  void deleteRenderbuffer(Renderbuffer renderbuffer) native;
+
+  void deleteShader(Shader shader) native;
+
+  void deleteTexture(Texture texture) native;
+
+  void depthFunc(int func) native;
+
+  void depthMask(bool flag) native;
+
+  void depthRange(num zNear, num zFar) native;
+
+  void detachShader(Program program, Shader shader) native;
+
+  void disable(int cap) native;
+
+  void disableVertexAttribArray(int index) native;
+
+  void drawArrays(int mode, int first, int count) native;
+
+  void drawElements(int mode, int count, int type, int offset) native;
+
+  void enable(int cap) native;
+
+  void enableVertexAttribArray(int index) native;
+
+  void finish() native;
+
+  void flush() native;
+
+  void framebufferRenderbuffer(int target, int attachment,
+      int renderbuffertarget, Renderbuffer renderbuffer) native;
+
+  void framebufferTexture2D(int target, int attachment, int textarget,
+      Texture texture, int level) native;
+
+  void frontFace(int mode) native;
+
+  void generateMipmap(int target) native;
+
+  ActiveInfo getActiveAttrib(Program program, int index) native;
+
+  ActiveInfo getActiveUniform(Program program, int index) native;
+
+  List<Shader> getAttachedShaders(Program program) native;
+
+  int getAttribLocation(Program program, String name) native;
+
+  @Creates('int|Null')
+  @Returns('int|Null')
+  Object getBufferParameter(int target, int pname) native;
+
+  @Creates('ContextAttributes|Null')
+  Map getContextAttributes() {
+    return convertNativeToDart_Dictionary(_getContextAttributes_1());
+  }
+
+  @JSName('getContextAttributes')
+  @Creates('ContextAttributes|Null')
+  _getContextAttributes_1() native;
+
+  int getError() native;
+
+  Object getExtension(String name) native;
+
+  @Creates('int|Renderbuffer|Texture|Null')
+  @Returns('int|Renderbuffer|Texture|Null')
+  Object getFramebufferAttachmentParameter(
+      int target, int attachment, int pname) native;
+
+  @Creates(
+      'Null|num|String|bool|JSExtendableArray|NativeFloat32List|NativeInt32List|NativeUint32List|Framebuffer|Renderbuffer|Texture')
+  @Returns(
+      'Null|num|String|bool|JSExtendableArray|NativeFloat32List|NativeInt32List|NativeUint32List|Framebuffer|Renderbuffer|Texture')
+  Object getParameter(int pname) native;
+
+  String getProgramInfoLog(Program program) native;
+
+  @Creates('int|bool|Null')
+  @Returns('int|bool|Null')
+  Object getProgramParameter(Program program, int pname) native;
+
+  @Creates('int|Null')
+  @Returns('int|Null')
+  Object getRenderbufferParameter(int target, int pname) native;
+
+  String getShaderInfoLog(Shader shader) native;
+
+  @Creates('int|bool|Null')
+  @Returns('int|bool|Null')
+  Object getShaderParameter(Shader shader, int pname) native;
+
+  ShaderPrecisionFormat getShaderPrecisionFormat(
+      int shadertype, int precisiontype) native;
+
+  String getShaderSource(Shader shader) native;
+
+  List<String> getSupportedExtensions() native;
+
+  @Creates('int|Null')
+  @Returns('int|Null')
+  Object getTexParameter(int target, int pname) native;
+
+  @Creates(
+      'Null|num|String|bool|JSExtendableArray|NativeFloat32List|NativeInt32List|NativeUint32List')
+  @Returns(
+      'Null|num|String|bool|JSExtendableArray|NativeFloat32List|NativeInt32List|NativeUint32List')
+  Object getUniform(Program program, UniformLocation location) native;
+
+  UniformLocation getUniformLocation(Program program, String name) native;
+
+  @Creates('Null|num|bool|NativeFloat32List|Buffer')
+  @Returns('Null|num|bool|NativeFloat32List|Buffer')
+  Object getVertexAttrib(int index, int pname) native;
+
+  int getVertexAttribOffset(int index, int pname) native;
+
+  void hint(int target, int mode) native;
+
+  bool isBuffer(Buffer buffer) native;
+
+  bool isContextLost() native;
+
+  bool isEnabled(int cap) native;
+
+  bool isFramebuffer(Framebuffer framebuffer) native;
+
+  bool isProgram(Program program) native;
+
+  bool isRenderbuffer(Renderbuffer renderbuffer) native;
+
+  bool isShader(Shader shader) native;
+
+  bool isTexture(Texture texture) native;
+
+  void lineWidth(num width) native;
+
+  void linkProgram(Program program) native;
+
+  void pixelStorei(int pname, int param) native;
+
+  void polygonOffset(num factor, num units) native;
+
+  @JSName('readPixels')
+  void _readPixels(int x, int y, int width, int height, int format, int type,
+      TypedData pixels) native;
+
+  void renderbufferStorage(
+      int target, int internalformat, int width, int height) native;
+
+  void sampleCoverage(num value, bool invert) native;
+
+  void scissor(int x, int y, int width, int height) native;
+
+  void shaderSource(Shader shader, String string) native;
+
+  void stencilFunc(int func, int ref, int mask) native;
+
+  void stencilFuncSeparate(int face, int func, int ref, int mask) native;
+
+  void stencilMask(int mask) native;
+
+  void stencilMaskSeparate(int face, int mask) native;
+
+  void stencilOp(int fail, int zfail, int zpass) native;
+
+  void stencilOpSeparate(int face, int fail, int zfail, int zpass) native;
+
+  void texImage2D(
+      int target,
+      int level,
+      int internalformat,
+      int format_OR_width,
+      int height_OR_type,
+      bitmap_OR_border_OR_canvas_OR_image_OR_pixels_OR_video,
+      [int format,
+      int type,
+      TypedData pixels]) {
+    if (type != null &&
+        format != null &&
+        (bitmap_OR_border_OR_canvas_OR_image_OR_pixels_OR_video is int)) {
+      _texImage2D_1(
+          target,
+          level,
+          internalformat,
+          format_OR_width,
+          height_OR_type,
+          bitmap_OR_border_OR_canvas_OR_image_OR_pixels_OR_video,
+          format,
+          type,
+          pixels);
+      return;
+    }
+    if ((bitmap_OR_border_OR_canvas_OR_image_OR_pixels_OR_video is ImageData) &&
+        format == null &&
+        type == null &&
+        pixels == null) {
+      var pixels_1 = convertDartToNative_ImageData(
+          bitmap_OR_border_OR_canvas_OR_image_OR_pixels_OR_video);
+      _texImage2D_2(target, level, internalformat, format_OR_width,
+          height_OR_type, pixels_1);
+      return;
+    }
+    if ((bitmap_OR_border_OR_canvas_OR_image_OR_pixels_OR_video
+            is ImageElement) &&
+        format == null &&
+        type == null &&
+        pixels == null) {
+      _texImage2D_3(
+          target,
+          level,
+          internalformat,
+          format_OR_width,
+          height_OR_type,
+          bitmap_OR_border_OR_canvas_OR_image_OR_pixels_OR_video);
+      return;
+    }
+    if ((bitmap_OR_border_OR_canvas_OR_image_OR_pixels_OR_video
+            is CanvasElement) &&
+        format == null &&
+        type == null &&
+        pixels == null) {
+      _texImage2D_4(
+          target,
+          level,
+          internalformat,
+          format_OR_width,
+          height_OR_type,
+          bitmap_OR_border_OR_canvas_OR_image_OR_pixels_OR_video);
+      return;
+    }
+    if ((bitmap_OR_border_OR_canvas_OR_image_OR_pixels_OR_video
+            is VideoElement) &&
+        format == null &&
+        type == null &&
+        pixels == null) {
+      _texImage2D_5(
+          target,
+          level,
+          internalformat,
+          format_OR_width,
+          height_OR_type,
+          bitmap_OR_border_OR_canvas_OR_image_OR_pixels_OR_video);
+      return;
+    }
+    if ((bitmap_OR_border_OR_canvas_OR_image_OR_pixels_OR_video
+            is ImageBitmap) &&
+        format == null &&
+        type == null &&
+        pixels == null) {
+      _texImage2D_6(
+          target,
+          level,
+          internalformat,
+          format_OR_width,
+          height_OR_type,
+          bitmap_OR_border_OR_canvas_OR_image_OR_pixels_OR_video);
+      return;
+    }
+    throw new ArgumentError("Incorrect number or type of arguments");
+  }
+
+  @JSName('texImage2D')
+  void _texImage2D_1(target, level, internalformat, width, height, int border,
+      format, type, TypedData pixels) native;
+  @JSName('texImage2D')
+  void _texImage2D_2(target, level, internalformat, format, type, pixels)
+      native;
+  @JSName('texImage2D')
+  void _texImage2D_3(
+      target, level, internalformat, format, type, ImageElement image) native;
+  @JSName('texImage2D')
+  void _texImage2D_4(
+      target, level, internalformat, format, type, CanvasElement canvas) native;
+  @JSName('texImage2D')
+  void _texImage2D_5(
+      target, level, internalformat, format, type, VideoElement video) native;
+  @JSName('texImage2D')
+  void _texImage2D_6(
+      target, level, internalformat, format, type, ImageBitmap bitmap) native;
+
+  void texParameterf(int target, int pname, num param) native;
+
+  void texParameteri(int target, int pname, int param) native;
+
+  void texSubImage2D(
+      int target,
+      int level,
+      int xoffset,
+      int yoffset,
+      int format_OR_width,
+      int height_OR_type,
+      bitmap_OR_canvas_OR_format_OR_image_OR_pixels_OR_video,
+      [int type,
+      TypedData pixels]) {
+    if (type != null &&
+        (bitmap_OR_canvas_OR_format_OR_image_OR_pixels_OR_video is int)) {
+      _texSubImage2D_1(
+          target,
+          level,
+          xoffset,
+          yoffset,
+          format_OR_width,
+          height_OR_type,
+          bitmap_OR_canvas_OR_format_OR_image_OR_pixels_OR_video,
+          type,
+          pixels);
+      return;
+    }
+    if ((bitmap_OR_canvas_OR_format_OR_image_OR_pixels_OR_video is ImageData) &&
+        type == null &&
+        pixels == null) {
+      var pixels_1 = convertDartToNative_ImageData(
+          bitmap_OR_canvas_OR_format_OR_image_OR_pixels_OR_video);
+      _texSubImage2D_2(target, level, xoffset, yoffset, format_OR_width,
+          height_OR_type, pixels_1);
+      return;
+    }
+    if ((bitmap_OR_canvas_OR_format_OR_image_OR_pixels_OR_video
+            is ImageElement) &&
+        type == null &&
+        pixels == null) {
+      _texSubImage2D_3(
+          target,
+          level,
+          xoffset,
+          yoffset,
+          format_OR_width,
+          height_OR_type,
+          bitmap_OR_canvas_OR_format_OR_image_OR_pixels_OR_video);
+      return;
+    }
+    if ((bitmap_OR_canvas_OR_format_OR_image_OR_pixels_OR_video
+            is CanvasElement) &&
+        type == null &&
+        pixels == null) {
+      _texSubImage2D_4(
+          target,
+          level,
+          xoffset,
+          yoffset,
+          format_OR_width,
+          height_OR_type,
+          bitmap_OR_canvas_OR_format_OR_image_OR_pixels_OR_video);
+      return;
+    }
+    if ((bitmap_OR_canvas_OR_format_OR_image_OR_pixels_OR_video
+            is VideoElement) &&
+        type == null &&
+        pixels == null) {
+      _texSubImage2D_5(
+          target,
+          level,
+          xoffset,
+          yoffset,
+          format_OR_width,
+          height_OR_type,
+          bitmap_OR_canvas_OR_format_OR_image_OR_pixels_OR_video);
+      return;
+    }
+    if ((bitmap_OR_canvas_OR_format_OR_image_OR_pixels_OR_video
+            is ImageBitmap) &&
+        type == null &&
+        pixels == null) {
+      _texSubImage2D_6(
+          target,
+          level,
+          xoffset,
+          yoffset,
+          format_OR_width,
+          height_OR_type,
+          bitmap_OR_canvas_OR_format_OR_image_OR_pixels_OR_video);
+      return;
+    }
+    throw new ArgumentError("Incorrect number or type of arguments");
+  }
+
+  @JSName('texSubImage2D')
+  void _texSubImage2D_1(target, level, xoffset, yoffset, width, height,
+      int format, type, TypedData pixels) native;
+  @JSName('texSubImage2D')
+  void _texSubImage2D_2(target, level, xoffset, yoffset, format, type, pixels)
+      native;
+  @JSName('texSubImage2D')
+  void _texSubImage2D_3(
+      target, level, xoffset, yoffset, format, type, ImageElement image) native;
+  @JSName('texSubImage2D')
+  void _texSubImage2D_4(target, level, xoffset, yoffset, format, type,
+      CanvasElement canvas) native;
+  @JSName('texSubImage2D')
+  void _texSubImage2D_5(
+      target, level, xoffset, yoffset, format, type, VideoElement video) native;
+  @JSName('texSubImage2D')
+  void _texSubImage2D_6(
+      target, level, xoffset, yoffset, format, type, ImageBitmap bitmap) native;
+
+  void uniform1f(UniformLocation location, num x) native;
+
+  void uniform1fv(UniformLocation location, v) native;
+
+  void uniform1i(UniformLocation location, int x) native;
+
+  void uniform1iv(UniformLocation location, v) native;
+
+  void uniform2f(UniformLocation location, num x, num y) native;
+
+  void uniform2fv(UniformLocation location, v) native;
+
+  void uniform2i(UniformLocation location, int x, int y) native;
+
+  void uniform2iv(UniformLocation location, v) native;
+
+  void uniform3f(UniformLocation location, num x, num y, num z) native;
+
+  void uniform3fv(UniformLocation location, v) native;
+
+  void uniform3i(UniformLocation location, int x, int y, int z) native;
+
+  void uniform3iv(UniformLocation location, v) native;
+
+  void uniform4f(UniformLocation location, num x, num y, num z, num w) native;
+
+  void uniform4fv(UniformLocation location, v) native;
+
+  void uniform4i(UniformLocation location, int x, int y, int z, int w) native;
+
+  void uniform4iv(UniformLocation location, v) native;
+
+  void uniformMatrix2fv(UniformLocation location, bool transpose, array) native;
+
+  void uniformMatrix3fv(UniformLocation location, bool transpose, array) native;
+
+  void uniformMatrix4fv(UniformLocation location, bool transpose, array) native;
+
+  void useProgram(Program program) native;
+
+  void validateProgram(Program program) native;
+
+  void vertexAttrib1f(int indx, num x) native;
+
+  void vertexAttrib1fv(int indx, values) native;
+
+  void vertexAttrib2f(int indx, num x, num y) native;
+
+  void vertexAttrib2fv(int indx, values) native;
+
+  void vertexAttrib3f(int indx, num x, num y, num z) native;
+
+  void vertexAttrib3fv(int indx, values) native;
+
+  void vertexAttrib4f(int indx, num x, num y, num z, num w) native;
+
+  void vertexAttrib4fv(int indx, values) native;
+
+  void vertexAttribPointer(int indx, int size, int type, bool normalized,
+      int stride, int offset) native;
+
+  void viewport(int x, int y, int width, int height) native;
+
+  void readPixels(int x, int y, int width, int height, int format, int type,
+      TypedData pixels) {
+    _readPixels(x, y, width, height, format, type, pixels);
+  }
+
+  /**
+   * Sets the currently bound texture to [data].
+   *
+   * [data] can be either an [ImageElement], a
+   * [CanvasElement], a [VideoElement], [TypedData] or an [ImageData] object.
+   *
+   * This is deprecated in favor of [texImage2D].
+   */
+  @Deprecated("Use texImage2D")
+  void texImage2DUntyped(int targetTexture, int levelOfDetail,
+      int internalFormat, int format, int type, data) {
+    texImage2D(
+        targetTexture, levelOfDetail, internalFormat, format, type, data);
+  }
+
+  /**
+   * Sets the currently bound texture to [data].
+   *
+   * This is deprecated in favour of [texImage2D].
+   */
+  @Deprecated("Use texImage2D")
+  void texImage2DTyped(int targetTexture, int levelOfDetail, int internalFormat,
+      int width, int height, int border, int format, int type, TypedData data) {
+    texImage2D(targetTexture, levelOfDetail, internalFormat, width, height,
+        border, format, type, data);
+  }
+
+  /**
+   * Updates a sub-rectangle of the currently bound texture to [data].
+   *
+   * [data] can be either an [ImageElement], a
+   * [CanvasElement], a [VideoElement], [TypedData] or an [ImageData] object.
+   *
+   */
+  @Deprecated("Use texSubImage2D")
+  void texSubImage2DUntyped(int targetTexture, int levelOfDetail, int xOffset,
+      int yOffset, int format, int type, data) {
+    texSubImage2D(
+        targetTexture, levelOfDetail, xOffset, yOffset, format, type, data);
+  }
+
+  /**
+   * Updates a sub-rectangle of the currently bound texture to [data].
+   */
+  @Deprecated("Use texSubImage2D")
+  void texSubImage2DTyped(
+      int targetTexture,
+      int levelOfDetail,
+      int xOffset,
+      int yOffset,
+      int width,
+      int height,
+      int border,
+      int format,
+      int type,
+      TypedData data) {
+    texSubImage2D(targetTexture, levelOfDetail, xOffset, yOffset, width, height,
+        format, type, data);
+  }
+
+  /**
+   * Set the bufferData to [data].
+   */
+  @Deprecated("Use bufferData")
+  void bufferDataTyped(int target, TypedData data, int usage) {
+    bufferData(target, data, usage);
+  }
+
+  /**
+   * Set the bufferSubData to [data].
+   */
+  @Deprecated("Use bufferSubData")
+  void bufferSubDataTyped(int target, int offset, TypedData data) {
+    bufferSubData(target, offset, data);
+  }
+}
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("WebGL2RenderingContext")
+class RenderingContext2 extends Interceptor
+    implements _WebGL2RenderingContextBase, _WebGLRenderingContextBase {
+  // To suppress missing implicit constructor warnings.
+  factory RenderingContext2._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final Canvas canvas;
+
+  // From WebGL2RenderingContextBase
+
+  void beginQuery(int target, Query query) native;
+
+  void beginTransformFeedback(int primitiveMode) native;
+
+  void bindBufferBase(int target, int index, Buffer buffer) native;
+
+  void bindBufferRange(
+      int target, int index, Buffer buffer, int offset, int size) native;
+
+  void bindSampler(int unit, Sampler sampler) native;
+
+  void bindTransformFeedback(int target, TransformFeedback feedback) native;
+
+  void bindVertexArray(VertexArrayObject vertexArray) native;
+
+  void blitFramebuffer(int srcX0, int srcY0, int srcX1, int srcY1, int dstX0,
+      int dstY0, int dstX1, int dstY1, int mask, int filter) native;
+
+  @JSName('bufferData')
+  void bufferData2(int target, TypedData srcData, int usage, int srcOffset,
+      [int length]) native;
+
+  @JSName('bufferSubData')
+  void bufferSubData2(
+      int target, int dstByteOffset, TypedData srcData, int srcOffset,
+      [int length]) native;
+
+  void clearBufferfi(int buffer, int drawbuffer, num depth, int stencil) native;
+
+  void clearBufferfv(int buffer, int drawbuffer, value, [int srcOffset]) native;
+
+  void clearBufferiv(int buffer, int drawbuffer, value, [int srcOffset]) native;
+
+  void clearBufferuiv(int buffer, int drawbuffer, value, [int srcOffset])
+      native;
+
+  int clientWaitSync(Sync sync, int flags, int timeout) native;
+
+  @JSName('compressedTexImage2D')
+  void compressedTexImage2D2(int target, int level, int internalformat,
+      int width, int height, int border, TypedData data, int srcOffset,
+      [int srcLengthOverride]) native;
+
+  @JSName('compressedTexImage2D')
+  void compressedTexImage2D3(int target, int level, int internalformat,
+      int width, int height, int border, int imageSize, int offset) native;
+
+  void compressedTexImage3D(int target, int level, int internalformat,
+      int width, int height, int depth, int border, TypedData data,
+      [int srcOffset, int srcLengthOverride]) native;
+
+  @JSName('compressedTexImage3D')
+  void compressedTexImage3D2(
+      int target,
+      int level,
+      int internalformat,
+      int width,
+      int height,
+      int depth,
+      int border,
+      int imageSize,
+      int offset) native;
+
+  @JSName('compressedTexSubImage2D')
+  void compressedTexSubImage2D2(int target, int level, int xoffset, int yoffset,
+      int width, int height, int format, TypedData data, int srcOffset,
+      [int srcLengthOverride]) native;
+
+  @JSName('compressedTexSubImage2D')
+  void compressedTexSubImage2D3(int target, int level, int xoffset, int yoffset,
+      int width, int height, int format, int imageSize, int offset) native;
+
+  void compressedTexSubImage3D(int target, int level, int xoffset, int yoffset,
+      int zoffset, int width, int height, int depth, int format, TypedData data,
+      [int srcOffset, int srcLengthOverride]) native;
+
+  @JSName('compressedTexSubImage3D')
+  void compressedTexSubImage3D2(
+      int target,
+      int level,
+      int xoffset,
+      int yoffset,
+      int zoffset,
+      int width,
+      int height,
+      int depth,
+      int format,
+      int imageSize,
+      int offset) native;
+
+  void copyBufferSubData(int readTarget, int writeTarget, int readOffset,
+      int writeOffset, int size) native;
+
+  void copyTexSubImage3D(int target, int level, int xoffset, int yoffset,
+      int zoffset, int x, int y, int width, int height) native;
+
+  Query createQuery() native;
+
+  Sampler createSampler() native;
+
+  TransformFeedback createTransformFeedback() native;
+
+  VertexArrayObject createVertexArray() native;
+
+  void deleteQuery(Query query) native;
+
+  void deleteSampler(Sampler sampler) native;
+
+  void deleteSync(Sync sync) native;
+
+  void deleteTransformFeedback(TransformFeedback feedback) native;
+
+  void deleteVertexArray(VertexArrayObject vertexArray) native;
+
+  void drawArraysInstanced(int mode, int first, int count, int instanceCount)
+      native;
+
+  void drawBuffers(List<int> buffers) native;
+
+  void drawElementsInstanced(
+      int mode, int count, int type, int offset, int instanceCount) native;
+
+  void drawRangeElements(
+      int mode, int start, int end, int count, int type, int offset) native;
+
+  void endQuery(int target) native;
+
+  void endTransformFeedback() native;
+
+  Sync fenceSync(int condition, int flags) native;
+
+  void framebufferTextureLayer(
+      int target, int attachment, Texture texture, int level, int layer) native;
+
+  String getActiveUniformBlockName(Program program, int uniformBlockIndex)
+      native;
+
+  Object getActiveUniformBlockParameter(
+      Program program, int uniformBlockIndex, int pname) native;
+
+  Object getActiveUniforms(Program program, List<int> uniformIndices, int pname)
+      native;
+
+  void getBufferSubData(int target, int srcByteOffset, TypedData dstData,
+      [int dstOffset, int length]) native;
+
+  int getFragDataLocation(Program program, String name) native;
+
+  Object getIndexedParameter(int target, int index) native;
+
+  Object getInternalformatParameter(int target, int internalformat, int pname)
+      native;
+
+  Object getQuery(int target, int pname) native;
+
+  Object getQueryParameter(Query query, int pname) native;
+
+  Object getSamplerParameter(Sampler sampler, int pname) native;
+
+  Object getSyncParameter(Sync sync, int pname) native;
+
+  ActiveInfo getTransformFeedbackVarying(Program program, int index) native;
+
+  int getUniformBlockIndex(Program program, String uniformBlockName) native;
+
+  List<int> getUniformIndices(Program program, List<String> uniformNames) {
+    List uniformNames_1 = convertDartToNative_StringArray(uniformNames);
+    return _getUniformIndices_1(program, uniformNames_1);
+  }
+
+  @JSName('getUniformIndices')
+  List<int> _getUniformIndices_1(Program program, List uniformNames) native;
+
+  void invalidateFramebuffer(int target, List<int> attachments) native;
+
+  void invalidateSubFramebuffer(int target, List<int> attachments, int x, int y,
+      int width, int height) native;
+
+  bool isQuery(Query query) native;
+
+  bool isSampler(Sampler sampler) native;
+
+  bool isSync(Sync sync) native;
+
+  bool isTransformFeedback(TransformFeedback feedback) native;
+
+  bool isVertexArray(VertexArrayObject vertexArray) native;
+
+  void pauseTransformFeedback() native;
+
+  void readBuffer(int mode) native;
+
+  @JSName('readPixels')
+  void readPixels2(int x, int y, int width, int height, int format, int type,
+      dstData_OR_offset,
+      [int offset]) native;
+
+  void renderbufferStorageMultisample(int target, int samples,
+      int internalformat, int width, int height) native;
+
+  void resumeTransformFeedback() native;
+
+  void samplerParameterf(Sampler sampler, int pname, num param) native;
+
+  void samplerParameteri(Sampler sampler, int pname, int param) native;
+
+  void texImage2D2(
+      int target,
+      int level,
+      int internalformat,
+      int width,
+      int height,
+      int border,
+      int format,
+      int type,
+      bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_srcData_OR_video,
+      [int srcOffset]) {
+    if ((bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_srcData_OR_video
+            is int) &&
+        srcOffset == null) {
+      _texImage2D2_1(
+          target,
+          level,
+          internalformat,
+          width,
+          height,
+          border,
+          format,
+          type,
+          bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_srcData_OR_video);
+      return;
+    }
+    if ((bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_srcData_OR_video
+            is ImageData) &&
+        srcOffset == null) {
+      var data_1 = convertDartToNative_ImageData(
+          bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_srcData_OR_video);
+      _texImage2D2_2(target, level, internalformat, width, height, border,
+          format, type, data_1);
+      return;
+    }
+    if ((bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_srcData_OR_video
+            is ImageElement) &&
+        srcOffset == null) {
+      _texImage2D2_3(
+          target,
+          level,
+          internalformat,
+          width,
+          height,
+          border,
+          format,
+          type,
+          bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_srcData_OR_video);
+      return;
+    }
+    if ((bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_srcData_OR_video
+            is CanvasElement) &&
+        srcOffset == null) {
+      _texImage2D2_4(
+          target,
+          level,
+          internalformat,
+          width,
+          height,
+          border,
+          format,
+          type,
+          bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_srcData_OR_video);
+      return;
+    }
+    if ((bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_srcData_OR_video
+            is VideoElement) &&
+        srcOffset == null) {
+      _texImage2D2_5(
+          target,
+          level,
+          internalformat,
+          width,
+          height,
+          border,
+          format,
+          type,
+          bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_srcData_OR_video);
+      return;
+    }
+    if ((bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_srcData_OR_video
+            is ImageBitmap) &&
+        srcOffset == null) {
+      _texImage2D2_6(
+          target,
+          level,
+          internalformat,
+          width,
+          height,
+          border,
+          format,
+          type,
+          bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_srcData_OR_video);
+      return;
+    }
+    if (srcOffset != null &&
+        (bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_srcData_OR_video
+            is TypedData)) {
+      _texImage2D2_7(
+          target,
+          level,
+          internalformat,
+          width,
+          height,
+          border,
+          format,
+          type,
+          bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_srcData_OR_video,
+          srcOffset);
+      return;
+    }
+    throw new ArgumentError("Incorrect number or type of arguments");
+  }
+
+  @JSName('texImage2D')
+  void _texImage2D2_1(target, level, internalformat, width, height, border,
+      format, type, int offset) native;
+  @JSName('texImage2D')
+  void _texImage2D2_2(target, level, internalformat, width, height, border,
+      format, type, data) native;
+  @JSName('texImage2D')
+  void _texImage2D2_3(target, level, internalformat, width, height, border,
+      format, type, ImageElement image) native;
+  @JSName('texImage2D')
+  void _texImage2D2_4(target, level, internalformat, width, height, border,
+      format, type, CanvasElement canvas) native;
+  @JSName('texImage2D')
+  void _texImage2D2_5(target, level, internalformat, width, height, border,
+      format, type, VideoElement video) native;
+  @JSName('texImage2D')
+  void _texImage2D2_6(target, level, internalformat, width, height, border,
+      format, type, ImageBitmap bitmap) native;
+  @JSName('texImage2D')
+  void _texImage2D2_7(target, level, internalformat, width, height, border,
+      format, type, TypedData srcData, srcOffset) native;
+
+  void texImage3D(
+      int target,
+      int level,
+      int internalformat,
+      int width,
+      int height,
+      int depth,
+      int border,
+      int format,
+      int type,
+      bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_pixels_OR_video,
+      [int srcOffset]) {
+    if ((bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_pixels_OR_video
+            is int) &&
+        srcOffset == null) {
+      _texImage3D_1(
+          target,
+          level,
+          internalformat,
+          width,
+          height,
+          depth,
+          border,
+          format,
+          type,
+          bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_pixels_OR_video);
+      return;
+    }
+    if ((bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_pixels_OR_video
+            is ImageData) &&
+        srcOffset == null) {
+      var data_1 = convertDartToNative_ImageData(
+          bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_pixels_OR_video);
+      _texImage3D_2(target, level, internalformat, width, height, depth, border,
+          format, type, data_1);
+      return;
+    }
+    if ((bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_pixels_OR_video
+            is ImageElement) &&
+        srcOffset == null) {
+      _texImage3D_3(
+          target,
+          level,
+          internalformat,
+          width,
+          height,
+          depth,
+          border,
+          format,
+          type,
+          bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_pixels_OR_video);
+      return;
+    }
+    if ((bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_pixels_OR_video
+            is CanvasElement) &&
+        srcOffset == null) {
+      _texImage3D_4(
+          target,
+          level,
+          internalformat,
+          width,
+          height,
+          depth,
+          border,
+          format,
+          type,
+          bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_pixels_OR_video);
+      return;
+    }
+    if ((bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_pixels_OR_video
+            is VideoElement) &&
+        srcOffset == null) {
+      _texImage3D_5(
+          target,
+          level,
+          internalformat,
+          width,
+          height,
+          depth,
+          border,
+          format,
+          type,
+          bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_pixels_OR_video);
+      return;
+    }
+    if ((bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_pixels_OR_video
+            is ImageBitmap) &&
+        srcOffset == null) {
+      _texImage3D_6(
+          target,
+          level,
+          internalformat,
+          width,
+          height,
+          depth,
+          border,
+          format,
+          type,
+          bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_pixels_OR_video);
+      return;
+    }
+    if ((bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_pixels_OR_video
+                is TypedData ||
+            bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_pixels_OR_video ==
+                null) &&
+        srcOffset == null) {
+      _texImage3D_7(
+          target,
+          level,
+          internalformat,
+          width,
+          height,
+          depth,
+          border,
+          format,
+          type,
+          bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_pixels_OR_video);
+      return;
+    }
+    if (srcOffset != null &&
+        (bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_pixels_OR_video
+            is TypedData)) {
+      _texImage3D_8(
+          target,
+          level,
+          internalformat,
+          width,
+          height,
+          depth,
+          border,
+          format,
+          type,
+          bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_pixels_OR_video,
+          srcOffset);
+      return;
+    }
+    throw new ArgumentError("Incorrect number or type of arguments");
+  }
+
+  @JSName('texImage3D')
+  void _texImage3D_1(target, level, internalformat, width, height, depth,
+      border, format, type, int offset) native;
+  @JSName('texImage3D')
+  void _texImage3D_2(target, level, internalformat, width, height, depth,
+      border, format, type, data) native;
+  @JSName('texImage3D')
+  void _texImage3D_3(target, level, internalformat, width, height, depth,
+      border, format, type, ImageElement image) native;
+  @JSName('texImage3D')
+  void _texImage3D_4(target, level, internalformat, width, height, depth,
+      border, format, type, CanvasElement canvas) native;
+  @JSName('texImage3D')
+  void _texImage3D_5(target, level, internalformat, width, height, depth,
+      border, format, type, VideoElement video) native;
+  @JSName('texImage3D')
+  void _texImage3D_6(target, level, internalformat, width, height, depth,
+      border, format, type, ImageBitmap bitmap) native;
+  @JSName('texImage3D')
+  void _texImage3D_7(target, level, internalformat, width, height, depth,
+      border, format, type, TypedData pixels) native;
+  @JSName('texImage3D')
+  void _texImage3D_8(target, level, internalformat, width, height, depth,
+      border, format, type, TypedData pixels, srcOffset) native;
+
+  void texStorage2D(
+      int target, int levels, int internalformat, int width, int height) native;
+
+  void texStorage3D(int target, int levels, int internalformat, int width,
+      int height, int depth) native;
+
+  void texSubImage2D2(
+      int target,
+      int level,
+      int xoffset,
+      int yoffset,
+      int width,
+      int height,
+      int format,
+      int type,
+      bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_srcData_OR_video,
+      [int srcOffset]) {
+    if ((bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_srcData_OR_video
+            is int) &&
+        srcOffset == null) {
+      _texSubImage2D2_1(
+          target,
+          level,
+          xoffset,
+          yoffset,
+          width,
+          height,
+          format,
+          type,
+          bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_srcData_OR_video);
+      return;
+    }
+    if ((bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_srcData_OR_video
+            is ImageData) &&
+        srcOffset == null) {
+      var data_1 = convertDartToNative_ImageData(
+          bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_srcData_OR_video);
+      _texSubImage2D2_2(
+          target, level, xoffset, yoffset, width, height, format, type, data_1);
+      return;
+    }
+    if ((bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_srcData_OR_video
+            is ImageElement) &&
+        srcOffset == null) {
+      _texSubImage2D2_3(
+          target,
+          level,
+          xoffset,
+          yoffset,
+          width,
+          height,
+          format,
+          type,
+          bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_srcData_OR_video);
+      return;
+    }
+    if ((bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_srcData_OR_video
+            is CanvasElement) &&
+        srcOffset == null) {
+      _texSubImage2D2_4(
+          target,
+          level,
+          xoffset,
+          yoffset,
+          width,
+          height,
+          format,
+          type,
+          bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_srcData_OR_video);
+      return;
+    }
+    if ((bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_srcData_OR_video
+            is VideoElement) &&
+        srcOffset == null) {
+      _texSubImage2D2_5(
+          target,
+          level,
+          xoffset,
+          yoffset,
+          width,
+          height,
+          format,
+          type,
+          bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_srcData_OR_video);
+      return;
+    }
+    if ((bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_srcData_OR_video
+            is ImageBitmap) &&
+        srcOffset == null) {
+      _texSubImage2D2_6(
+          target,
+          level,
+          xoffset,
+          yoffset,
+          width,
+          height,
+          format,
+          type,
+          bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_srcData_OR_video);
+      return;
+    }
+    if (srcOffset != null &&
+        (bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_srcData_OR_video
+            is TypedData)) {
+      _texSubImage2D2_7(
+          target,
+          level,
+          xoffset,
+          yoffset,
+          width,
+          height,
+          format,
+          type,
+          bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_srcData_OR_video,
+          srcOffset);
+      return;
+    }
+    throw new ArgumentError("Incorrect number or type of arguments");
+  }
+
+  @JSName('texSubImage2D')
+  void _texSubImage2D2_1(target, level, xoffset, yoffset, width, height, format,
+      type, int offset) native;
+  @JSName('texSubImage2D')
+  void _texSubImage2D2_2(target, level, xoffset, yoffset, width, height, format,
+      type, data) native;
+  @JSName('texSubImage2D')
+  void _texSubImage2D2_3(target, level, xoffset, yoffset, width, height, format,
+      type, ImageElement image) native;
+  @JSName('texSubImage2D')
+  void _texSubImage2D2_4(target, level, xoffset, yoffset, width, height, format,
+      type, CanvasElement canvas) native;
+  @JSName('texSubImage2D')
+  void _texSubImage2D2_5(target, level, xoffset, yoffset, width, height, format,
+      type, VideoElement video) native;
+  @JSName('texSubImage2D')
+  void _texSubImage2D2_6(target, level, xoffset, yoffset, width, height, format,
+      type, ImageBitmap bitmap) native;
+  @JSName('texSubImage2D')
+  void _texSubImage2D2_7(target, level, xoffset, yoffset, width, height, format,
+      type, TypedData srcData, srcOffset) native;
+
+  void texSubImage3D(
+      int target,
+      int level,
+      int xoffset,
+      int yoffset,
+      int zoffset,
+      int width,
+      int height,
+      int depth,
+      int format,
+      int type,
+      bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_pixels_OR_video,
+      [int srcOffset]) {
+    if ((bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_pixels_OR_video
+            is int) &&
+        srcOffset == null) {
+      _texSubImage3D_1(
+          target,
+          level,
+          xoffset,
+          yoffset,
+          zoffset,
+          width,
+          height,
+          depth,
+          format,
+          type,
+          bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_pixels_OR_video);
+      return;
+    }
+    if ((bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_pixels_OR_video
+            is ImageData) &&
+        srcOffset == null) {
+      var data_1 = convertDartToNative_ImageData(
+          bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_pixels_OR_video);
+      _texSubImage3D_2(target, level, xoffset, yoffset, zoffset, width, height,
+          depth, format, type, data_1);
+      return;
+    }
+    if ((bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_pixels_OR_video
+            is ImageElement) &&
+        srcOffset == null) {
+      _texSubImage3D_3(
+          target,
+          level,
+          xoffset,
+          yoffset,
+          zoffset,
+          width,
+          height,
+          depth,
+          format,
+          type,
+          bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_pixels_OR_video);
+      return;
+    }
+    if ((bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_pixels_OR_video
+            is CanvasElement) &&
+        srcOffset == null) {
+      _texSubImage3D_4(
+          target,
+          level,
+          xoffset,
+          yoffset,
+          zoffset,
+          width,
+          height,
+          depth,
+          format,
+          type,
+          bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_pixels_OR_video);
+      return;
+    }
+    if ((bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_pixels_OR_video
+            is VideoElement) &&
+        srcOffset == null) {
+      _texSubImage3D_5(
+          target,
+          level,
+          xoffset,
+          yoffset,
+          zoffset,
+          width,
+          height,
+          depth,
+          format,
+          type,
+          bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_pixels_OR_video);
+      return;
+    }
+    if ((bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_pixels_OR_video
+            is ImageBitmap) &&
+        srcOffset == null) {
+      _texSubImage3D_6(
+          target,
+          level,
+          xoffset,
+          yoffset,
+          zoffset,
+          width,
+          height,
+          depth,
+          format,
+          type,
+          bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_pixels_OR_video);
+      return;
+    }
+    if ((bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_pixels_OR_video
+            is TypedData) &&
+        srcOffset == null) {
+      _texSubImage3D_7(
+          target,
+          level,
+          xoffset,
+          yoffset,
+          zoffset,
+          width,
+          height,
+          depth,
+          format,
+          type,
+          bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_pixels_OR_video);
+      return;
+    }
+    if (srcOffset != null &&
+        (bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_pixels_OR_video
+            is TypedData)) {
+      _texSubImage3D_8(
+          target,
+          level,
+          xoffset,
+          yoffset,
+          zoffset,
+          width,
+          height,
+          depth,
+          format,
+          type,
+          bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_pixels_OR_video,
+          srcOffset);
+      return;
+    }
+    throw new ArgumentError("Incorrect number or type of arguments");
+  }
+
+  @JSName('texSubImage3D')
+  void _texSubImage3D_1(target, level, xoffset, yoffset, zoffset, width, height,
+      depth, format, type, int offset) native;
+  @JSName('texSubImage3D')
+  void _texSubImage3D_2(target, level, xoffset, yoffset, zoffset, width, height,
+      depth, format, type, data) native;
+  @JSName('texSubImage3D')
+  void _texSubImage3D_3(target, level, xoffset, yoffset, zoffset, width, height,
+      depth, format, type, ImageElement image) native;
+  @JSName('texSubImage3D')
+  void _texSubImage3D_4(target, level, xoffset, yoffset, zoffset, width, height,
+      depth, format, type, CanvasElement canvas) native;
+  @JSName('texSubImage3D')
+  void _texSubImage3D_5(target, level, xoffset, yoffset, zoffset, width, height,
+      depth, format, type, VideoElement video) native;
+  @JSName('texSubImage3D')
+  void _texSubImage3D_6(target, level, xoffset, yoffset, zoffset, width, height,
+      depth, format, type, ImageBitmap bitmap) native;
+  @JSName('texSubImage3D')
+  void _texSubImage3D_7(target, level, xoffset, yoffset, zoffset, width, height,
+      depth, format, type, TypedData pixels) native;
+  @JSName('texSubImage3D')
+  void _texSubImage3D_8(target, level, xoffset, yoffset, zoffset, width, height,
+      depth, format, type, TypedData pixels, srcOffset) native;
+
+  void transformFeedbackVaryings(
+      Program program, List<String> varyings, int bufferMode) {
+    List varyings_1 = convertDartToNative_StringArray(varyings);
+    _transformFeedbackVaryings_1(program, varyings_1, bufferMode);
+    return;
+  }
+
+  @JSName('transformFeedbackVaryings')
+  void _transformFeedbackVaryings_1(Program program, List varyings, bufferMode)
+      native;
+
+  @JSName('uniform1fv')
+  void uniform1fv2(UniformLocation location, v, int srcOffset, [int srcLength])
+      native;
+
+  @JSName('uniform1iv')
+  void uniform1iv2(UniformLocation location, v, int srcOffset, [int srcLength])
+      native;
+
+  void uniform1ui(UniformLocation location, int v0) native;
+
+  void uniform1uiv(UniformLocation location, v, [int srcOffset, int srcLength])
+      native;
+
+  @JSName('uniform2fv')
+  void uniform2fv2(UniformLocation location, v, int srcOffset, [int srcLength])
+      native;
+
+  @JSName('uniform2iv')
+  void uniform2iv2(UniformLocation location, v, int srcOffset, [int srcLength])
+      native;
+
+  void uniform2ui(UniformLocation location, int v0, int v1) native;
+
+  void uniform2uiv(UniformLocation location, v, [int srcOffset, int srcLength])
+      native;
+
+  @JSName('uniform3fv')
+  void uniform3fv2(UniformLocation location, v, int srcOffset, [int srcLength])
+      native;
+
+  @JSName('uniform3iv')
+  void uniform3iv2(UniformLocation location, v, int srcOffset, [int srcLength])
+      native;
+
+  void uniform3ui(UniformLocation location, int v0, int v1, int v2) native;
+
+  void uniform3uiv(UniformLocation location, v, [int srcOffset, int srcLength])
+      native;
+
+  @JSName('uniform4fv')
+  void uniform4fv2(UniformLocation location, v, int srcOffset, [int srcLength])
+      native;
+
+  @JSName('uniform4iv')
+  void uniform4iv2(UniformLocation location, v, int srcOffset, [int srcLength])
+      native;
+
+  void uniform4ui(UniformLocation location, int v0, int v1, int v2, int v3)
+      native;
+
+  void uniform4uiv(UniformLocation location, v, [int srcOffset, int srcLength])
+      native;
+
+  void uniformBlockBinding(
+      Program program, int uniformBlockIndex, int uniformBlockBinding) native;
+
+  @JSName('uniformMatrix2fv')
+  void uniformMatrix2fv2(
+      UniformLocation location, bool transpose, array, int srcOffset,
+      [int srcLength]) native;
+
+  void uniformMatrix2x3fv(UniformLocation location, bool transpose, value,
+      [int srcOffset, int srcLength]) native;
+
+  void uniformMatrix2x4fv(UniformLocation location, bool transpose, value,
+      [int srcOffset, int srcLength]) native;
+
+  @JSName('uniformMatrix3fv')
+  void uniformMatrix3fv2(
+      UniformLocation location, bool transpose, array, int srcOffset,
+      [int srcLength]) native;
+
+  void uniformMatrix3x2fv(UniformLocation location, bool transpose, value,
+      [int srcOffset, int srcLength]) native;
+
+  void uniformMatrix3x4fv(UniformLocation location, bool transpose, value,
+      [int srcOffset, int srcLength]) native;
+
+  @JSName('uniformMatrix4fv')
+  void uniformMatrix4fv2(
+      UniformLocation location, bool transpose, array, int srcOffset,
+      [int srcLength]) native;
+
+  void uniformMatrix4x2fv(UniformLocation location, bool transpose, value,
+      [int srcOffset, int srcLength]) native;
+
+  void uniformMatrix4x3fv(UniformLocation location, bool transpose, value,
+      [int srcOffset, int srcLength]) native;
+
+  void vertexAttribDivisor(int index, int divisor) native;
+
+  void vertexAttribI4i(int index, int x, int y, int z, int w) native;
+
+  void vertexAttribI4iv(int index, v) native;
+
+  void vertexAttribI4ui(int index, int x, int y, int z, int w) native;
+
+  void vertexAttribI4uiv(int index, v) native;
+
+  void vertexAttribIPointer(
+      int index, int size, int type, int stride, int offset) native;
+
+  void waitSync(Sync sync, int flags, int timeout) native;
+
+  // From WebGLRenderingContextBase
+
+  final int drawingBufferHeight;
+
+  final int drawingBufferWidth;
+
+  void activeTexture(int texture) native;
+
+  void attachShader(Program program, Shader shader) native;
+
+  void bindAttribLocation(Program program, int index, String name) native;
+
+  void bindBuffer(int target, Buffer buffer) native;
+
+  void bindFramebuffer(int target, Framebuffer framebuffer) native;
+
+  void bindRenderbuffer(int target, Renderbuffer renderbuffer) native;
+
+  void bindTexture(int target, Texture texture) native;
+
+  void blendColor(num red, num green, num blue, num alpha) native;
+
+  void blendEquation(int mode) native;
+
+  void blendEquationSeparate(int modeRGB, int modeAlpha) native;
+
+  void blendFunc(int sfactor, int dfactor) native;
+
+  void blendFuncSeparate(int srcRGB, int dstRGB, int srcAlpha, int dstAlpha)
+      native;
+
+  void bufferData(int target, data_OR_size, int usage) native;
+
+  void bufferSubData(int target, int offset, data) native;
+
+  int checkFramebufferStatus(int target) native;
+
+  void clear(int mask) native;
+
+  void clearColor(num red, num green, num blue, num alpha) native;
+
+  void clearDepth(num depth) native;
+
+  void clearStencil(int s) native;
+
+  void colorMask(bool red, bool green, bool blue, bool alpha) native;
+
+  Future commit() => promiseToFuture(JS("", "#.commit()", this));
+
+  void compileShader(Shader shader) native;
+
+  void compressedTexImage2D(int target, int level, int internalformat,
+      int width, int height, int border, TypedData data) native;
+
+  void compressedTexSubImage2D(int target, int level, int xoffset, int yoffset,
+      int width, int height, int format, TypedData data) native;
+
+  void copyTexImage2D(int target, int level, int internalformat, int x, int y,
+      int width, int height, int border) native;
+
+  void copyTexSubImage2D(int target, int level, int xoffset, int yoffset, int x,
+      int y, int width, int height) native;
+
+  Buffer createBuffer() native;
+
+  Framebuffer createFramebuffer() native;
+
+  Program createProgram() native;
+
+  Renderbuffer createRenderbuffer() native;
+
+  Shader createShader(int type) native;
+
+  Texture createTexture() native;
+
+  void cullFace(int mode) native;
+
+  void deleteBuffer(Buffer buffer) native;
+
+  void deleteFramebuffer(Framebuffer framebuffer) native;
+
+  void deleteProgram(Program program) native;
+
+  void deleteRenderbuffer(Renderbuffer renderbuffer) native;
+
+  void deleteShader(Shader shader) native;
+
+  void deleteTexture(Texture texture) native;
+
+  void depthFunc(int func) native;
+
+  void depthMask(bool flag) native;
+
+  void depthRange(num zNear, num zFar) native;
+
+  void detachShader(Program program, Shader shader) native;
+
+  void disable(int cap) native;
+
+  void disableVertexAttribArray(int index) native;
+
+  void drawArrays(int mode, int first, int count) native;
+
+  void drawElements(int mode, int count, int type, int offset) native;
+
+  void enable(int cap) native;
+
+  void enableVertexAttribArray(int index) native;
+
+  void finish() native;
+
+  void flush() native;
+
+  void framebufferRenderbuffer(int target, int attachment,
+      int renderbuffertarget, Renderbuffer renderbuffer) native;
+
+  void framebufferTexture2D(int target, int attachment, int textarget,
+      Texture texture, int level) native;
+
+  void frontFace(int mode) native;
+
+  void generateMipmap(int target) native;
+
+  ActiveInfo getActiveAttrib(Program program, int index) native;
+
+  ActiveInfo getActiveUniform(Program program, int index) native;
+
+  List<Shader> getAttachedShaders(Program program) native;
+
+  int getAttribLocation(Program program, String name) native;
+
+  Object getBufferParameter(int target, int pname) native;
+
+  Map getContextAttributes() {
+    return convertNativeToDart_Dictionary(_getContextAttributes_1());
+  }
+
+  @JSName('getContextAttributes')
+  _getContextAttributes_1() native;
+
+  int getError() native;
+
+  Object getExtension(String name) native;
+
+  Object getFramebufferAttachmentParameter(
+      int target, int attachment, int pname) native;
+
+  Object getParameter(int pname) native;
+
+  String getProgramInfoLog(Program program) native;
+
+  Object getProgramParameter(Program program, int pname) native;
+
+  Object getRenderbufferParameter(int target, int pname) native;
+
+  String getShaderInfoLog(Shader shader) native;
+
+  Object getShaderParameter(Shader shader, int pname) native;
+
+  ShaderPrecisionFormat getShaderPrecisionFormat(
+      int shadertype, int precisiontype) native;
+
+  String getShaderSource(Shader shader) native;
+
+  List<String> getSupportedExtensions() native;
+
+  Object getTexParameter(int target, int pname) native;
+
+  Object getUniform(Program program, UniformLocation location) native;
+
+  UniformLocation getUniformLocation(Program program, String name) native;
+
+  Object getVertexAttrib(int index, int pname) native;
+
+  int getVertexAttribOffset(int index, int pname) native;
+
+  void hint(int target, int mode) native;
+
+  bool isBuffer(Buffer buffer) native;
+
+  bool isContextLost() native;
+
+  bool isEnabled(int cap) native;
+
+  bool isFramebuffer(Framebuffer framebuffer) native;
+
+  bool isProgram(Program program) native;
+
+  bool isRenderbuffer(Renderbuffer renderbuffer) native;
+
+  bool isShader(Shader shader) native;
+
+  bool isTexture(Texture texture) native;
+
+  void lineWidth(num width) native;
+
+  void linkProgram(Program program) native;
+
+  void pixelStorei(int pname, int param) native;
+
+  void polygonOffset(num factor, num units) native;
+
+  @JSName('readPixels')
+  void _readPixels(int x, int y, int width, int height, int format, int type,
+      TypedData pixels) native;
+
+  void renderbufferStorage(
+      int target, int internalformat, int width, int height) native;
+
+  void sampleCoverage(num value, bool invert) native;
+
+  void scissor(int x, int y, int width, int height) native;
+
+  void shaderSource(Shader shader, String string) native;
+
+  void stencilFunc(int func, int ref, int mask) native;
+
+  void stencilFuncSeparate(int face, int func, int ref, int mask) native;
+
+  void stencilMask(int mask) native;
+
+  void stencilMaskSeparate(int face, int mask) native;
+
+  void stencilOp(int fail, int zfail, int zpass) native;
+
+  void stencilOpSeparate(int face, int fail, int zfail, int zpass) native;
+
+  void texImage2D(
+      int target,
+      int level,
+      int internalformat,
+      int format_OR_width,
+      int height_OR_type,
+      bitmap_OR_border_OR_canvas_OR_image_OR_pixels_OR_video,
+      [int format,
+      int type,
+      TypedData pixels]) {
+    if (type != null &&
+        format != null &&
+        (bitmap_OR_border_OR_canvas_OR_image_OR_pixels_OR_video is int)) {
+      _texImage2D_1(
+          target,
+          level,
+          internalformat,
+          format_OR_width,
+          height_OR_type,
+          bitmap_OR_border_OR_canvas_OR_image_OR_pixels_OR_video,
+          format,
+          type,
+          pixels);
+      return;
+    }
+    if ((bitmap_OR_border_OR_canvas_OR_image_OR_pixels_OR_video is ImageData) &&
+        format == null &&
+        type == null &&
+        pixels == null) {
+      var pixels_1 = convertDartToNative_ImageData(
+          bitmap_OR_border_OR_canvas_OR_image_OR_pixels_OR_video);
+      _texImage2D_2(target, level, internalformat, format_OR_width,
+          height_OR_type, pixels_1);
+      return;
+    }
+    if ((bitmap_OR_border_OR_canvas_OR_image_OR_pixels_OR_video
+            is ImageElement) &&
+        format == null &&
+        type == null &&
+        pixels == null) {
+      _texImage2D_3(
+          target,
+          level,
+          internalformat,
+          format_OR_width,
+          height_OR_type,
+          bitmap_OR_border_OR_canvas_OR_image_OR_pixels_OR_video);
+      return;
+    }
+    if ((bitmap_OR_border_OR_canvas_OR_image_OR_pixels_OR_video
+            is CanvasElement) &&
+        format == null &&
+        type == null &&
+        pixels == null) {
+      _texImage2D_4(
+          target,
+          level,
+          internalformat,
+          format_OR_width,
+          height_OR_type,
+          bitmap_OR_border_OR_canvas_OR_image_OR_pixels_OR_video);
+      return;
+    }
+    if ((bitmap_OR_border_OR_canvas_OR_image_OR_pixels_OR_video
+            is VideoElement) &&
+        format == null &&
+        type == null &&
+        pixels == null) {
+      _texImage2D_5(
+          target,
+          level,
+          internalformat,
+          format_OR_width,
+          height_OR_type,
+          bitmap_OR_border_OR_canvas_OR_image_OR_pixels_OR_video);
+      return;
+    }
+    if ((bitmap_OR_border_OR_canvas_OR_image_OR_pixels_OR_video
+            is ImageBitmap) &&
+        format == null &&
+        type == null &&
+        pixels == null) {
+      _texImage2D_6(
+          target,
+          level,
+          internalformat,
+          format_OR_width,
+          height_OR_type,
+          bitmap_OR_border_OR_canvas_OR_image_OR_pixels_OR_video);
+      return;
+    }
+    throw new ArgumentError("Incorrect number or type of arguments");
+  }
+
+  @JSName('texImage2D')
+  void _texImage2D_1(target, level, internalformat, width, height, int border,
+      format, type, TypedData pixels) native;
+  @JSName('texImage2D')
+  void _texImage2D_2(target, level, internalformat, format, type, pixels)
+      native;
+  @JSName('texImage2D')
+  void _texImage2D_3(
+      target, level, internalformat, format, type, ImageElement image) native;
+  @JSName('texImage2D')
+  void _texImage2D_4(
+      target, level, internalformat, format, type, CanvasElement canvas) native;
+  @JSName('texImage2D')
+  void _texImage2D_5(
+      target, level, internalformat, format, type, VideoElement video) native;
+  @JSName('texImage2D')
+  void _texImage2D_6(
+      target, level, internalformat, format, type, ImageBitmap bitmap) native;
+
+  void texParameterf(int target, int pname, num param) native;
+
+  void texParameteri(int target, int pname, int param) native;
+
+  void texSubImage2D(
+      int target,
+      int level,
+      int xoffset,
+      int yoffset,
+      int format_OR_width,
+      int height_OR_type,
+      bitmap_OR_canvas_OR_format_OR_image_OR_pixels_OR_video,
+      [int type,
+      TypedData pixels]) {
+    if (type != null &&
+        (bitmap_OR_canvas_OR_format_OR_image_OR_pixels_OR_video is int)) {
+      _texSubImage2D_1(
+          target,
+          level,
+          xoffset,
+          yoffset,
+          format_OR_width,
+          height_OR_type,
+          bitmap_OR_canvas_OR_format_OR_image_OR_pixels_OR_video,
+          type,
+          pixels);
+      return;
+    }
+    if ((bitmap_OR_canvas_OR_format_OR_image_OR_pixels_OR_video is ImageData) &&
+        type == null &&
+        pixels == null) {
+      var pixels_1 = convertDartToNative_ImageData(
+          bitmap_OR_canvas_OR_format_OR_image_OR_pixels_OR_video);
+      _texSubImage2D_2(target, level, xoffset, yoffset, format_OR_width,
+          height_OR_type, pixels_1);
+      return;
+    }
+    if ((bitmap_OR_canvas_OR_format_OR_image_OR_pixels_OR_video
+            is ImageElement) &&
+        type == null &&
+        pixels == null) {
+      _texSubImage2D_3(
+          target,
+          level,
+          xoffset,
+          yoffset,
+          format_OR_width,
+          height_OR_type,
+          bitmap_OR_canvas_OR_format_OR_image_OR_pixels_OR_video);
+      return;
+    }
+    if ((bitmap_OR_canvas_OR_format_OR_image_OR_pixels_OR_video
+            is CanvasElement) &&
+        type == null &&
+        pixels == null) {
+      _texSubImage2D_4(
+          target,
+          level,
+          xoffset,
+          yoffset,
+          format_OR_width,
+          height_OR_type,
+          bitmap_OR_canvas_OR_format_OR_image_OR_pixels_OR_video);
+      return;
+    }
+    if ((bitmap_OR_canvas_OR_format_OR_image_OR_pixels_OR_video
+            is VideoElement) &&
+        type == null &&
+        pixels == null) {
+      _texSubImage2D_5(
+          target,
+          level,
+          xoffset,
+          yoffset,
+          format_OR_width,
+          height_OR_type,
+          bitmap_OR_canvas_OR_format_OR_image_OR_pixels_OR_video);
+      return;
+    }
+    if ((bitmap_OR_canvas_OR_format_OR_image_OR_pixels_OR_video
+            is ImageBitmap) &&
+        type == null &&
+        pixels == null) {
+      _texSubImage2D_6(
+          target,
+          level,
+          xoffset,
+          yoffset,
+          format_OR_width,
+          height_OR_type,
+          bitmap_OR_canvas_OR_format_OR_image_OR_pixels_OR_video);
+      return;
+    }
+    throw new ArgumentError("Incorrect number or type of arguments");
+  }
+
+  @JSName('texSubImage2D')
+  void _texSubImage2D_1(target, level, xoffset, yoffset, width, height,
+      int format, type, TypedData pixels) native;
+  @JSName('texSubImage2D')
+  void _texSubImage2D_2(target, level, xoffset, yoffset, format, type, pixels)
+      native;
+  @JSName('texSubImage2D')
+  void _texSubImage2D_3(
+      target, level, xoffset, yoffset, format, type, ImageElement image) native;
+  @JSName('texSubImage2D')
+  void _texSubImage2D_4(target, level, xoffset, yoffset, format, type,
+      CanvasElement canvas) native;
+  @JSName('texSubImage2D')
+  void _texSubImage2D_5(
+      target, level, xoffset, yoffset, format, type, VideoElement video) native;
+  @JSName('texSubImage2D')
+  void _texSubImage2D_6(
+      target, level, xoffset, yoffset, format, type, ImageBitmap bitmap) native;
+
+  void uniform1f(UniformLocation location, num x) native;
+
+  void uniform1fv(UniformLocation location, v) native;
+
+  void uniform1i(UniformLocation location, int x) native;
+
+  void uniform1iv(UniformLocation location, v) native;
+
+  void uniform2f(UniformLocation location, num x, num y) native;
+
+  void uniform2fv(UniformLocation location, v) native;
+
+  void uniform2i(UniformLocation location, int x, int y) native;
+
+  void uniform2iv(UniformLocation location, v) native;
+
+  void uniform3f(UniformLocation location, num x, num y, num z) native;
+
+  void uniform3fv(UniformLocation location, v) native;
+
+  void uniform3i(UniformLocation location, int x, int y, int z) native;
+
+  void uniform3iv(UniformLocation location, v) native;
+
+  void uniform4f(UniformLocation location, num x, num y, num z, num w) native;
+
+  void uniform4fv(UniformLocation location, v) native;
+
+  void uniform4i(UniformLocation location, int x, int y, int z, int w) native;
+
+  void uniform4iv(UniformLocation location, v) native;
+
+  void uniformMatrix2fv(UniformLocation location, bool transpose, array) native;
+
+  void uniformMatrix3fv(UniformLocation location, bool transpose, array) native;
+
+  void uniformMatrix4fv(UniformLocation location, bool transpose, array) native;
+
+  void useProgram(Program program) native;
+
+  void validateProgram(Program program) native;
+
+  void vertexAttrib1f(int indx, num x) native;
+
+  void vertexAttrib1fv(int indx, values) native;
+
+  void vertexAttrib2f(int indx, num x, num y) native;
+
+  void vertexAttrib2fv(int indx, values) native;
+
+  void vertexAttrib3f(int indx, num x, num y, num z) native;
+
+  void vertexAttrib3fv(int indx, values) native;
+
+  void vertexAttrib4f(int indx, num x, num y, num z, num w) native;
+
+  void vertexAttrib4fv(int indx, values) native;
+
+  void vertexAttribPointer(int indx, int size, int type, bool normalized,
+      int stride, int offset) native;
+
+  void viewport(int x, int y, int width, int height) native;
+
+  void readPixels(int x, int y, int width, int height, int format, int type,
+      TypedData pixels) {
+    _readPixels(x, y, width, height, format, type, pixels);
+  }
+}
+
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("WebGLSampler")
+class Sampler extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory Sampler._() {
+    throw new UnsupportedError("Not supported");
+  }
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("WebGLShader")
+class Shader extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory Shader._() {
+    throw new UnsupportedError("Not supported");
+  }
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("WebGLShaderPrecisionFormat")
+class ShaderPrecisionFormat extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory ShaderPrecisionFormat._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final int precision;
+
+  final int rangeMax;
+
+  final int rangeMin;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("WebGLSync")
+class Sync extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory Sync._() {
+    throw new UnsupportedError("Not supported");
+  }
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("WebGLTexture")
+class Texture extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory Texture._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final bool lastUploadedVideoFrameWasSkipped;
+
+  final int lastUploadedVideoHeight;
+
+  final num lastUploadedVideoTimestamp;
+
+  final int lastUploadedVideoWidth;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("WebGLTimerQueryEXT")
+class TimerQueryExt extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory TimerQueryExt._() {
+    throw new UnsupportedError("Not supported");
+  }
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("WebGLTransformFeedback")
+class TransformFeedback extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory TransformFeedback._() {
+    throw new UnsupportedError("Not supported");
+  }
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("WebGLUniformLocation")
+class UniformLocation extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory UniformLocation._() {
+    throw new UnsupportedError("Not supported");
+  }
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("WebGLVertexArrayObject")
+class VertexArrayObject extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory VertexArrayObject._() {
+    throw new UnsupportedError("Not supported");
+  }
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("WebGLVertexArrayObjectOES")
+class VertexArrayObjectOes extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory VertexArrayObjectOes._() {
+    throw new UnsupportedError("Not supported");
+  }
+}
+// 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.
+
+/// Amalgamation of the WebGL constants from the IDL interfaces in
+/// WebGLRenderingContextBase, WebGL2RenderingContextBase, & WebGLDrawBuffers.
+/// Because the RenderingContextBase interfaces are hidden they would be
+/// replicated in more than one class (e.g., RenderingContext and
+/// RenderingContext2) to prevent that duplication these 600+ constants are
+/// defined in one abstract class (WebGL).
+@Native("WebGL")
+abstract class WebGL {
+  // To suppress missing implicit constructor warnings.
+  factory WebGL._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  static const int ACTIVE_ATTRIBUTES = 0x8B89;
+
+  static const int ACTIVE_TEXTURE = 0x84E0;
+
+  static const int ACTIVE_UNIFORMS = 0x8B86;
+
+  static const int ACTIVE_UNIFORM_BLOCKS = 0x8A36;
+
+  static const int ALIASED_LINE_WIDTH_RANGE = 0x846E;
+
+  static const int ALIASED_POINT_SIZE_RANGE = 0x846D;
+
+  static const int ALPHA = 0x1906;
+
+  static const int ALPHA_BITS = 0x0D55;
+
+  static const int ALREADY_SIGNALED = 0x911A;
+
+  static const int ALWAYS = 0x0207;
+
+  static const int ANY_SAMPLES_PASSED = 0x8C2F;
+
+  static const int ANY_SAMPLES_PASSED_CONSERVATIVE = 0x8D6A;
+
+  static const int ARRAY_BUFFER = 0x8892;
+
+  static const int ARRAY_BUFFER_BINDING = 0x8894;
+
+  static const int ATTACHED_SHADERS = 0x8B85;
+
+  static const int BACK = 0x0405;
+
+  static const int BLEND = 0x0BE2;
+
+  static const int BLEND_COLOR = 0x8005;
+
+  static const int BLEND_DST_ALPHA = 0x80CA;
+
+  static const int BLEND_DST_RGB = 0x80C8;
+
+  static const int BLEND_EQUATION = 0x8009;
+
+  static const int BLEND_EQUATION_ALPHA = 0x883D;
+
+  static const int BLEND_EQUATION_RGB = 0x8009;
+
+  static const int BLEND_SRC_ALPHA = 0x80CB;
+
+  static const int BLEND_SRC_RGB = 0x80C9;
+
+  static const int BLUE_BITS = 0x0D54;
+
+  static const int BOOL = 0x8B56;
+
+  static const int BOOL_VEC2 = 0x8B57;
+
+  static const int BOOL_VEC3 = 0x8B58;
+
+  static const int BOOL_VEC4 = 0x8B59;
+
+  static const int BROWSER_DEFAULT_WEBGL = 0x9244;
+
+  static const int BUFFER_SIZE = 0x8764;
+
+  static const int BUFFER_USAGE = 0x8765;
+
+  static const int BYTE = 0x1400;
+
+  static const int CCW = 0x0901;
+
+  static const int CLAMP_TO_EDGE = 0x812F;
+
+  static const int COLOR = 0x1800;
+
+  static const int COLOR_ATTACHMENT0 = 0x8CE0;
+
+  static const int COLOR_ATTACHMENT0_WEBGL = 0x8CE0;
+
+  static const int COLOR_ATTACHMENT1 = 0x8CE1;
+
+  static const int COLOR_ATTACHMENT10 = 0x8CEA;
+
+  static const int COLOR_ATTACHMENT10_WEBGL = 0x8CEA;
+
+  static const int COLOR_ATTACHMENT11 = 0x8CEB;
+
+  static const int COLOR_ATTACHMENT11_WEBGL = 0x8CEB;
+
+  static const int COLOR_ATTACHMENT12 = 0x8CEC;
+
+  static const int COLOR_ATTACHMENT12_WEBGL = 0x8CEC;
+
+  static const int COLOR_ATTACHMENT13 = 0x8CED;
+
+  static const int COLOR_ATTACHMENT13_WEBGL = 0x8CED;
+
+  static const int COLOR_ATTACHMENT14 = 0x8CEE;
+
+  static const int COLOR_ATTACHMENT14_WEBGL = 0x8CEE;
+
+  static const int COLOR_ATTACHMENT15 = 0x8CEF;
+
+  static const int COLOR_ATTACHMENT15_WEBGL = 0x8CEF;
+
+  static const int COLOR_ATTACHMENT1_WEBGL = 0x8CE1;
+
+  static const int COLOR_ATTACHMENT2 = 0x8CE2;
+
+  static const int COLOR_ATTACHMENT2_WEBGL = 0x8CE2;
+
+  static const int COLOR_ATTACHMENT3 = 0x8CE3;
+
+  static const int COLOR_ATTACHMENT3_WEBGL = 0x8CE3;
+
+  static const int COLOR_ATTACHMENT4 = 0x8CE4;
+
+  static const int COLOR_ATTACHMENT4_WEBGL = 0x8CE4;
+
+  static const int COLOR_ATTACHMENT5 = 0x8CE5;
+
+  static const int COLOR_ATTACHMENT5_WEBGL = 0x8CE5;
+
+  static const int COLOR_ATTACHMENT6 = 0x8CE6;
+
+  static const int COLOR_ATTACHMENT6_WEBGL = 0x8CE6;
+
+  static const int COLOR_ATTACHMENT7 = 0x8CE7;
+
+  static const int COLOR_ATTACHMENT7_WEBGL = 0x8CE7;
+
+  static const int COLOR_ATTACHMENT8 = 0x8CE8;
+
+  static const int COLOR_ATTACHMENT8_WEBGL = 0x8CE8;
+
+  static const int COLOR_ATTACHMENT9 = 0x8CE9;
+
+  static const int COLOR_ATTACHMENT9_WEBGL = 0x8CE9;
+
+  static const int COLOR_BUFFER_BIT = 0x00004000;
+
+  static const int COLOR_CLEAR_VALUE = 0x0C22;
+
+  static const int COLOR_WRITEMASK = 0x0C23;
+
+  static const int COMPARE_REF_TO_TEXTURE = 0x884E;
+
+  static const int COMPILE_STATUS = 0x8B81;
+
+  static const int COMPRESSED_TEXTURE_FORMATS = 0x86A3;
+
+  static const int CONDITION_SATISFIED = 0x911C;
+
+  static const int CONSTANT_ALPHA = 0x8003;
+
+  static const int CONSTANT_COLOR = 0x8001;
+
+  static const int CONTEXT_LOST_WEBGL = 0x9242;
+
+  static const int COPY_READ_BUFFER = 0x8F36;
+
+  static const int COPY_READ_BUFFER_BINDING = 0x8F36;
+
+  static const int COPY_WRITE_BUFFER = 0x8F37;
+
+  static const int COPY_WRITE_BUFFER_BINDING = 0x8F37;
+
+  static const int CULL_FACE = 0x0B44;
+
+  static const int CULL_FACE_MODE = 0x0B45;
+
+  static const int CURRENT_PROGRAM = 0x8B8D;
+
+  static const int CURRENT_QUERY = 0x8865;
+
+  static const int CURRENT_VERTEX_ATTRIB = 0x8626;
+
+  static const int CW = 0x0900;
+
+  static const int DECR = 0x1E03;
+
+  static const int DECR_WRAP = 0x8508;
+
+  static const int DELETE_STATUS = 0x8B80;
+
+  static const int DEPTH = 0x1801;
+
+  static const int DEPTH24_STENCIL8 = 0x88F0;
+
+  static const int DEPTH32F_STENCIL8 = 0x8CAD;
+
+  static const int DEPTH_ATTACHMENT = 0x8D00;
+
+  static const int DEPTH_BITS = 0x0D56;
+
+  static const int DEPTH_BUFFER_BIT = 0x00000100;
+
+  static const int DEPTH_CLEAR_VALUE = 0x0B73;
+
+  static const int DEPTH_COMPONENT = 0x1902;
+
+  static const int DEPTH_COMPONENT16 = 0x81A5;
+
+  static const int DEPTH_COMPONENT24 = 0x81A6;
+
+  static const int DEPTH_COMPONENT32F = 0x8CAC;
+
+  static const int DEPTH_FUNC = 0x0B74;
+
+  static const int DEPTH_RANGE = 0x0B70;
+
+  static const int DEPTH_STENCIL = 0x84F9;
+
+  static const int DEPTH_STENCIL_ATTACHMENT = 0x821A;
+
+  static const int DEPTH_TEST = 0x0B71;
+
+  static const int DEPTH_WRITEMASK = 0x0B72;
+
+  static const int DITHER = 0x0BD0;
+
+  static const int DONT_CARE = 0x1100;
+
+  static const int DRAW_BUFFER0 = 0x8825;
+
+  static const int DRAW_BUFFER0_WEBGL = 0x8825;
+
+  static const int DRAW_BUFFER1 = 0x8826;
+
+  static const int DRAW_BUFFER10 = 0x882F;
+
+  static const int DRAW_BUFFER10_WEBGL = 0x882F;
+
+  static const int DRAW_BUFFER11 = 0x8830;
+
+  static const int DRAW_BUFFER11_WEBGL = 0x8830;
+
+  static const int DRAW_BUFFER12 = 0x8831;
+
+  static const int DRAW_BUFFER12_WEBGL = 0x8831;
+
+  static const int DRAW_BUFFER13 = 0x8832;
+
+  static const int DRAW_BUFFER13_WEBGL = 0x8832;
+
+  static const int DRAW_BUFFER14 = 0x8833;
+
+  static const int DRAW_BUFFER14_WEBGL = 0x8833;
+
+  static const int DRAW_BUFFER15 = 0x8834;
+
+  static const int DRAW_BUFFER15_WEBGL = 0x8834;
+
+  static const int DRAW_BUFFER1_WEBGL = 0x8826;
+
+  static const int DRAW_BUFFER2 = 0x8827;
+
+  static const int DRAW_BUFFER2_WEBGL = 0x8827;
+
+  static const int DRAW_BUFFER3 = 0x8828;
+
+  static const int DRAW_BUFFER3_WEBGL = 0x8828;
+
+  static const int DRAW_BUFFER4 = 0x8829;
+
+  static const int DRAW_BUFFER4_WEBGL = 0x8829;
+
+  static const int DRAW_BUFFER5 = 0x882A;
+
+  static const int DRAW_BUFFER5_WEBGL = 0x882A;
+
+  static const int DRAW_BUFFER6 = 0x882B;
+
+  static const int DRAW_BUFFER6_WEBGL = 0x882B;
+
+  static const int DRAW_BUFFER7 = 0x882C;
+
+  static const int DRAW_BUFFER7_WEBGL = 0x882C;
+
+  static const int DRAW_BUFFER8 = 0x882D;
+
+  static const int DRAW_BUFFER8_WEBGL = 0x882D;
+
+  static const int DRAW_BUFFER9 = 0x882E;
+
+  static const int DRAW_BUFFER9_WEBGL = 0x882E;
+
+  static const int DRAW_FRAMEBUFFER = 0x8CA9;
+
+  static const int DRAW_FRAMEBUFFER_BINDING = 0x8CA6;
+
+  static const int DST_ALPHA = 0x0304;
+
+  static const int DST_COLOR = 0x0306;
+
+  static const int DYNAMIC_COPY = 0x88EA;
+
+  static const int DYNAMIC_DRAW = 0x88E8;
+
+  static const int DYNAMIC_READ = 0x88E9;
+
+  static const int ELEMENT_ARRAY_BUFFER = 0x8893;
+
+  static const int ELEMENT_ARRAY_BUFFER_BINDING = 0x8895;
+
+  static const int EQUAL = 0x0202;
+
+  static const int FASTEST = 0x1101;
+
+  static const int FLOAT = 0x1406;
+
+  static const int FLOAT_32_UNSIGNED_INT_24_8_REV = 0x8DAD;
+
+  static const int FLOAT_MAT2 = 0x8B5A;
+
+  static const int FLOAT_MAT2x3 = 0x8B65;
+
+  static const int FLOAT_MAT2x4 = 0x8B66;
+
+  static const int FLOAT_MAT3 = 0x8B5B;
+
+  static const int FLOAT_MAT3x2 = 0x8B67;
+
+  static const int FLOAT_MAT3x4 = 0x8B68;
+
+  static const int FLOAT_MAT4 = 0x8B5C;
+
+  static const int FLOAT_MAT4x2 = 0x8B69;
+
+  static const int FLOAT_MAT4x3 = 0x8B6A;
+
+  static const int FLOAT_VEC2 = 0x8B50;
+
+  static const int FLOAT_VEC3 = 0x8B51;
+
+  static const int FLOAT_VEC4 = 0x8B52;
+
+  static const int FRAGMENT_SHADER = 0x8B30;
+
+  static const int FRAGMENT_SHADER_DERIVATIVE_HINT = 0x8B8B;
+
+  static const int FRAMEBUFFER = 0x8D40;
+
+  static const int FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE = 0x8215;
+
+  static const int FRAMEBUFFER_ATTACHMENT_BLUE_SIZE = 0x8214;
+
+  static const int FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING = 0x8210;
+
+  static const int FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE = 0x8211;
+
+  static const int FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE = 0x8216;
+
+  static const int FRAMEBUFFER_ATTACHMENT_GREEN_SIZE = 0x8213;
+
+  static const int FRAMEBUFFER_ATTACHMENT_OBJECT_NAME = 0x8CD1;
+
+  static const int FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE = 0x8CD0;
+
+  static const int FRAMEBUFFER_ATTACHMENT_RED_SIZE = 0x8212;
+
+  static const int FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE = 0x8217;
+
+  static const int FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE = 0x8CD3;
+
+  static const int FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER = 0x8CD4;
+
+  static const int FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL = 0x8CD2;
+
+  static const int FRAMEBUFFER_BINDING = 0x8CA6;
+
+  static const int FRAMEBUFFER_COMPLETE = 0x8CD5;
+
+  static const int FRAMEBUFFER_DEFAULT = 0x8218;
+
+  static const int FRAMEBUFFER_INCOMPLETE_ATTACHMENT = 0x8CD6;
+
+  static const int FRAMEBUFFER_INCOMPLETE_DIMENSIONS = 0x8CD9;
+
+  static const int FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT = 0x8CD7;
+
+  static const int FRAMEBUFFER_INCOMPLETE_MULTISAMPLE = 0x8D56;
+
+  static const int FRAMEBUFFER_UNSUPPORTED = 0x8CDD;
+
+  static const int FRONT = 0x0404;
+
+  static const int FRONT_AND_BACK = 0x0408;
+
+  static const int FRONT_FACE = 0x0B46;
+
+  static const int FUNC_ADD = 0x8006;
+
+  static const int FUNC_REVERSE_SUBTRACT = 0x800B;
+
+  static const int FUNC_SUBTRACT = 0x800A;
+
+  static const int GENERATE_MIPMAP_HINT = 0x8192;
+
+  static const int GEQUAL = 0x0206;
+
+  static const int GREATER = 0x0204;
+
+  static const int GREEN_BITS = 0x0D53;
+
+  static const int HALF_FLOAT = 0x140B;
+
+  static const int HIGH_FLOAT = 0x8DF2;
+
+  static const int HIGH_INT = 0x8DF5;
+
+  static const int IMPLEMENTATION_COLOR_READ_FORMAT = 0x8B9B;
+
+  static const int IMPLEMENTATION_COLOR_READ_TYPE = 0x8B9A;
+
+  static const int INCR = 0x1E02;
+
+  static const int INCR_WRAP = 0x8507;
+
+  static const int INT = 0x1404;
+
+  static const int INTERLEAVED_ATTRIBS = 0x8C8C;
+
+  static const int INT_2_10_10_10_REV = 0x8D9F;
+
+  static const int INT_SAMPLER_2D = 0x8DCA;
+
+  static const int INT_SAMPLER_2D_ARRAY = 0x8DCF;
+
+  static const int INT_SAMPLER_3D = 0x8DCB;
+
+  static const int INT_SAMPLER_CUBE = 0x8DCC;
+
+  static const int INT_VEC2 = 0x8B53;
+
+  static const int INT_VEC3 = 0x8B54;
+
+  static const int INT_VEC4 = 0x8B55;
+
+  static const int INVALID_ENUM = 0x0500;
+
+  static const int INVALID_FRAMEBUFFER_OPERATION = 0x0506;
+
+  static const int INVALID_INDEX = 0xFFFFFFFF;
+
+  static const int INVALID_OPERATION = 0x0502;
+
+  static const int INVALID_VALUE = 0x0501;
+
+  static const int INVERT = 0x150A;
+
+  static const int KEEP = 0x1E00;
+
+  static const int LEQUAL = 0x0203;
+
+  static const int LESS = 0x0201;
+
+  static const int LINEAR = 0x2601;
+
+  static const int LINEAR_MIPMAP_LINEAR = 0x2703;
+
+  static const int LINEAR_MIPMAP_NEAREST = 0x2701;
+
+  static const int LINES = 0x0001;
+
+  static const int LINE_LOOP = 0x0002;
+
+  static const int LINE_STRIP = 0x0003;
+
+  static const int LINE_WIDTH = 0x0B21;
+
+  static const int LINK_STATUS = 0x8B82;
+
+  static const int LOW_FLOAT = 0x8DF0;
+
+  static const int LOW_INT = 0x8DF3;
+
+  static const int LUMINANCE = 0x1909;
+
+  static const int LUMINANCE_ALPHA = 0x190A;
+
+  static const int MAX = 0x8008;
+
+  static const int MAX_3D_TEXTURE_SIZE = 0x8073;
+
+  static const int MAX_ARRAY_TEXTURE_LAYERS = 0x88FF;
+
+  static const int MAX_CLIENT_WAIT_TIMEOUT_WEBGL = 0x9247;
+
+  static const int MAX_COLOR_ATTACHMENTS = 0x8CDF;
+
+  static const int MAX_COLOR_ATTACHMENTS_WEBGL = 0x8CDF;
+
+  static const int MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS = 0x8A33;
+
+  static const int MAX_COMBINED_TEXTURE_IMAGE_UNITS = 0x8B4D;
+
+  static const int MAX_COMBINED_UNIFORM_BLOCKS = 0x8A2E;
+
+  static const int MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS = 0x8A31;
+
+  static const int MAX_CUBE_MAP_TEXTURE_SIZE = 0x851C;
+
+  static const int MAX_DRAW_BUFFERS = 0x8824;
+
+  static const int MAX_DRAW_BUFFERS_WEBGL = 0x8824;
+
+  static const int MAX_ELEMENTS_INDICES = 0x80E9;
+
+  static const int MAX_ELEMENTS_VERTICES = 0x80E8;
+
+  static const int MAX_ELEMENT_INDEX = 0x8D6B;
+
+  static const int MAX_FRAGMENT_INPUT_COMPONENTS = 0x9125;
+
+  static const int MAX_FRAGMENT_UNIFORM_BLOCKS = 0x8A2D;
+
+  static const int MAX_FRAGMENT_UNIFORM_COMPONENTS = 0x8B49;
+
+  static const int MAX_FRAGMENT_UNIFORM_VECTORS = 0x8DFD;
+
+  static const int MAX_PROGRAM_TEXEL_OFFSET = 0x8905;
+
+  static const int MAX_RENDERBUFFER_SIZE = 0x84E8;
+
+  static const int MAX_SAMPLES = 0x8D57;
+
+  static const int MAX_SERVER_WAIT_TIMEOUT = 0x9111;
+
+  static const int MAX_TEXTURE_IMAGE_UNITS = 0x8872;
+
+  static const int MAX_TEXTURE_LOD_BIAS = 0x84FD;
+
+  static const int MAX_TEXTURE_SIZE = 0x0D33;
+
+  static const int MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS = 0x8C8A;
+
+  static const int MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS = 0x8C8B;
+
+  static const int MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS = 0x8C80;
+
+  static const int MAX_UNIFORM_BLOCK_SIZE = 0x8A30;
+
+  static const int MAX_UNIFORM_BUFFER_BINDINGS = 0x8A2F;
+
+  static const int MAX_VARYING_COMPONENTS = 0x8B4B;
+
+  static const int MAX_VARYING_VECTORS = 0x8DFC;
+
+  static const int MAX_VERTEX_ATTRIBS = 0x8869;
+
+  static const int MAX_VERTEX_OUTPUT_COMPONENTS = 0x9122;
+
+  static const int MAX_VERTEX_TEXTURE_IMAGE_UNITS = 0x8B4C;
+
+  static const int MAX_VERTEX_UNIFORM_BLOCKS = 0x8A2B;
+
+  static const int MAX_VERTEX_UNIFORM_COMPONENTS = 0x8B4A;
+
+  static const int MAX_VERTEX_UNIFORM_VECTORS = 0x8DFB;
+
+  static const int MAX_VIEWPORT_DIMS = 0x0D3A;
+
+  static const int MEDIUM_FLOAT = 0x8DF1;
+
+  static const int MEDIUM_INT = 0x8DF4;
+
+  static const int MIN = 0x8007;
+
+  static const int MIN_PROGRAM_TEXEL_OFFSET = 0x8904;
+
+  static const int MIRRORED_REPEAT = 0x8370;
+
+  static const int NEAREST = 0x2600;
+
+  static const int NEAREST_MIPMAP_LINEAR = 0x2702;
+
+  static const int NEAREST_MIPMAP_NEAREST = 0x2700;
+
+  static const int NEVER = 0x0200;
+
+  static const int NICEST = 0x1102;
+
+  static const int NONE = 0;
+
+  static const int NOTEQUAL = 0x0205;
+
+  static const int NO_ERROR = 0;
+
+  static const int OBJECT_TYPE = 0x9112;
+
+  static const int ONE = 1;
+
+  static const int ONE_MINUS_CONSTANT_ALPHA = 0x8004;
+
+  static const int ONE_MINUS_CONSTANT_COLOR = 0x8002;
+
+  static const int ONE_MINUS_DST_ALPHA = 0x0305;
+
+  static const int ONE_MINUS_DST_COLOR = 0x0307;
+
+  static const int ONE_MINUS_SRC_ALPHA = 0x0303;
+
+  static const int ONE_MINUS_SRC_COLOR = 0x0301;
+
+  static const int OUT_OF_MEMORY = 0x0505;
+
+  static const int PACK_ALIGNMENT = 0x0D05;
+
+  static const int PACK_ROW_LENGTH = 0x0D02;
+
+  static const int PACK_SKIP_PIXELS = 0x0D04;
+
+  static const int PACK_SKIP_ROWS = 0x0D03;
+
+  static const int PIXEL_PACK_BUFFER = 0x88EB;
+
+  static const int PIXEL_PACK_BUFFER_BINDING = 0x88ED;
+
+  static const int PIXEL_UNPACK_BUFFER = 0x88EC;
+
+  static const int PIXEL_UNPACK_BUFFER_BINDING = 0x88EF;
+
+  static const int POINTS = 0x0000;
+
+  static const int POLYGON_OFFSET_FACTOR = 0x8038;
+
+  static const int POLYGON_OFFSET_FILL = 0x8037;
+
+  static const int POLYGON_OFFSET_UNITS = 0x2A00;
+
+  static const int QUERY_RESULT = 0x8866;
+
+  static const int QUERY_RESULT_AVAILABLE = 0x8867;
+
+  static const int R11F_G11F_B10F = 0x8C3A;
+
+  static const int R16F = 0x822D;
+
+  static const int R16I = 0x8233;
+
+  static const int R16UI = 0x8234;
+
+  static const int R32F = 0x822E;
+
+  static const int R32I = 0x8235;
+
+  static const int R32UI = 0x8236;
+
+  static const int R8 = 0x8229;
+
+  static const int R8I = 0x8231;
+
+  static const int R8UI = 0x8232;
+
+  static const int R8_SNORM = 0x8F94;
+
+  static const int RASTERIZER_DISCARD = 0x8C89;
+
+  static const int READ_BUFFER = 0x0C02;
+
+  static const int READ_FRAMEBUFFER = 0x8CA8;
+
+  static const int READ_FRAMEBUFFER_BINDING = 0x8CAA;
+
+  static const int RED = 0x1903;
+
+  static const int RED_BITS = 0x0D52;
+
+  static const int RED_INTEGER = 0x8D94;
+
+  static const int RENDERBUFFER = 0x8D41;
+
+  static const int RENDERBUFFER_ALPHA_SIZE = 0x8D53;
+
+  static const int RENDERBUFFER_BINDING = 0x8CA7;
+
+  static const int RENDERBUFFER_BLUE_SIZE = 0x8D52;
+
+  static const int RENDERBUFFER_DEPTH_SIZE = 0x8D54;
+
+  static const int RENDERBUFFER_GREEN_SIZE = 0x8D51;
+
+  static const int RENDERBUFFER_HEIGHT = 0x8D43;
+
+  static const int RENDERBUFFER_INTERNAL_FORMAT = 0x8D44;
+
+  static const int RENDERBUFFER_RED_SIZE = 0x8D50;
+
+  static const int RENDERBUFFER_SAMPLES = 0x8CAB;
+
+  static const int RENDERBUFFER_STENCIL_SIZE = 0x8D55;
+
+  static const int RENDERBUFFER_WIDTH = 0x8D42;
+
+  static const int RENDERER = 0x1F01;
+
+  static const int REPEAT = 0x2901;
+
+  static const int REPLACE = 0x1E01;
+
+  static const int RG = 0x8227;
+
+  static const int RG16F = 0x822F;
+
+  static const int RG16I = 0x8239;
+
+  static const int RG16UI = 0x823A;
+
+  static const int RG32F = 0x8230;
+
+  static const int RG32I = 0x823B;
+
+  static const int RG32UI = 0x823C;
+
+  static const int RG8 = 0x822B;
+
+  static const int RG8I = 0x8237;
+
+  static const int RG8UI = 0x8238;
+
+  static const int RG8_SNORM = 0x8F95;
+
+  static const int RGB = 0x1907;
+
+  static const int RGB10_A2 = 0x8059;
+
+  static const int RGB10_A2UI = 0x906F;
+
+  static const int RGB16F = 0x881B;
+
+  static const int RGB16I = 0x8D89;
+
+  static const int RGB16UI = 0x8D77;
+
+  static const int RGB32F = 0x8815;
+
+  static const int RGB32I = 0x8D83;
+
+  static const int RGB32UI = 0x8D71;
+
+  static const int RGB565 = 0x8D62;
+
+  static const int RGB5_A1 = 0x8057;
+
+  static const int RGB8 = 0x8051;
+
+  static const int RGB8I = 0x8D8F;
+
+  static const int RGB8UI = 0x8D7D;
+
+  static const int RGB8_SNORM = 0x8F96;
+
+  static const int RGB9_E5 = 0x8C3D;
+
+  static const int RGBA = 0x1908;
+
+  static const int RGBA16F = 0x881A;
+
+  static const int RGBA16I = 0x8D88;
+
+  static const int RGBA16UI = 0x8D76;
+
+  static const int RGBA32F = 0x8814;
+
+  static const int RGBA32I = 0x8D82;
+
+  static const int RGBA32UI = 0x8D70;
+
+  static const int RGBA4 = 0x8056;
+
+  static const int RGBA8 = 0x8058;
+
+  static const int RGBA8I = 0x8D8E;
+
+  static const int RGBA8UI = 0x8D7C;
+
+  static const int RGBA8_SNORM = 0x8F97;
+
+  static const int RGBA_INTEGER = 0x8D99;
+
+  static const int RGB_INTEGER = 0x8D98;
+
+  static const int RG_INTEGER = 0x8228;
+
+  static const int SAMPLER_2D = 0x8B5E;
+
+  static const int SAMPLER_2D_ARRAY = 0x8DC1;
+
+  static const int SAMPLER_2D_ARRAY_SHADOW = 0x8DC4;
+
+  static const int SAMPLER_2D_SHADOW = 0x8B62;
+
+  static const int SAMPLER_3D = 0x8B5F;
+
+  static const int SAMPLER_BINDING = 0x8919;
+
+  static const int SAMPLER_CUBE = 0x8B60;
+
+  static const int SAMPLER_CUBE_SHADOW = 0x8DC5;
+
+  static const int SAMPLES = 0x80A9;
+
+  static const int SAMPLE_ALPHA_TO_COVERAGE = 0x809E;
+
+  static const int SAMPLE_BUFFERS = 0x80A8;
+
+  static const int SAMPLE_COVERAGE = 0x80A0;
+
+  static const int SAMPLE_COVERAGE_INVERT = 0x80AB;
+
+  static const int SAMPLE_COVERAGE_VALUE = 0x80AA;
+
+  static const int SCISSOR_BOX = 0x0C10;
+
+  static const int SCISSOR_TEST = 0x0C11;
+
+  static const int SEPARATE_ATTRIBS = 0x8C8D;
+
+  static const int SHADER_TYPE = 0x8B4F;
+
+  static const int SHADING_LANGUAGE_VERSION = 0x8B8C;
+
+  static const int SHORT = 0x1402;
+
+  static const int SIGNALED = 0x9119;
+
+  static const int SIGNED_NORMALIZED = 0x8F9C;
+
+  static const int SRC_ALPHA = 0x0302;
+
+  static const int SRC_ALPHA_SATURATE = 0x0308;
+
+  static const int SRC_COLOR = 0x0300;
+
+  static const int SRGB = 0x8C40;
+
+  static const int SRGB8 = 0x8C41;
+
+  static const int SRGB8_ALPHA8 = 0x8C43;
+
+  static const int STATIC_COPY = 0x88E6;
+
+  static const int STATIC_DRAW = 0x88E4;
+
+  static const int STATIC_READ = 0x88E5;
+
+  static const int STENCIL = 0x1802;
+
+  static const int STENCIL_ATTACHMENT = 0x8D20;
+
+  static const int STENCIL_BACK_FAIL = 0x8801;
+
+  static const int STENCIL_BACK_FUNC = 0x8800;
+
+  static const int STENCIL_BACK_PASS_DEPTH_FAIL = 0x8802;
+
+  static const int STENCIL_BACK_PASS_DEPTH_PASS = 0x8803;
+
+  static const int STENCIL_BACK_REF = 0x8CA3;
+
+  static const int STENCIL_BACK_VALUE_MASK = 0x8CA4;
+
+  static const int STENCIL_BACK_WRITEMASK = 0x8CA5;
+
+  static const int STENCIL_BITS = 0x0D57;
+
+  static const int STENCIL_BUFFER_BIT = 0x00000400;
+
+  static const int STENCIL_CLEAR_VALUE = 0x0B91;
+
+  static const int STENCIL_FAIL = 0x0B94;
+
+  static const int STENCIL_FUNC = 0x0B92;
+
+  static const int STENCIL_INDEX8 = 0x8D48;
+
+  static const int STENCIL_PASS_DEPTH_FAIL = 0x0B95;
+
+  static const int STENCIL_PASS_DEPTH_PASS = 0x0B96;
+
+  static const int STENCIL_REF = 0x0B97;
+
+  static const int STENCIL_TEST = 0x0B90;
+
+  static const int STENCIL_VALUE_MASK = 0x0B93;
+
+  static const int STENCIL_WRITEMASK = 0x0B98;
+
+  static const int STREAM_COPY = 0x88E2;
+
+  static const int STREAM_DRAW = 0x88E0;
+
+  static const int STREAM_READ = 0x88E1;
+
+  static const int SUBPIXEL_BITS = 0x0D50;
+
+  static const int SYNC_CONDITION = 0x9113;
+
+  static const int SYNC_FENCE = 0x9116;
+
+  static const int SYNC_FLAGS = 0x9115;
+
+  static const int SYNC_FLUSH_COMMANDS_BIT = 0x00000001;
+
+  static const int SYNC_GPU_COMMANDS_COMPLETE = 0x9117;
+
+  static const int SYNC_STATUS = 0x9114;
+
+  static const int TEXTURE = 0x1702;
+
+  static const int TEXTURE0 = 0x84C0;
+
+  static const int TEXTURE1 = 0x84C1;
+
+  static const int TEXTURE10 = 0x84CA;
+
+  static const int TEXTURE11 = 0x84CB;
+
+  static const int TEXTURE12 = 0x84CC;
+
+  static const int TEXTURE13 = 0x84CD;
+
+  static const int TEXTURE14 = 0x84CE;
+
+  static const int TEXTURE15 = 0x84CF;
+
+  static const int TEXTURE16 = 0x84D0;
+
+  static const int TEXTURE17 = 0x84D1;
+
+  static const int TEXTURE18 = 0x84D2;
+
+  static const int TEXTURE19 = 0x84D3;
+
+  static const int TEXTURE2 = 0x84C2;
+
+  static const int TEXTURE20 = 0x84D4;
+
+  static const int TEXTURE21 = 0x84D5;
+
+  static const int TEXTURE22 = 0x84D6;
+
+  static const int TEXTURE23 = 0x84D7;
+
+  static const int TEXTURE24 = 0x84D8;
+
+  static const int TEXTURE25 = 0x84D9;
+
+  static const int TEXTURE26 = 0x84DA;
+
+  static const int TEXTURE27 = 0x84DB;
+
+  static const int TEXTURE28 = 0x84DC;
+
+  static const int TEXTURE29 = 0x84DD;
+
+  static const int TEXTURE3 = 0x84C3;
+
+  static const int TEXTURE30 = 0x84DE;
+
+  static const int TEXTURE31 = 0x84DF;
+
+  static const int TEXTURE4 = 0x84C4;
+
+  static const int TEXTURE5 = 0x84C5;
+
+  static const int TEXTURE6 = 0x84C6;
+
+  static const int TEXTURE7 = 0x84C7;
+
+  static const int TEXTURE8 = 0x84C8;
+
+  static const int TEXTURE9 = 0x84C9;
+
+  static const int TEXTURE_2D = 0x0DE1;
+
+  static const int TEXTURE_2D_ARRAY = 0x8C1A;
+
+  static const int TEXTURE_3D = 0x806F;
+
+  static const int TEXTURE_BASE_LEVEL = 0x813C;
+
+  static const int TEXTURE_BINDING_2D = 0x8069;
+
+  static const int TEXTURE_BINDING_2D_ARRAY = 0x8C1D;
+
+  static const int TEXTURE_BINDING_3D = 0x806A;
+
+  static const int TEXTURE_BINDING_CUBE_MAP = 0x8514;
+
+  static const int TEXTURE_COMPARE_FUNC = 0x884D;
+
+  static const int TEXTURE_COMPARE_MODE = 0x884C;
+
+  static const int TEXTURE_CUBE_MAP = 0x8513;
+
+  static const int TEXTURE_CUBE_MAP_NEGATIVE_X = 0x8516;
+
+  static const int TEXTURE_CUBE_MAP_NEGATIVE_Y = 0x8518;
+
+  static const int TEXTURE_CUBE_MAP_NEGATIVE_Z = 0x851A;
+
+  static const int TEXTURE_CUBE_MAP_POSITIVE_X = 0x8515;
+
+  static const int TEXTURE_CUBE_MAP_POSITIVE_Y = 0x8517;
+
+  static const int TEXTURE_CUBE_MAP_POSITIVE_Z = 0x8519;
+
+  static const int TEXTURE_IMMUTABLE_FORMAT = 0x912F;
+
+  static const int TEXTURE_IMMUTABLE_LEVELS = 0x82DF;
+
+  static const int TEXTURE_MAG_FILTER = 0x2800;
+
+  static const int TEXTURE_MAX_LEVEL = 0x813D;
+
+  static const int TEXTURE_MAX_LOD = 0x813B;
+
+  static const int TEXTURE_MIN_FILTER = 0x2801;
+
+  static const int TEXTURE_MIN_LOD = 0x813A;
+
+  static const int TEXTURE_WRAP_R = 0x8072;
+
+  static const int TEXTURE_WRAP_S = 0x2802;
+
+  static const int TEXTURE_WRAP_T = 0x2803;
+
+  static const int TIMEOUT_EXPIRED = 0x911B;
+
+  static const int TIMEOUT_IGNORED = -1;
+
+  static const int TRANSFORM_FEEDBACK = 0x8E22;
+
+  static const int TRANSFORM_FEEDBACK_ACTIVE = 0x8E24;
+
+  static const int TRANSFORM_FEEDBACK_BINDING = 0x8E25;
+
+  static const int TRANSFORM_FEEDBACK_BUFFER = 0x8C8E;
+
+  static const int TRANSFORM_FEEDBACK_BUFFER_BINDING = 0x8C8F;
+
+  static const int TRANSFORM_FEEDBACK_BUFFER_MODE = 0x8C7F;
+
+  static const int TRANSFORM_FEEDBACK_BUFFER_SIZE = 0x8C85;
+
+  static const int TRANSFORM_FEEDBACK_BUFFER_START = 0x8C84;
+
+  static const int TRANSFORM_FEEDBACK_PAUSED = 0x8E23;
+
+  static const int TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN = 0x8C88;
+
+  static const int TRANSFORM_FEEDBACK_VARYINGS = 0x8C83;
+
+  static const int TRIANGLES = 0x0004;
+
+  static const int TRIANGLE_FAN = 0x0006;
+
+  static const int TRIANGLE_STRIP = 0x0005;
+
+  static const int UNIFORM_ARRAY_STRIDE = 0x8A3C;
+
+  static const int UNIFORM_BLOCK_ACTIVE_UNIFORMS = 0x8A42;
+
+  static const int UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES = 0x8A43;
+
+  static const int UNIFORM_BLOCK_BINDING = 0x8A3F;
+
+  static const int UNIFORM_BLOCK_DATA_SIZE = 0x8A40;
+
+  static const int UNIFORM_BLOCK_INDEX = 0x8A3A;
+
+  static const int UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER = 0x8A46;
+
+  static const int UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER = 0x8A44;
+
+  static const int UNIFORM_BUFFER = 0x8A11;
+
+  static const int UNIFORM_BUFFER_BINDING = 0x8A28;
+
+  static const int UNIFORM_BUFFER_OFFSET_ALIGNMENT = 0x8A34;
+
+  static const int UNIFORM_BUFFER_SIZE = 0x8A2A;
+
+  static const int UNIFORM_BUFFER_START = 0x8A29;
+
+  static const int UNIFORM_IS_ROW_MAJOR = 0x8A3E;
+
+  static const int UNIFORM_MATRIX_STRIDE = 0x8A3D;
+
+  static const int UNIFORM_OFFSET = 0x8A3B;
+
+  static const int UNIFORM_SIZE = 0x8A38;
+
+  static const int UNIFORM_TYPE = 0x8A37;
+
+  static const int UNPACK_ALIGNMENT = 0x0CF5;
+
+  static const int UNPACK_COLORSPACE_CONVERSION_WEBGL = 0x9243;
+
+  static const int UNPACK_FLIP_Y_WEBGL = 0x9240;
+
+  static const int UNPACK_IMAGE_HEIGHT = 0x806E;
+
+  static const int UNPACK_PREMULTIPLY_ALPHA_WEBGL = 0x9241;
+
+  static const int UNPACK_ROW_LENGTH = 0x0CF2;
+
+  static const int UNPACK_SKIP_IMAGES = 0x806D;
+
+  static const int UNPACK_SKIP_PIXELS = 0x0CF4;
+
+  static const int UNPACK_SKIP_ROWS = 0x0CF3;
+
+  static const int UNSIGNALED = 0x9118;
+
+  static const int UNSIGNED_BYTE = 0x1401;
+
+  static const int UNSIGNED_INT = 0x1405;
+
+  static const int UNSIGNED_INT_10F_11F_11F_REV = 0x8C3B;
+
+  static const int UNSIGNED_INT_24_8 = 0x84FA;
+
+  static const int UNSIGNED_INT_2_10_10_10_REV = 0x8368;
+
+  static const int UNSIGNED_INT_5_9_9_9_REV = 0x8C3E;
+
+  static const int UNSIGNED_INT_SAMPLER_2D = 0x8DD2;
+
+  static const int UNSIGNED_INT_SAMPLER_2D_ARRAY = 0x8DD7;
+
+  static const int UNSIGNED_INT_SAMPLER_3D = 0x8DD3;
+
+  static const int UNSIGNED_INT_SAMPLER_CUBE = 0x8DD4;
+
+  static const int UNSIGNED_INT_VEC2 = 0x8DC6;
+
+  static const int UNSIGNED_INT_VEC3 = 0x8DC7;
+
+  static const int UNSIGNED_INT_VEC4 = 0x8DC8;
+
+  static const int UNSIGNED_NORMALIZED = 0x8C17;
+
+  static const int UNSIGNED_SHORT = 0x1403;
+
+  static const int UNSIGNED_SHORT_4_4_4_4 = 0x8033;
+
+  static const int UNSIGNED_SHORT_5_5_5_1 = 0x8034;
+
+  static const int UNSIGNED_SHORT_5_6_5 = 0x8363;
+
+  static const int VALIDATE_STATUS = 0x8B83;
+
+  static const int VENDOR = 0x1F00;
+
+  static const int VERSION = 0x1F02;
+
+  static const int VERTEX_ARRAY_BINDING = 0x85B5;
+
+  static const int VERTEX_ATTRIB_ARRAY_BUFFER_BINDING = 0x889F;
+
+  static const int VERTEX_ATTRIB_ARRAY_DIVISOR = 0x88FE;
+
+  static const int VERTEX_ATTRIB_ARRAY_ENABLED = 0x8622;
+
+  static const int VERTEX_ATTRIB_ARRAY_INTEGER = 0x88FD;
+
+  static const int VERTEX_ATTRIB_ARRAY_NORMALIZED = 0x886A;
+
+  static const int VERTEX_ATTRIB_ARRAY_POINTER = 0x8645;
+
+  static const int VERTEX_ATTRIB_ARRAY_SIZE = 0x8623;
+
+  static const int VERTEX_ATTRIB_ARRAY_STRIDE = 0x8624;
+
+  static const int VERTEX_ATTRIB_ARRAY_TYPE = 0x8625;
+
+  static const int VERTEX_SHADER = 0x8B31;
+
+  static const int VIEWPORT = 0x0BA2;
+
+  static const int WAIT_FAILED = 0x911D;
+
+  static const int ZERO = 0;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("WebGL2RenderingContextBase")
+abstract class _WebGL2RenderingContextBase extends Interceptor
+    implements _WebGLRenderingContextBase {
+  // To suppress missing implicit constructor warnings.
+  factory _WebGL2RenderingContextBase._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  // From WebGLRenderingContextBase
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+abstract class _WebGLRenderingContextBase extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory _WebGLRenderingContextBase._() {
+    throw new UnsupportedError("Not supported");
+  }
+}
diff --git a/sdk_nnbd/lib/web_sql/dart2js/web_sql_dart2js.dart b/sdk_nnbd/lib/web_sql/dart2js/web_sql_dart2js.dart
new file mode 100644
index 0000000..0f703f9
--- /dev/null
+++ b/sdk_nnbd/lib/web_sql/dart2js/web_sql_dart2js.dart
@@ -0,0 +1,306 @@
+/**
+ * An API for storing data in the browser that can be queried with SQL.
+ *
+ * **Caution:** this specification is no longer actively maintained by the Web
+ * Applications Working Group and may be removed at any time.
+ * See [the W3C Web SQL Database specification](http://www.w3.org/TR/webdatabase/)
+ * for more information.
+ *
+ * The [dart:indexed_db] APIs is a recommended alternatives.
+ *
+ * {@category Web}
+ */
+library dart.dom.web_sql;
+
+import 'dart:async';
+import 'dart:collection' hide LinkedList, LinkedListEntry;
+import 'dart:_internal' show FixedLengthListMixin;
+import 'dart:html';
+import 'dart:html_common';
+import 'dart:_foreign_helper' show JS;
+import 'dart:_interceptors' show Interceptor;
+// DO NOT EDIT - unless you are editing documentation as per:
+// https://code.google.com/p/dart/wiki/ContributingHTMLDocumentation
+// Auto-generated dart:audio library.
+
+import 'dart:_js_helper'
+    show
+        applyExtension,
+        convertDartClosureToJS,
+        Creates,
+        JSName,
+        Native,
+        JavaScriptIndexingBehavior;
+
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+typedef void SqlStatementCallback(
+    SqlTransaction transaction, SqlResultSet resultSet);
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+typedef void SqlStatementErrorCallback(
+    SqlTransaction transaction, SqlError error);
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+typedef void SqlTransactionCallback(SqlTransaction transaction);
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+typedef void SqlTransactionErrorCallback(SqlError error);
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.SAFARI)
+@Native("Database")
+class SqlDatabase extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory SqlDatabase._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  /// Checks if this type is supported on the current platform.
+  static bool get supported => JS('bool', '!!(window.openDatabase)');
+
+  final String version;
+
+  @JSName('changeVersion')
+  /**
+   * Atomically update the database version to [newVersion], asynchronously
+   * running [callback] on the [SqlTransaction] representing this
+   * [changeVersion] transaction.
+   *
+   * If [callback] runs successfully, then [successCallback] is called.
+   * Otherwise, [errorCallback] is called.
+   *
+   * [oldVersion] should match the database's current [version] exactly.
+   *
+   * See also:
+   *
+   * * [Database.changeVersion](http://www.w3.org/TR/webdatabase/#dom-database-changeversion) from W3C.
+   */
+  void _changeVersion(String oldVersion, String newVersion,
+      [SqlTransactionCallback callback,
+      SqlTransactionErrorCallback errorCallback,
+      VoidCallback successCallback]) native;
+
+  @JSName('changeVersion')
+  /**
+   * Atomically update the database version to [newVersion], asynchronously
+   * running [callback] on the [SqlTransaction] representing this
+   * [changeVersion] transaction.
+   *
+   * If [callback] runs successfully, then [successCallback] is called.
+   * Otherwise, [errorCallback] is called.
+   *
+   * [oldVersion] should match the database's current [version] exactly.
+   *
+   * See also:
+   *
+   * * [Database.changeVersion](http://www.w3.org/TR/webdatabase/#dom-database-changeversion) from W3C.
+   */
+  Future<SqlTransaction> changeVersion(String oldVersion, String newVersion) {
+    var completer = new Completer<SqlTransaction>();
+    _changeVersion(oldVersion, newVersion, (value) {
+      completer.complete(value);
+    }, (error) {
+      completer.completeError(error);
+    });
+    return completer.future;
+  }
+
+  @JSName('readTransaction')
+  void _readTransaction(SqlTransactionCallback callback,
+      [SqlTransactionErrorCallback errorCallback,
+      VoidCallback successCallback]) native;
+
+  @JSName('readTransaction')
+  Future<SqlTransaction> readTransaction() {
+    var completer = new Completer<SqlTransaction>();
+    _readTransaction((value) {
+      completer.complete(value);
+    }, (error) {
+      completer.completeError(error);
+    });
+    return completer.future;
+  }
+
+  void transaction(SqlTransactionCallback callback,
+      [SqlTransactionErrorCallback errorCallback,
+      VoidCallback successCallback]) native;
+
+  @JSName('transaction')
+  Future<SqlTransaction> transaction_future() {
+    var completer = new Completer<SqlTransaction>();
+    transaction((value) {
+      applyExtension('SQLTransaction', value);
+      completer.complete(value);
+    }, (error) {
+      completer.completeError(error);
+    });
+    return completer.future;
+  }
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("SQLError")
+class SqlError extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory SqlError._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  static const int CONSTRAINT_ERR = 6;
+
+  static const int DATABASE_ERR = 1;
+
+  static const int QUOTA_ERR = 4;
+
+  static const int SYNTAX_ERR = 5;
+
+  static const int TIMEOUT_ERR = 7;
+
+  static const int TOO_LARGE_ERR = 3;
+
+  static const int UNKNOWN_ERR = 0;
+
+  static const int VERSION_ERR = 2;
+
+  final int code;
+
+  final String message;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("SQLResultSet")
+class SqlResultSet extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory SqlResultSet._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  final int insertId;
+
+  final SqlResultSetRowList rows;
+
+  final int rowsAffected;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("SQLResultSetRowList")
+class SqlResultSetRowList extends Interceptor
+    with ListMixin<Map>, ImmutableListMixin<Map>
+    implements List<Map> {
+  // To suppress missing implicit constructor warnings.
+  factory SqlResultSetRowList._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  int get length => JS("int", "#.length", this);
+
+  Map operator [](int index) {
+    if (JS("bool", "# >>> 0 !== # || # >= #", index, index, index, length))
+      throw new RangeError.index(index, this);
+    return this.item(index);
+  }
+
+  void operator []=(int index, Map value) {
+    throw new UnsupportedError("Cannot assign element of immutable List.");
+  }
+  // -- start List<Map> mixins.
+  // Map is the element type.
+
+  set length(int value) {
+    throw new UnsupportedError("Cannot resize immutable List.");
+  }
+
+  Map get first {
+    if (this.length > 0) {
+      return JS('Map', '#[0]', this);
+    }
+    throw new StateError("No elements");
+  }
+
+  Map get last {
+    int len = this.length;
+    if (len > 0) {
+      return JS('Map', '#[#]', this, len - 1);
+    }
+    throw new StateError("No elements");
+  }
+
+  Map get single {
+    int len = this.length;
+    if (len == 1) {
+      return JS('Map', '#[0]', this);
+    }
+    if (len == 0) throw new StateError("No elements");
+    throw new StateError("More than one element");
+  }
+
+  Map elementAt(int index) => this[index];
+  // -- end List<Map> mixins.
+
+  Map item(int index) {
+    return convertNativeToDart_Dictionary(_item_1(index));
+  }
+
+  @JSName('item')
+  _item_1(index) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.SAFARI)
+// http://www.w3.org/TR/webdatabase/#sqltransaction
+@deprecated // deprecated
+@Native("SQLTransaction")
+class SqlTransaction extends Interceptor {
+  // To suppress missing implicit constructor warnings.
+  factory SqlTransaction._() {
+    throw new UnsupportedError("Not supported");
+  }
+
+  @JSName('executeSql')
+  void _executeSql(String sqlStatement,
+      [List arguments,
+      SqlStatementCallback callback,
+      SqlStatementErrorCallback errorCallback]) native;
+
+  @JSName('executeSql')
+  Future<SqlResultSet> executeSql(String sqlStatement, [List arguments]) {
+    var completer = new Completer<SqlResultSet>();
+    _executeSql(sqlStatement, arguments, (transaction, resultSet) {
+      applyExtension('SQLResultSet', resultSet);
+      applyExtension('SQLResultSetRowList', resultSet.rows);
+      completer.complete(resultSet);
+    }, (transaction, error) {
+      completer.completeError(error);
+    });
+    return completer.future;
+  }
+}
diff --git a/tests/compiler/dart2js_extra/38005_test.dart b/tests/compiler/dart2js_extra/38005_test.dart
new file mode 100644
index 0000000..2789b31
--- /dev/null
+++ b/tests/compiler/dart2js_extra/38005_test.dart
@@ -0,0 +1,21 @@
+// 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:expect/expect.dart";
+
+class A {}
+
+int foo<T>() {
+  switch (T) {
+    case A:
+      return 42;
+    default:
+      return -1;
+  }
+}
+
+void main() {
+  Expect.equals(42, foo<A>());
+  Expect.equals(-1, foo<int>());
+}
diff --git a/tests/language_2/extension_methods/static_extension_getter_setter_conflicts_test.dart b/tests/language_2/extension_methods/static_extension_getter_setter_conflicts_test.dart
index 402ff2d..e1baee5 100644
--- a/tests/language_2/extension_methods/static_extension_getter_setter_conflicts_test.dart
+++ b/tests/language_2/extension_methods/static_extension_getter_setter_conflicts_test.dart
@@ -68,13 +68,13 @@
   c1a.m1;
 
   c1a.m1 = 0;
-  //  ^^^^^^
-  // [analyzer] COMPILE_TIME_ERROR.UNDEFINED_EXTENSION_SETTER
+  //  ^^
+  // [analyzer] STATIC_WARNING.ASSIGNMENT_TO_FINAL_LOCAL
   // [cfe] unspecified
 
   c1a.m2;
   //  ^^
-  // [analyzer] COMPILE_TIME_ERROR.UNDEFINED_EXTENSION_GETTER
+  // [analyzer] STATIC_TYPE_WARNING.UNDEFINED_GETTER
   // [cfe] unspecified
 
   c1a.m2 = 0;
@@ -87,7 +87,7 @@
   // [cfe] unspecified
 
   c1b.m1 = 0;
-  //  ^^^^^^
+  //  ^^
   // [analyzer] COMPILE_TIME_ERROR.AMBIGUOUS_EXTENSION_MEMBER_ACCESS
   // [cfe] unspecified
 
@@ -97,7 +97,7 @@
   // [cfe] unspecified
 
   c1b.m2 = 0;
-  //  ^^^^^^
+  //  ^^
   // [analyzer] COMPILE_TIME_ERROR.AMBIGUOUS_EXTENSION_MEMBER_ACCESS
   // [cfe] unspecified
 }
@@ -119,14 +119,14 @@
 
     this.m1;
     this.m1 = 0;
-    //   ^^^^^^
-    // [analyzer] COMPILE_TIME_ERROR.UNDEFINED_EXTENSION_SETTER
+    //   ^^
+    // [analyzer] STATIC_WARNING.ASSIGNMENT_TO_FINAL_NO_SETTER
     // [cfe] unspecified
 
     this.m2 = 0;
     this.m2;
     //   ^^
-    // [analyzer] COMPILE_TIME_ERROR.UNDEFINED_EXTENSION_GETTER
+    // [analyzer] STATIC_TYPE_WARNING.UNDEFINED_GETTER
     // [cfe] unspecified
 
     // Check that `this.mc` refers to `C2.mc`.
diff --git a/tests/language_2/language_2_analyzer.status b/tests/language_2/language_2_analyzer.status
index bb945c5..cddcbd3 100644
--- a/tests/language_2/language_2_analyzer.status
+++ b/tests/language_2/language_2_analyzer.status
@@ -7,7 +7,6 @@
 [ $compiler == dart2analyzer ]
 generic_no_such_method_dispatcher_simple_test: Skip # failing-by-design: This test is just for kernel
 large_class_declaration_test: Slow
-regress_23408_test: Skip # don't care about the static warning.
 vm/debug_break_enabled_vm_test: Skip
 vm/debug_break_vm_test/*: Skip
 vm/regress_27201_test: SkipByDesign # Loads bad library, so will always crash.
diff --git a/tests/language_2/map_literal3_test.dart b/tests/language_2/map_literal3_test.dart
index 36827f6..a5d054c 100644
--- a/tests/language_2/map_literal3_test.dart
+++ b/tests/language_2/map_literal3_test.dart
@@ -40,35 +40,20 @@
           "b": b,
         }["b"]);
 
-    // Make map grow. We currently don't have a way to construct
-    // strings from an integer value, so we can't use a loop here.
     var m = new Map();
     Expect.equals(m.length, 0);
-    m["1"] = 1;
-    m["2"] = 2;
-    m["3"] = 3;
-    m["4"] = 4;
-    m["5"] = 5;
-    m["6"] = 6;
-    m["7"] = 7;
-    m["8"] = 8;
-    m["9"] = 9;
-    m["10"] = 10;
-    m["11"] = 11;
-    m["12"] = 12;
-    m["13"] = 13;
-    m["14"] = 14;
-    m["15"] = 15;
-    m["16"] = 16;
+    for (var i = 1; i <= 16; i++) {
+      m[i.toString()] = i;
+    }
     Expect.equals(16, m.length);
-    m.remove("1");
-    m.remove("1"); // Remove element twice.
-    m.remove("16");
+    Expect.equals(1, m.remove("1"));
+    Expect.isNull(m.remove("1")); // Remove element twice.
+    Expect.equals(16, m.remove("16"));
     Expect.equals(14, m.length);
 
     final cmap = const <String, num>{"a": 10, "b": 100, "a": 1000}; //# 01: compile-time error
     final cmap2 = const <String, num>{"a": 10, "a": 100, "a": 1000}; //# 02: compile-time error
-    var mmap = <String, num>{"a": 10, "b": 100, "a": 1000}; //# 03: compile-time error
+    var mmap = <String, num>{"a": 10, "b": 100, "a": 1000}; //# 03: ok
     var mmap = <String, num>{"a": ctr(), "b": ctr(), "a": ctr()}; //# 04: compile-time error
 
     Expect.equals(10, {"beta": 100, "alpha": 9 + 1}["alpha"]);
diff --git a/tests/language_2/vm/osr_nonempty_stack_test.dart b/tests/language_2/vm/osr_nonempty_stack_test.dart
index 9797e6e..a31df50 100644
--- a/tests/language_2/vm/osr_nonempty_stack_test.dart
+++ b/tests/language_2/vm/osr_nonempty_stack_test.dart
@@ -93,6 +93,12 @@
   return x;
 }
 
+List<int> globalList = [
+  1,
+  for (int loc1 = 2; loc1 <= 100000; loc1++) loc1,
+  100001
+];
+
 main() {
   int n = 20000;
   int g = 457;
@@ -134,4 +140,10 @@
     Expect.equals(e[i], expect);
     if (++k == (n + 2)) k = 0;
   }
+
+  Expect.isTrue(globalList != null);
+  Expect.equals(100001, globalList.length);
+  for (int i = 0; i < globalList.length; i++) {
+    Expect.equals(globalList[i], i + 1);
+  }
 }
diff --git a/tests/lib_2/async/future_test.dart b/tests/lib_2/async/future_test.dart
index 515adca..9223646 100644
--- a/tests/lib_2/async/future_test.dart
+++ b/tests/lib_2/async/future_test.dart
@@ -1248,7 +1248,7 @@
   UglyFuture(int badness)
       : _result = (badness == 0) ? 42 : new UglyFuture(badness - 1);
   Future<S> then<S>(action(value), {Function onError}) {
-    var c = new Completer();
+    var c = new Completer<S>();
     c.complete(new Future.microtask(() => action(_result)));
     return c.future;
   }
diff --git a/tests/lib_2/lib_2_kernel.status b/tests/lib_2/lib_2_kernel.status
index 23463b5..2aeba0c 100644
--- a/tests/lib_2/lib_2_kernel.status
+++ b/tests/lib_2/lib_2_kernel.status
@@ -68,9 +68,9 @@
 
 [ ($compiler == dartk || $compiler == dartkb) && ($hot_reload || $hot_reload_rollback) ]
 isolate/message4_test: Crash # Timeout and sporadic crash (issue 33824)
-mirrors/dynamic_load_test: Crash
-mirrors/library_uri_io_test: Skip # Timeout
-mirrors/library_uri_package_test: Skip # Timeout
+mirrors/dynamic_load_test: Skip # Reload has an effect similar to deleting the dynamically loaded library
+mirrors/immutable_collections_test: Pass, Slow
+mirrors/mirrors_reader_test: Pass, Slow
 
 [ $compiler == app_jitk || $compiler == dartk || $compiler == dartkb || $compiler == dartkp ]
 html/*: SkipByDesign
diff --git a/tests/standalone_2/io/server_socket_exception_test.dart b/tests/standalone_2/io/server_socket_exception_test.dart
index f6c0993..16d1c34 100644
--- a/tests/standalone_2/io/server_socket_exception_test.dart
+++ b/tests/standalone_2/io/server_socket_exception_test.dart
@@ -28,10 +28,9 @@
     Expect.equals(true, !wrongExceptionCaught);
 
     // Test invalid host.
-    ServerSocket
-        .bind("__INVALID_HOST__", 0)
-        .then((server) {})
-        .catchError((e) => e is SocketException);
+    ServerSocket.bind("__INVALID_HOST__", 0).then((server) {
+      Expect.fail('Connection succeeded.');
+    }).catchError((e) => Expect.isTrue(e is SocketException));
   });
 }
 
diff --git a/tools/VERSION b/tools/VERSION
index e822ddc..da78ef9 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -33,7 +33,7 @@
 MAJOR 2
 MINOR 6
 PATCH 0
-PRERELEASE 0
+PRERELEASE 1
 PRERELEASE_PATCH 0
 ABI_VERSION 14
 OLDEST_SUPPORTED_ABI_VERSION 13
diff --git a/tools/approve_results.dart b/tools/approve_results.dart
index ebf1dd1..dc39a52 100755
--- a/tools/approve_results.dart
+++ b/tools/approve_results.dart
@@ -99,7 +99,9 @@
   bool get isApproved => result == null || result == approvedResult;
   List<String> get flakyModes =>
       flakinessData != null ? flakinessData["outcomes"].cast<String>() : null;
-  bool get isFlake => flakinessData != null && flakyModes.contains(result);
+  bool get isFlake =>
+      resultData != null && resultData["flaky"] ||
+      flakinessData != null && flakyModes.contains(result);
 }
 
 /// Loads the results file as as a map if the file exists, otherwise returns the