[dart] Update 3p packages

Also adding a link to //docs/development/languages/dart/third_party.md
from README.md to improve discoverability.

The goal of this update is to update protobuf to 0.7.0 for compatibility
with the Dart protobuf compiler.

Dependencies:
* https://dart-review.googlesource.com/40480 for a consistent version
  (Dart SDK had protobuf locked to 0.5.x).
* https://fuchsia-review.googlesource.com/121935 to remove an analysis
  failure that these updates would raise.
* https://fuchsia-review.googlesource.com/121968 (soft dependency)
  specifies the required package version and exposes the version
  conflict addressed by dart.../40480

Change-Id: I52b69b575172fd53740295e502ac8bc527a2a6e9
diff --git a/README.md b/README.md
index 2c2b01e..64a6b31 100644
--- a/README.md
+++ b/README.md
@@ -4,4 +4,4 @@
 This repository contains a copy of Dart packages used in the rest of Fuchsia
 that are mirrored from other locations, such as pub.dartlang.org.
 
-importer/third\_party contains a copy of PyYAML 3.12 from pyyaml.org.
+To update, please see [Third-party Dart packages](https://fuchsia.googlesource.com/docs/+/master/development/languages/dart/third_party.md).
diff --git a/_discoveryapis_commons/.travis.yml b/_discoveryapis_commons/.travis.yml
new file mode 100644
index 0000000..16cd8fd
--- /dev/null
+++ b/_discoveryapis_commons/.travis.yml
@@ -0,0 +1,18 @@
+language: dart
+
+dart:
+  - dev
+
+dart_task:
+  - test
+  - test: --platform firefox -j 1
+  - dartanalyzer: --fatal-infos --fatal-warnings .
+  - dartfmt
+
+# Only building master means that we don't run two builds for each pull request.
+branches:
+  only: [master]
+
+cache:
+ directories:
+   - $HOME/.pub-cache
diff --git a/_discoveryapis_commons/BUILD.gn b/_discoveryapis_commons/BUILD.gn
index 4848c1d..f603bca 100644
--- a/_discoveryapis_commons/BUILD.gn
+++ b/_discoveryapis_commons/BUILD.gn
@@ -1,4 +1,4 @@
-# This file is generated by importer.py for _discoveryapis_commons-0.1.4
+# This file is generated by importer.py for _discoveryapis_commons-0.1.5
 
 import("//build/dart/dart_library.gni")
 
diff --git a/_discoveryapis_commons/CHANGELOG.md b/_discoveryapis_commons/CHANGELOG.md
index 6c830a2..2e93798 100644
--- a/_discoveryapis_commons/CHANGELOG.md
+++ b/_discoveryapis_commons/CHANGELOG.md
@@ -1,3 +1,10 @@
+## 0.1.5
+
+- Updates to support Dart 2.0 core library changes (wave
+  2.2). See [issue 31847][sdk#31847] for details.
+
+  [sdk#31847]: https://github.com/dart-lang/sdk/issues/31847
+
 ## 0.1.4
 
 - Make package strong-mode clean.
diff --git a/_discoveryapis_commons/lib/src/clients.dart b/_discoveryapis_commons/lib/src/clients.dart
index 5e33874..fe1ec30 100644
--- a/_discoveryapis_commons/lib/src/clients.dart
+++ b/_discoveryapis_commons/lib/src/clients.dart
@@ -122,11 +122,11 @@
     });
   }
 
-  Future _request(
+  Future<http.StreamedResponse> _request(
       String requestUrl,
       String method,
       String body,
-      Map queryParams,
+      Map<String, List<String>> queryParams,
       client_requests.Media uploadMedia,
       client_requests.UploadOptions uploadOptions,
       client_requests.DownloadOptions downloadOptions,
@@ -313,7 +313,7 @@
 /**
  * Base64 encodes a stream of bytes.
  */
-class Base64Encoder implements StreamTransformer<List<int>, String> {
+class Base64Encoder extends StreamTransformerBase<List<int>, String> {
   static int lengthOfBase64Stream(int lengthOfByteStream) {
     return ((lengthOfByteStream + 2) ~/ 3) * 4;
   }
@@ -603,7 +603,8 @@
    * Returns the returned [http.StreamedResponse] or completes with an error if
    * the upload did not succeed. The response stream will not be listened to.
    */
-  Future _uploadChunk(Uri uri, ResumableChunk chunk, {bool lastChunk: false}) {
+  Future<http.StreamedResponse> _uploadChunk(Uri uri, ResumableChunk chunk,
+      {bool lastChunk: false}) {
     // If [uploadMedia.length] is null, we do not know the length.
     var mediaTotalLength =
         _uploadMedia.length == null ? null : _uploadMedia.length.toString();
diff --git a/_discoveryapis_commons/pubspec.yaml b/_discoveryapis_commons/pubspec.yaml
index 3669126..4086341 100644
--- a/_discoveryapis_commons/pubspec.yaml
+++ b/_discoveryapis_commons/pubspec.yaml
@@ -1,10 +1,10 @@
 name: _discoveryapis_commons
-version: 0.1.4
+version: 0.1.5
 author: Dart Team <misc@dartlang.org>
 description: Library for use by client APIs generated from Discovery Documents.
 homepage: https://github.com/dart-lang/discoveryapis_commons
 environment:
-  sdk: '>=1.21.0 <2.0.0'
+  sdk: '>=2.0.0-dev.20.0 <2.0.0'
 dependencies:
   http: '>=0.11.1 <0.12.0'
 dev_dependencies:
diff --git a/bazel_worker/BUILD.gn b/bazel_worker/BUILD.gn
index 32c51a3..826d3f3 100644
--- a/bazel_worker/BUILD.gn
+++ b/bazel_worker/BUILD.gn
@@ -1,4 +1,4 @@
-# This file is generated by importer.py for bazel_worker-0.1.8
+# This file is generated by importer.py for bazel_worker-0.1.9
 
 import("//build/dart/dart_library.gni")
 
diff --git a/bazel_worker/CHANGELOG.md b/bazel_worker/CHANGELOG.md
index b8b0031..b3cd92a 100644
--- a/bazel_worker/CHANGELOG.md
+++ b/bazel_worker/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.1.9
+
+* Update the worker_protocol.pb.dart file with the latest proto generator.
+
 ## 0.1.8
 
 * Add `Future cancel()` method to `DriverConnection`, which in the case of a
diff --git a/bazel_worker/lib/src/worker_protocol.pb.dart b/bazel_worker/lib/src/worker_protocol.pb.dart
index 6bff2f2..bb31b04 100644
--- a/bazel_worker/lib/src/worker_protocol.pb.dart
+++ b/bazel_worker/lib/src/worker_protocol.pb.dart
@@ -10,11 +10,12 @@
 
 // ignore: UNUSED_SHOWN_NAME
 import 'dart:core' show int, bool, double, String, List, override;
+
 import 'package:protobuf/protobuf.dart';
 
 class Input extends GeneratedMessage {
   static final BuilderInfo _i = new BuilderInfo('Input')
-    ..a<String>(1, 'path', PbFieldType.OS)
+    ..aOS(1, 'path')
     ..a<List<int>>(2, 'digest', PbFieldType.OY)
     ..hasRequiredFields = false;
 
@@ -37,20 +38,20 @@
     if (v is! Input) checkItemFailed(v, 'Input');
   }
 
-  String get path => $_get(0, 1, '');
+  String get path => $_getS(0, '');
   set path(String v) {
-    $_setString(0, 1, v);
+    $_setString(0, v);
   }
 
-  bool hasPath() => $_has(0, 1);
+  bool hasPath() => $_has(0);
   void clearPath() => clearField(1);
 
-  List<int> get digest => $_get(1, 2, null);
+  List<int> get digest => $_getN(1);
   set digest(List<int> v) {
-    $_setBytes(1, 2, v);
+    $_setBytes(1, v);
   }
 
-  bool hasDigest() => $_has(1, 2);
+  bool hasDigest() => $_has(1);
   void clearDigest() => clearField(2);
 }
 
@@ -58,7 +59,7 @@
 
 class WorkRequest extends GeneratedMessage {
   static final BuilderInfo _i = new BuilderInfo('WorkRequest')
-    ..p<String>(1, 'arguments', PbFieldType.PS)
+    ..pPS(1, 'arguments')
     ..pp<Input>(2, 'inputs', PbFieldType.PM, Input.$checkItem, Input.create)
     ..hasRequiredFields = false;
 
@@ -83,9 +84,9 @@
     if (v is! WorkRequest) checkItemFailed(v, 'WorkRequest');
   }
 
-  List<String> get arguments => $_get(0, 1, null);
+  List<String> get arguments => $_getN(0);
 
-  List<Input> get inputs => $_get(1, 2, null);
+  List<Input> get inputs => $_getN(1);
 }
 
 class _ReadonlyWorkRequest extends WorkRequest with ReadonlyMessageMixin {}
@@ -93,7 +94,7 @@
 class WorkResponse extends GeneratedMessage {
   static final BuilderInfo _i = new BuilderInfo('WorkResponse')
     ..a<int>(1, 'exitCode', PbFieldType.O3)
-    ..a<String>(2, 'output', PbFieldType.OS)
+    ..aOS(2, 'output')
     ..hasRequiredFields = false;
 
   WorkResponse() : super();
@@ -118,20 +119,20 @@
     if (v is! WorkResponse) checkItemFailed(v, 'WorkResponse');
   }
 
-  int get exitCode => $_get(0, 1, 0);
+  int get exitCode => $_get(0, 0);
   set exitCode(int v) {
-    $_setUnsignedInt32(0, 1, v);
+    $_setUnsignedInt32(0, v);
   }
 
-  bool hasExitCode() => $_has(0, 1);
+  bool hasExitCode() => $_has(0);
   void clearExitCode() => clearField(1);
 
-  String get output => $_get(1, 2, '');
+  String get output => $_getS(1, '');
   set output(String v) {
-    $_setString(1, 2, v);
+    $_setString(1, v);
   }
 
-  bool hasOutput() => $_has(1, 2);
+  bool hasOutput() => $_has(1);
   void clearOutput() => clearField(2);
 }
 
diff --git a/bazel_worker/pubspec.yaml b/bazel_worker/pubspec.yaml
index d2007e5..686ee6d 100644
--- a/bazel_worker/pubspec.yaml
+++ b/bazel_worker/pubspec.yaml
@@ -1,5 +1,5 @@
 name: bazel_worker
-version: 0.1.8
+version: 0.1.9
 description: Tools for creating a bazel persistent worker.
 author: Dart Team <misc@dartlang.org>
 homepage: https://github.com/dart-lang/bazel_worker
@@ -9,7 +9,7 @@
 
 dependencies:
   async: ">1.9.0 <3.0.0"
-  protobuf: ">=0.5.0 <0.7.0"
+  protobuf: ">=0.7.0 <0.8.0"
 
 dev_dependencies:
   test: ^0.12.0
diff --git a/dart_style/BUILD.gn b/dart_style/BUILD.gn
index b65c7bc..7c7ede8 100644
--- a/dart_style/BUILD.gn
+++ b/dart_style/BUILD.gn
@@ -1,4 +1,4 @@
-# This file is generated by importer.py for dart_style-1.0.9
+# This file is generated by importer.py for dart_style-1.0.9+1
 
 import("//build/dart/dart_library.gni")
 
diff --git a/dart_style/pubspec.yaml b/dart_style/pubspec.yaml
index d1f9821..0d9467f 100644
--- a/dart_style/pubspec.yaml
+++ b/dart_style/pubspec.yaml
@@ -1,18 +1,18 @@
 name: dart_style
 # Note: See tool/grind.dart for how to bump the version.
-version: 1.0.9
+version: 1.0.9+1
 author: Dart Team <misc@dartlang.org>
 description: Opinionated, automatic Dart source code formatter.
 homepage: https://github.com/dart-lang/dart_style
 environment:
   sdk: ">=1.8.0 <2.0.0"
 dependencies:
-  analyzer: '^0.30.0'
+  analyzer: '>=0.30.0 <0.32.0'
   args: '>=0.12.1 <2.0.0'
   path: '>=1.0.0 <2.0.0'
   source_span: '>=1.4.0 <2.0.0'
 dev_dependencies:
-  async: '>=1.0.0 <=2.0.0'
+  async: '>=1.0.0 <=3.0.0'
   browser: '>=0.10.0 <0.11.0'
   grinder: '^0.8.0'
   js: ^0.6.0
diff --git a/fixnum/BUILD.gn b/fixnum/BUILD.gn
index 7f346ce..21094bd 100644
--- a/fixnum/BUILD.gn
+++ b/fixnum/BUILD.gn
@@ -1,4 +1,4 @@
-# This file is generated by importer.py for fixnum-0.10.6
+# This file is generated by importer.py for fixnum-0.10.7
 
 import("//build/dart/dart_library.gni")
 
diff --git a/fixnum/CHANGELOG.md b/fixnum/CHANGELOG.md
index 228c997..3a427ac 100644
--- a/fixnum/CHANGELOG.md
+++ b/fixnum/CHANGELOG.md
@@ -1,3 +1,10 @@
+## 0.10.7
+
+* Bugfix: Make bitshifts work at bitwidth boundaries. Previously,
+  `new Int64(3) << 64 == Int64(3)`. This ensures that the result is 0 in such
+  cases.
+* Updated maximum SDK constraint from 2.0.0-dev.infinity to 2.0.0.
+
 ## 0.10.6
 
 * Fix `Int64([int value])` constructor to avoid rounding error on intermediate
diff --git a/fixnum/lib/src/int32.dart b/fixnum/lib/src/int32.dart
index 562ff0c..db8ecd0 100644
--- a/fixnum/lib/src/int32.dart
+++ b/fixnum/lib/src/int32.dart
@@ -239,7 +239,9 @@
     if (n < 0) {
       throw new ArgumentError(n);
     }
-    n &= 31;
+    if (n >= 32) {
+      return ZERO;
+    }
     return new Int32(_i << n);
   }
 
@@ -247,7 +249,9 @@
     if (n < 0) {
       throw new ArgumentError(n);
     }
-    n &= 31;
+    if (n >= 32) {
+      return isNegative ? const Int32._internal(-1) : ZERO;
+    }
     int value;
     if (_i >= 0) {
       value = _i >> n;
@@ -261,7 +265,9 @@
     if (n < 0) {
       throw new ArgumentError(n);
     }
-    n &= 31;
+    if (n >= 32) {
+      return ZERO;
+    }
     int value;
     if (_i >= 0) {
       value = _i >> n;
diff --git a/fixnum/lib/src/int64.dart b/fixnum/lib/src/int64.dart
index c25b8fa..a84cbd9 100644
--- a/fixnum/lib/src/int64.dart
+++ b/fixnum/lib/src/int64.dart
@@ -343,7 +343,9 @@
     if (n < 0) {
       throw new ArgumentError.value(n);
     }
-    n &= 63;
+    if (n >= 64) {
+      return ZERO;
+    }
 
     int res0, res1, res2;
     if (n < _BITS) {
@@ -367,7 +369,9 @@
     if (n < 0) {
       throw new ArgumentError.value(n);
     }
-    n &= 63;
+    if (n >= 64) {
+      return isNegative ? const Int64._bits(_MASK, _MASK, _MASK2) : ZERO;
+    }
 
     int res0, res1, res2;
 
@@ -410,7 +414,9 @@
     if (n < 0) {
       throw new ArgumentError.value(n);
     }
-    n &= 63;
+    if (n >= 64) {
+      return ZERO;
+    }
 
     int res0, res1, res2;
     int a2 = _MASK2 & _h; // Ensure a2 is positive.
diff --git a/fixnum/pubspec.yaml b/fixnum/pubspec.yaml
index a80a13e..d794eb1 100644
--- a/fixnum/pubspec.yaml
+++ b/fixnum/pubspec.yaml
@@ -1,9 +1,9 @@
 name: fixnum
-version: 0.10.6
+version: 0.10.7
 author: Dart Team <misc@dartlang.org>
 description: Library for 32- and 64-bit signed fixed-width integers.
 homepage: https://github.com/dart-lang/fixnum
 dev_dependencies:
   test: ^0.12.0
 environment:
-  sdk: ">=1.8.3 <2.0.0-dev.infinity"
+  sdk: ">=1.8.3 <2.0.0"
diff --git a/json_rpc_2/BUILD.gn b/json_rpc_2/BUILD.gn
index 872cebd..fe4527b 100644
--- a/json_rpc_2/BUILD.gn
+++ b/json_rpc_2/BUILD.gn
@@ -1,4 +1,4 @@
-# This file is generated by importer.py for json_rpc_2-2.0.6
+# This file is generated by importer.py for json_rpc_2-2.0.7
 
 import("//build/dart/dart_library.gni")
 
diff --git a/json_rpc_2/CHANGELOG.md b/json_rpc_2/CHANGELOG.md
index 6279653..ac97f07 100644
--- a/json_rpc_2/CHANGELOG.md
+++ b/json_rpc_2/CHANGELOG.md
@@ -1,3 +1,8 @@
+## 2.0.7
+
+* When a `Client` is closed before a request completes, the error sent to that
+  request's `Future` now includes the request method to aid in debugging.
+
 ## 2.0.6
 
 * Internal changes only.
diff --git a/json_rpc_2/lib/src/client.dart b/json_rpc_2/lib/src/client.dart
index 3607c4a..ff5c803 100644
--- a/json_rpc_2/lib/src/client.dart
+++ b/json_rpc_2/lib/src/client.dart
@@ -65,7 +65,8 @@
     _manager.done.whenComplete(() {
       for (var request in _pendingRequests.values) {
         request.completer.completeError(
-            new StateError("The client closed with pending requests."),
+            new StateError(
+                'The client closed with pending request "${request.method}".'),
             StackTrace.current);
       }
       _pendingRequests.clear();
@@ -106,7 +107,7 @@
     _send(method, parameters, id);
 
     var completer = new Completer.sync();
-    _pendingRequests[id] = new _Request(completer, new Chain.current());
+    _pendingRequests[id] = new _Request(method, completer, new Chain.current());
     return completer.future;
   }
 
@@ -213,11 +214,14 @@
 
 /// A pending request to the server.
 class _Request {
+  /// THe method that was sent.
+  final String method;
+
   /// The completer to use to complete the response future.
   final Completer completer;
 
   /// The stack chain from where the request was made.
   final Chain chain;
 
-  _Request(this.completer, this.chain);
+  _Request(this.method, this.completer, this.chain);
 }
diff --git a/json_rpc_2/pubspec.yaml b/json_rpc_2/pubspec.yaml
index b841c4d..3b4f993 100644
--- a/json_rpc_2/pubspec.yaml
+++ b/json_rpc_2/pubspec.yaml
@@ -1,5 +1,5 @@
 name: json_rpc_2
-version: 2.0.6
+version: 2.0.7
 author: Dart Team <misc@dartlang.org>
 description: An implementation of the JSON-RPC 2.0 spec.
 homepage: http://github.com/dart-lang/json_rpc_2
diff --git a/json_schema/.github/CONTRIBUTING.md b/json_schema/.github/CONTRIBUTING.md
new file mode 100644
index 0000000..e0bf676
--- /dev/null
+++ b/json_schema/.github/CONTRIBUTING.md
@@ -0,0 +1,183 @@
+# Contributing to json_schema
+
+Looking to contribute something to the json_schema library? __Here's how you can help.__
+
++ __[Coding Standards](#coding-standards)__
+  + [General Formatting Guidelines](#general-formatting-guidelines)
++ __[Using the Issue Tracker](#using-the-issue-tracker)__
+  + [Reporting Bugs](#bug-reports)
+  + [Feature Requests](#feature-requests)
+  + [Submitting Pull Requests](#pull-requests)
++ __[Developer Workflow](#developer-workflow)__
+
+
+
+
+## Coding standards
+
+A lot can be gained by writing code in a consistent way.  Moreover, always remember that code is written and 
+maintained by _people_. Ensure your code is descriptive, well commented, and approachable by others.
+
+__ALWAYS__ adhere to the [Dart Style Guide].  _Please take the time to read it if you have never done so._
+
+&nbsp;
+
+
+### General formatting guidelines
+
++ __AVOID__ lines longer than 120 characters.
++ __AVOID__ using `dartfmt` as an excuse to ignore good judgement about
+  whether your code is readable and approachable by others.
+
+&nbsp;
+&nbsp;
+
+
+
+## Using the issue tracker
+
+The issue tracker is the preferred channel for [bug reports](#bug-reports) and [feature requests](#feature-requests), 
+but __please follow the guidelines:__
+
+  + __Fill out the template we've provided.__
+
+  + __Be Professional__
+    + Please __do not__ derail or troll issues. Keep the discussion on topic and respect the opinions of others.
+
+  + __Not that Professional__
+    + Feel free to include _relevant_ animated gifs to drive home your message / request.
+
+&nbsp;
+
+
+### Bug reports
+
+A bug is a _demonstrable problem_ that is caused by the code in the repository.
+
+_Good bug reports are extremely helpful - thank you!__
+
+__Guidelines for bug reports:__
+
+1. __Search for existing issues.__ Duplicate issues can become cumbersome, and you'd help us out a lot by first 
+   checking if someone else has reported the same issue. Moreover, the issue may have already been resolved with a 
+   fix available.
+
+2. __Record a screencast of yourself reproducing the issue__. 
+  1. Be sure the problem exists in json_schema's code by building a 
+     reduced test case that one of the reviewers can pull locally 
+     and test out.
+
+3. __Share as much information as possible.__ Include operating system and version, browser and version, etc. where appropriate. 
+
+Always include steps to reproduce the bug.
+
+__Example Bug Report:__
+
+> Short and descriptive example bug report title
+>
+> A summary of the issue and the browser/OS environment in which it occurs. If
+> suitable, include the steps required to reproduce the bug.
+>
+> 1. This is the first step
+> 2. This is the second step
+> 3. Further steps, etc.
+>
+> `<url>` - a link to branch with the reduced test case
+>
+> Any other information you want to share that is relevant to the issue being
+> reported. This might include the lines of code that you have identified as
+> causing the bug, and potential solutions (and your opinions on their
+> merits).
+
+&nbsp;
+
+
+### Feature requests
+
+Feature requests are welcome. But take a moment to find out whether your idea fits with the scope and aims of the 
+project. It's up to *you* to make a strong case to convince the `json_schema` team of the merits of this feature. 
+Please provide as much detail and context as possible.
+
+&nbsp;
+
+
+### Pull requests
+
+Good pull requests - patches, improvements, new features - are a fantastic help. They should remain focused in scope 
+and avoid containing unrelated commits.
+
+__Please ask first__ before embarking on any significant pull request (e.g. implementing features, refactoring code, 
+porting to a different language), otherwise you risk spending a lot of time working on something that the project's 
+lead developers might not want to merge into the project.
+
+Please adhere to the [Dart Style Guide] for all changes contained in your pull requests.
+
+Adhering to the following process is the best way to get your work included in the project:
+
+1. [Fork](http://help.github.com/fork-a-repo/) the project, clone your fork,
+   and configure the remotes:
+
+   ```bash
+   # Navigate to the directory where you store repos locally
+   cd ~/your-local-git-repo-spot
+   # Clone your fork of the repo into the current directory
+   git clone git@github.com:<your-username>/json_schema
+   # Navigate to the newly cloned directory
+   cd ~/your-local-git-repo-spot/json_schema
+   # Assign the repo you forked from to a remote called "upstream"
+   git remote add upstream git@github.com:Workiva/json_schema
+   ```
+
+2. If you cloned a while ago, get the latest changes from upstream:
+
+   ```bash
+   git checkout master
+   git pull upstream master
+   ```
+
+3. Create a new topic branch that will contain your feature, change, or fix:
+
+   ```bash
+   git checkout -b <topic-branch-name>
+   ```
+
+4. Commit your changes in logical chunks. Please adhere to these 
+   [git commit message guidelines](#git-commit-message-standards) or your code is unlikely be merged into the master 
+   branch. Optionally, you can use Git's [interactive rebase](https://help.github.com/articles/interactive-rebase) 
+   feature to tidy up your commits before making them public.
+
+5. Write tests for your changes.  
+  1. There are no exceptions.  
+  2. If you're having trouble, reach out in your PR about how to best go about testing your changes.
+
+6. If you have merge conflicts, locally merge the upstream master branch into your topic branch:
+
+   ```bash
+   git pull upstream master
+   ```
+
+7. Push your topic branch up to your fork:
+
+   ```bash
+   git push origin <topic-branch-name>
+   ```
+
+8. [Open a Pull Request](https://help.github.com/articles/using-pull-requests/)
+    with a clear title and description - following all the [issue guidelines](#using-the-issue-tracker) listed above.
+
+&nbsp;
+&nbsp;
+
+
+## Developer Workflow
+
+The `json_schema` developer workflow couldn't be any more simple!
+
+When you're ready to run the tests... run:
+
+```bash
+pub run dart_dev test
+```
+
+
+[Dart Style Guide]: https://www.dartlang.org/guides/language/effective-dart/style
\ No newline at end of file
diff --git a/json_schema/.github/ISSUE_TEMPLATE.md b/json_schema/.github/ISSUE_TEMPLATE.md
new file mode 100644
index 0000000..f5db425
--- /dev/null
+++ b/json_schema/.github/ISSUE_TEMPLATE.md
@@ -0,0 +1,28 @@
+<!--- Provide a general summary of the issue in the title above -->
+
+<!--- Provide the type of issue (Bug, Improvement, Feature Request) -->
+## Type
+
+## Details
+<!--- If you're describing a bug, tell us what happens instead of the expected behavior -->
+<!--- If you're suggesting a change/improvement, tell us how it should work -->
+
+## Possible Solution
+<!--- Not obligatory, but suggest a fix/reason for the bug, -->
+<!--- or ideas how to implement the addition or change -->
+
+<!--- Delete the following sections if not submitting a bug -->
+
+## Steps to Reproduce
+<!--- Provide steps to reproduce this bug. Include code to reproduce, if relevant -->
+1.
+2.
+3.
+
+## Your Environment
+<!--- Include as many relevant details about the environment you experienced the bug in -->
+* Version:
+* Browser name / VM and version:
+* Operating System and version:
+
+> __FYI:__ @michaelcarter-wf
\ No newline at end of file
diff --git a/json_schema/.github/PULL_REQUEST_TEMPLATE.md b/json_schema/.github/PULL_REQUEST_TEMPLATE.md
new file mode 100644
index 0000000..e2bcab9
--- /dev/null
+++ b/json_schema/.github/PULL_REQUEST_TEMPLATE.md
@@ -0,0 +1,16 @@
+## Ultimate problem:
+
+
+## How it was fixed:
+
+
+## Testing suggestions:
+
+
+## Potential areas of regression:
+
+
+
+---
+
+> __FYA:__ @michaelcarter-wf
\ No newline at end of file
diff --git a/json_schema/.gitignore b/json_schema/.gitignore
index 0de029e..aff650d 100644
--- a/json_schema/.gitignore
+++ b/json_schema/.gitignore
@@ -1,18 +1,17 @@
 *.~*~
+.idea/
 .packages
-packages
-build/
-.pub/
 .project
+.pub/
+*.dart.js
 *.iml
 *.ipr
 *.iws
-.idea/
-*.dart.js
 *.js_
 *.js.deps
 *.js.map
-# custom <additional>
+build/
+coverage
+packages
 pubspec.lock
-# end <additional>
 
diff --git a/json_schema/.travis.yml b/json_schema/.travis.yml
index 2e9f3e7..43be079 100644
--- a/json_schema/.travis.yml
+++ b/json_schema/.travis.yml
@@ -2,5 +2,11 @@
 sudo: false
 dart:
   - stable
-  - dev
-script: ./tool/travis.sh
\ No newline at end of file
+script:
+  - pub get --packages-dir
+  - pub run dependency_validator --ignore dart_style,coverage
+  - pub run dart_dev format --check
+  - pub run dart_dev analyze
+  - pub run dart_dev test
+  - pub run dart_dev coverage --no-html
+  - bash <(curl -s https://codecov.io/bash) -f coverage/coverage.lcov
\ No newline at end of file
diff --git a/json_schema/BUILD.gn b/json_schema/BUILD.gn
index b2b4932..6725498 100644
--- a/json_schema/BUILD.gn
+++ b/json_schema/BUILD.gn
@@ -1,4 +1,4 @@
-# This file is generated by importer.py for json_schema-1.0.7
+# This file is generated by importer.py for json_schema-1.0.8
 
 import("//build/dart/dart_library.gni")
 
diff --git a/json_schema/CHANGELOG.md b/json_schema/CHANGELOG.md
index b90af2e..3567e43 100644
--- a/json_schema/CHANGELOG.md
+++ b/json_schema/CHANGELOG.md
@@ -1,3 +1,9 @@
+## 1.0.8
+
+* Code cleanup
+* Strong mode
+* Switch build tools to dart_dev
+
 ## 1.0.7
 
 * Update dependency constraint on the `args` package.
diff --git a/json_schema/COPYRIGHT_TRANSFER b/json_schema/COPYRIGHT_TRANSFER
new file mode 100644
index 0000000..610c818
--- /dev/null
+++ b/json_schema/COPYRIGHT_TRANSFER
@@ -0,0 +1 @@
+I, Daniel Davidson, hereby assign the copyright of JSON Schema to Workiva Inc., to be carried forward under an open source license.
diff --git a/json_schema/LICENSE b/json_schema/LICENSE
index cd4d2bd..9f3f33e 100644
--- a/json_schema/LICENSE
+++ b/json_schema/LICENSE
@@ -1 +1,37 @@
-License: <a href="http://www.boost.org/LICENSE_1_0.txt">Boost License 1.0</a>.
+Copyright 2013-2018 Workiva Inc.
+
+Licensed under the Boost Software License (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.boost.org/LICENSE_1_0.txt
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+This software or document includes material copied from or derived 
+from JSON-Schema-Test-Suite (https://github.com/json-schema-org/JSON-Schema-Test-Suite), 
+Copyright (c) 2012 Julian Berman, which is licensed under the following terms:
+
+    Copyright (c) 2012 Julian Berman
+
+    Permission is hereby granted, free of charge, to any person obtaining a copy
+    of this software and associated documentation files (the "Software"), to deal
+    in the Software without restriction, including without limitation the rights
+    to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+    copies of the Software, and to permit persons to whom the Software is
+    furnished to do so, subject to the following conditions:
+
+    The above copyright notice and this permission notice shall be included in
+    all copies or substantial portions of the Software.
+
+    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+    AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+    THE SOFTWARE.
\ No newline at end of file
diff --git a/json_schema/README.md b/json_schema/README.md
index 6539a3f..d9cbcc8 100644
--- a/json_schema/README.md
+++ b/json_schema/README.md
@@ -2,7 +2,7 @@
 
   A *dart:io* dependent library for validating json instances against json schema (version Draft 04)
 
-![Build Status](https://travis-ci.org/patefacio/json_schema.svg)
+![Build Status](https://travis-ci.org/workiva/json_schema.svg)
 
 
 # How To Validate
diff --git a/json_schema/bin/gensamples.dart b/json_schema/bin/gensamples.dart
index b032e1b..2917ebe 100644
--- a/json_schema/bin/gensamples.dart
+++ b/json_schema/bin/gensamples.dart
@@ -1,11 +1,48 @@
+// Copyright 2013-2018 Workiva Inc.
+//
+// Licensed under the Boost Software License (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.boost.org/LICENSE_1_0.txt
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// This software or document includes material copied from or derived
+// from JSON-Schema-Test-Suite (https://github.com/json-schema-org/JSON-Schema-Test-Suite),
+// Copyright (c) 2012 Julian Berman, which is licensed under the following terms:
+//
+//     Copyright (c) 2012 Julian Berman
+//
+//     Permission is hereby granted, free of charge, to any person obtaining a copy
+//     of this software and associated documentation files (the "Software"), to deal
+//     in the Software without restriction, including without limitation the rights
+//     to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+//     copies of the Software, and to permit persons to whom the Software is
+//     furnished to do so, subject to the following conditions:
+//
+//     The above copyright notice and this permission notice shall be included in
+//     all copies or substantial portions of the Software.
+//
+//     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+//     IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+//     FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+//     AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+//     LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+//     OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+//     THE SOFTWARE.
+
 import 'dart:io';
 import 'package:path/path.dart';
 import 'package:json_schema/json_schema.dart';
 import 'package:json_schema/schema_dot.dart';
 
 main() {
-  var sourcePath = join(dirname(dirname(absolute(Platform.script.toFilePath()))),
-      'dot_samples', 'schemas');
+  var sourcePath = join(dirname(dirname(absolute(Platform.script.toFilePath()))), 'dot_samples', 'schemas');
   var outPath = join(dirname(sourcePath), 'schemaout');
   new Directory(sourcePath).listSync().forEach((jsonFile) {
     var fname = jsonFile.path;
@@ -13,20 +50,16 @@
     var dotFilename = join(outPath, '$base.dot');
     var pngOut = join(outPath, '$base.png');
 
-    Schema.createSchemaFromUrl(fname)
-      .then((schema) {
-        new File(dotFilename).writeAsStringSync(createDot(schema));
-      })
-      .then((_) {
-
-        Process.run('dot', ['-Tpng', '-o$pngOut', dotFilename])
-          .then((ProcessResult processResult) {
-            if(processResult.exitCode == 0) {
-              print("Finished running dot -Tpng -o$pngOut $fname");
-            } else {
-              print("FAILED: running dot -Tpng -o$pngOut $fname");
-            }
-          });
+    Schema.createSchemaFromUrl(fname).then((schema) {
+      new File(dotFilename).writeAsStringSync(createDot(schema));
+    }).then((_) {
+      Process.run('dot', ['-Tpng', '-o$pngOut', dotFilename]).then((ProcessResult processResult) {
+        if (processResult.exitCode == 0) {
+          print("Finished running dot -Tpng -o$pngOut $fname");
+        } else {
+          print("FAILED: running dot -Tpng -o$pngOut $fname");
+        }
       });
+    });
   });
-}
\ No newline at end of file
+}
diff --git a/json_schema/bin/schemadot.dart b/json_schema/bin/schemadot.dart
index bc09928..9e6102d 100644
--- a/json_schema/bin/schemadot.dart
+++ b/json_schema/bin/schemadot.dart
@@ -1,4 +1,41 @@
 #!/usr/bin/env dart
+// Copyright 2013-2018 Workiva Inc.
+//
+// Licensed under the Boost Software License (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.boost.org/LICENSE_1_0.txt
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// This software or document includes material copied from or derived
+// from JSON-Schema-Test-Suite (https://github.com/json-schema-org/JSON-Schema-Test-Suite),
+// Copyright (c) 2012 Julian Berman, which is licensed under the following terms:
+//
+//     Copyright (c) 2012 Julian Berman
+//
+//     Permission is hereby granted, free of charge, to any person obtaining a copy
+//     of this software and associated documentation files (the "Software"), to deal
+//     in the Software without restriction, including without limitation the rights
+//     to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+//     copies of the Software, and to permit persons to whom the Software is
+//     furnished to do so, subject to the following conditions:
+//
+//     The above copyright notice and this permission notice shall be included in
+//     all copies or substantial portions of the Software.
+//
+//     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+//     IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+//     FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+//     AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+//     LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+//     OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+//     THE SOFTWARE.
 
 ///
 /// Usage: schemadot --in-uri INPUT_JSON_URI --out-file OUTPUT_FILE
@@ -11,7 +48,6 @@
 import 'dart:async';
 import 'dart:convert' as convert;
 import 'dart:io';
-import 'dart:math';
 import 'package:args/args.dart';
 import 'package:json_schema/json_schema.dart';
 import 'package:json_schema/schema_dot.dart';
@@ -33,7 +69,7 @@
 the file, otherwise written to stdout.
 
 ''');
-  print(_parser.getUsage());
+  print(_parser.usage);
 }
 
 //! Method to parse command line options.
@@ -41,7 +77,6 @@
 Map _parseArgs(List<String> args) {
   ArgResults argResults;
   Map result = {};
-  List remaining = [];
 
   _parser = new ArgParser();
   try {
@@ -53,18 +88,8 @@
         abbr: 'h',
         defaultsTo: false);
 
-    _parser.addOption('in-uri',
-        help: '',
-        defaultsTo: null,
-        allowMultiple: false,
-        abbr: 'i',
-        allowed: null);
-    _parser.addOption('out-file',
-        help: '',
-        defaultsTo: null,
-        allowMultiple: false,
-        abbr: 'o',
-        allowed: null);
+    _parser.addOption('in-uri', help: '', defaultsTo: null, allowMultiple: false, abbr: 'i', allowed: null);
+    _parser.addOption('out-file', help: '', defaultsTo: null, allowMultiple: false, abbr: 'o', allowed: null);
     _parser.addOption('log-level',
         help: r'''
 Select log level from:
@@ -116,15 +141,13 @@
 final _logger = new Logger('schemadot');
 
 main(List<String> args) {
-  Logger.root.onRecord.listen(
-      (LogRecord r) => print("${r.loggerName} [${r.level}]:\t${r.message}"));
+  Logger.root.onRecord.listen((LogRecord r) => print("${r.loggerName} [${r.level}]:\t${r.message}"));
   Logger.root.level = Level.OFF;
   Map argResults = _parseArgs(args);
   Map options = argResults['options'];
-  List positionals = argResults['rest'];
+
   try {
-    if (options["in-uri"] == null)
-      throw new ArgumentError("option: in-uri is required");
+    if (options["in-uri"] == null) throw new ArgumentError("option: in-uri is required");
   } on ArgumentError catch (e) {
     print(e);
     _usage();
@@ -139,8 +162,7 @@
     new HttpClient()
         .getUrl(uri)
         .then((HttpClientRequest request) => request.close())
-        .then((HttpClientResponse response) =>
-            response.transform(new convert.Utf8Decoder()).join())
+        .then((HttpClientResponse response) => response.transform(new convert.Utf8Decoder()).join())
         .then((text) {
       completer.complete(text);
     });
diff --git a/json_schema/codegen/json_schema.ebisu_dart.dart b/json_schema/codegen/json_schema.ebisu_dart.dart
deleted file mode 100644
index 068ee0b..0000000
--- a/json_schema/codegen/json_schema.ebisu_dart.dart
+++ /dev/null
@@ -1,354 +0,0 @@
-import "dart:io";
-import "package:path/path.dart" as path;
-import "package:ebisu/ebisu_dart_meta.dart";
-import "package:ebisu/ebisu.dart";
-import "package:logging/logging.dart";
-
-String _topDir;
-
-void main() {
-  Logger.root.onRecord.listen((LogRecord r) =>
-      print("${r.loggerName} [${r.level}]:\t${r.message}"));
-  String here = path.absolute(Platform.script.toFilePath());
-  _topDir = path.dirname(path.dirname(here));
-  useDartFormatter = true;
-  System ebisu = system('json_schema')
-    ..pubSpec.homepage = 'https://github.com/patefacio/json_schema'
-    ..pubSpec.version = '1.0.7'
-    ..pubSpec.doc = 'Provide support for validating instances against json schema'
-    ..rootPath = '$_topDir'
-    ..doc = 'Json Schema related functionality'
-    ..testLibraries = [
-      library('test_invalid_schemas')
-      ..includesLogger = true
-      ..imports = [
-        'io', '"dart:convert" as convert', '"package:path/path.dart" as path',
-        'package:json_schema/json_schema.dart',
-      ],
-      library('test_validation')
-      ..includesLogger = true
-      ..imports = [
-        'io', '"dart:convert" as convert', '"package:path/path.dart" as path',
-        'package:json_schema/json_schema.dart',
-      ],
-    ]
-    ..scripts = [
-      script('schemadot')
-      ..imports = [
-        'package:json_schema/json_schema.dart',
-        'package:json_schema/schema_dot.dart',
-        '"dart:convert" as convert',
-        'math',
-        'async',
-      ]
-      ..doc = '''
-
-Usage: schemadot --in-uri INPUT_JSON_URI --out-file OUTPUT_FILE
-
-Given an input uri [in-uri] processes content of uri as
-json schema and generates input file for Graphviz dot
-program. If [out-file] provided, output is written to
-the file, otherwise written to stdout.
-'''
-      ..args = [
-        scriptArg('in_uri')
-        ..isRequired = true
-        ..abbr = 'i',
-        scriptArg('out_file')
-        ..abbr = 'o',
-      ]
-    ]
-    ..libraries = [
-      library('schema_dot')
-      ..doc = 'Functionality to create Graphviz input dot file from schema'
-      ..imports = [
-        'package:json_schema/json_schema.dart',
-        'convert',
-        'async',
-      ]
-      ..classes = [
-        class_('schema_node')
-        ..doc = 'Represents one node in the schema diagram'
-        ..members = [
-          member('schema')
-          ..doc = 'Referenced schema this node portrays'
-          ..type = 'Schema',
-          member('links')
-          ..doc = 'List of links (resulting in graph edge) from this node to another'
-          ..type = 'List<String>'
-        ]
-      ],
-      library('json_schema')
-      ..doc = 'Support for validating json instances against a json schema'
-      ..includesLogger = true
-      ..enums = [
-        enum_('schema_type')
-        ..isSnakeString = true
-        ..hasCustom = true
-        ..values = [
-          id('array'), id('boolean'), id('integer'),
-          id('number'), id('null'), id('object'),
-          id('string')
-        ]
-      ]
-      ..imports = [
-        'io',
-        'math',
-        '"dart:convert" as convert',
-        '"package:path/path.dart" as PATH',
-        'async',
-      ]
-      ..parts = [
-        part('schema')
-        ..classes = [
-          class_('schema')
-          ..defaultMemberAccess = RO
-          ..ctorCustoms = [ '_fromRootMap', '_fromMap' ]
-          ..doc = '''
-Constructed with a json schema, either as string or Map. Validation of
-the schema itself is done on construction. Any errors in the schema
-result in a FormatException being thrown.
-'''
-          ..members = [
-            member('root')
-            ..type = 'Schema'
-            ..ctors = [ '_fromMap' ],
-            member('schema_map')
-            ..type = 'Map'
-            ..classInit = '{}'
-            ..ctors = [ '_fromRootMap', '_fromMap' ],
-            member('path')
-            ..ctorInit = "'#'"
-            ..ctors = [ '_fromMap' ],
-
-            member('multiple_of')
-            ..type = 'num',
-            member('maximum')
-            ..type = 'num',
-            member('exclusive_maximum')
-            ..type = 'bool'
-            ..access = IA,
-            member('minimum')
-            ..type = 'num',
-            member('exclusive_minimum')
-            ..type = 'bool'
-            ..access = IA,
-            member('max_length')
-            ..type = 'int',
-            member('min_length')
-            ..type = 'int',
-            member('pattern')
-            ..type = 'RegExp',
-
-            // Validation keywords for any instance
-            member('enum_values')
-            ..type = 'List'
-            ..classInit = '[]',
-            member('all_of')
-            ..type = 'List<Schema>'
-            ..classInit = '[]',
-            member('any_of')
-            ..type = 'List<Schema>'
-            ..classInit = '[]',
-            member('one_of')
-            ..type = 'List<Schema>'
-            ..classInit = '[]',
-            member('not_schema')
-            ..type = 'Schema',
-            member('definitions')
-            ..type = 'Map<String,Schema>'
-            ..classInit = '{}',
-
-            // Meta-data
-            member('id')
-            ..type = 'Uri',
-            member('ref'),
-            member('description'),
-            member('title'),
-
-            member('schema_type_list')
-            ..type = 'List<SchemaType>',
-            member('items')
-            ..doc = 'To match all items to a schema'
-            ..type = 'Schema',
-            member('items_list')
-            ..doc = 'To match each item in array to a schema'
-            ..type = 'List<Schema>',
-            member('additional_items')
-            ..type = 'dynamic',
-            member('max_items')
-            ..type = 'int',
-            member('min_items')
-            ..type = 'int',
-            member('unique_items')
-            ..type = 'bool'
-            ..classInit = 'false',
-
-            member('required_properties')
-            ..type = 'List<String>',
-            member('max_properties')
-            ..type = 'int',
-            member('min_properties')
-            ..type = 'int'
-            ..classInit = '0',
-            member('properties')
-            ..type = 'Map<String,Schema>'
-            ..classInit = '{}',
-            member('additional_properties')
-            ..type = 'bool',
-            member('additional_properties_schema')
-            ..type = 'Schema',
-            member('pattern_properties')
-            ..type = 'Map<RegExp,Schema>'
-            ..classInit = '{}',
-
-            member('schema_dependencies')
-            ..type = 'Map<String,Schema>'
-            ..classInit = '{}',
-            member('property_dependencies')
-            ..type = 'Map<String,List<String>>'
-            ..classInit = '{}',
-
-            member('default_value')
-            ..type = 'dynamic',
-
-            member('ref_map')
-            ..doc = 'Map of path to schema object'
-            ..type = 'Map<String,Schema>'
-            ..classInit = '{}',
-            member('schema_refs')
-            ..doc = 'For schemas with \$ref maps path of schema to \$ref path'
-            ..type = 'Map<String,String>'
-            ..access = IA
-            ..classInit = '{}',
-            member('schema_assignments')
-            ..doc = 'Assignments to call for resolution upon end of parse'
-            ..type = 'List'
-            ..classInit = '[]'
-            ..access = IA,
-            member('free_form_map')
-            ..doc = 'Maps any non-key top level property to its original value'
-            ..type = 'Map<String,dynamic>'
-            ..classInit = '{}'
-            ..access = IA,
-            member('this_completer')
-            ..type = 'Completer'
-            ..classInit = 'new Completer()'
-            ..access = IA,
-            member('retrieval_requests')
-            ..type = 'List<Future<Schema>>'
-            ..init = []
-            ..access = IA,
-            member('paths_encountered')
-            ..doc = 'Set of strings to gaurd against path cycles'
-            ..type = 'Set<String>'
-            ..classInit = 'new Set()'
-            ..access = IA,
-            member('format')
-            ..doc = 'Support for optional formats (date-time, uri, email, ipv6, hostname)'
-            ..access = IA,
-          ]
-        ],
-        part('validator')
-      ..variables = [
-        variable('email_re')
-        ..isPublic = false
-        ..type = 'RegExp'
-        ..init = "new RegExp(\n"
-        r'''
-  r'^[_A-Za-z0-9-\+]+(\.[_A-Za-z0-9-]+)*'
-  r'@'
-  r'[A-Za-z0-9-]+(\.[A-Za-z0-9]+)*(\.[A-Za-z]{2,})$'
-'''
-        ")",
-        variable('default_email_validator')
-        ..type = 'var'
-        ..isPublic = false
-        ..init = '(String email) => _emailRe.firstMatch(email) != null',
-        variable('email_validator')
-        ..isPublic = false
-        ..type = 'var'
-        ..init = '_defaultEmailValidator',
-        variable('ipv4_re')
-        ..isPublic = false
-        ..type = 'RegExp'
-        ..init = "new RegExp(\n"
-        r'''
-  r'^(\d|[1-9]\d|1\d\d|2([0-4]\d|5[0-5]))\.'
-  r'(\d|[1-9]\d|1\d\d|2([0-4]\d|5[0-5]))\.'
-  r'(\d|[1-9]\d|1\d\d|2([0-4]\d|5[0-5]))\.'
-  r'(\d|[1-9]\d|1\d\d|2([0-4]\d|5[0-5]))$'
-'''
-        ")",
-        variable('ipv6_re')
-        ..isPublic = false
-        ..type = 'RegExp'
-        ..init = "new RegExp(\n"
-        r'''
-  r'(^([0-9a-f]{1,4}:){1,1}(:[0-9a-f]{1,4}){1,6}$)|'
-  r'(^([0-9a-f]{1,4}:){1,2}(:[0-9a-f]{1,4}){1,5}$)|'
-  r'(^([0-9a-f]{1,4}:){1,3}(:[0-9a-f]{1,4}){1,4}$)|'
-  r'(^([0-9a-f]{1,4}:){1,4}(:[0-9a-f]{1,4}){1,3}$)|'
-  r'(^([0-9a-f]{1,4}:){1,5}(:[0-9a-f]{1,4}){1,2}$)|'
-  r'(^([0-9a-f]{1,4}:){1,6}(:[0-9a-f]{1,4}){1,1}$)|'
-  r'(^(([0-9a-f]{1,4}:){1,7}|:):$)|'
-  r'(^:(:[0-9a-f]{1,4}){1,7}$)|'
-  r'(^((([0-9a-f]{1,4}:){6})(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3})$)|'
-  r'(^(([0-9a-f]{1,4}:){5}[0-9a-f]{1,4}:(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3})$)|'
-  r'(^([0-9a-f]{1,4}:){5}:[0-9a-f]{1,4}:(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}$)|'
-  r'(^([0-9a-f]{1,4}:){1,1}(:[0-9a-f]{1,4}){1,4}:(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}$)|'
-  r'(^([0-9a-f]{1,4}:){1,2}(:[0-9a-f]{1,4}){1,3}:(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}$)|'
-  r'(^([0-9a-f]{1,4}:){1,3}(:[0-9a-f]{1,4}){1,2}:(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}$)|'
-  r'(^([0-9a-f]{1,4}:){1,4}(:[0-9a-f]{1,4}){1,1}:(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}$)|'
-  r'(^(([0-9a-f]{1,4}:){1,5}|:):(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}$)|'
-  r'(^:(:[0-9a-f]{1,4}){1,5}:(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}$)'
-'''
-        ")",
-        variable('default_uri_validator')
-        ..type = 'var'
-        ..isPublic = false
-        ..init = '''
-(String uri) {
-  try {
-    final result = Uri.parse(uri);
-    if(result.path.startsWith('//')) return false;
-    return true;
-  } catch(e) {
-    return false;
-  }
-}''',
-        variable('hostname_re')
-        ..isPublic = false
-        ..type = 'RegExp'
-        ..init = "new RegExp(\n"
-        r'''
-  r'^(?=.{1,255}$)'
-  r'[0-9A-Za-z](?:(?:[0-9A-Za-z]|-){0,61}[0-9A-Za-z])?'
-  r'(?:\.[0-9A-Za-z](?:(?:[0-9A-Za-z]|-){0,61}[0-9A-Za-z])?)*\.?$'
-'''
-        ")",
-        variable('uri_validator')
-        ..isPublic = false
-        ..type = 'var'
-        ..init = '_defaultUriValidator',
-      ]
-        ..classes = [
-          class_('validator')
-          ..defaultMemberAccess = IA
-          ..doc = 'Initialized with schema, validates instances against it'
-          ..members = [
-            member('root_schema')
-            ..type = 'Schema'
-            ..ctors = [''],
-            member('errors')
-            ..type = 'List<String>'
-            ..access = RO
-            ..classInit = '[]',
-            member('report_multiple_errors')
-            ..type = 'bool',
-          ],
-        ]
-      ]
-    ];
-  ebisu.generate();
-}
diff --git a/json_schema/example/from_json/movie_sample.dart b/json_schema/example/from_json/movie_sample.dart
index d2eac74..b57d4fb 100644
--- a/json_schema/example/from_json/movie_sample.dart
+++ b/json_schema/example/from_json/movie_sample.dart
@@ -1,4 +1,41 @@
 #!/usr/bin/env dart
+// Copyright 2013-2018 Workiva Inc.
+//
+// Licensed under the Boost Software License (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.boost.org/LICENSE_1_0.txt
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// This software or document includes material copied from or derived
+// from JSON-Schema-Test-Suite (https://github.com/json-schema-org/JSON-Schema-Test-Suite),
+// Copyright (c) 2012 Julian Berman, which is licensed under the following terms:
+//
+//     Copyright (c) 2012 Julian Berman
+//
+//     Permission is hereby granted, free of charge, to any person obtaining a copy
+//     of this software and associated documentation files (the "Software"), to deal
+//     in the Software without restriction, including without limitation the rights
+//     to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+//     copies of the Software, and to permit persons to whom the Software is
+//     furnished to do so, subject to the following conditions:
+//
+//     The above copyright notice and this permission notice shall be included in
+//     all copies or substantial portions of the Software.
+//
+//     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+//     IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+//     FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+//     AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+//     LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+//     OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+//     THE SOFTWARE.
 
 import "package:json_schema/json_schema.dart";
 import "package:logging/logging.dart";
@@ -13,54 +50,44 @@
   // Define schema in code
   //////////////////////////////////////////////////////////////////////
   var movieSchema = {
-    "title" : "movie data",
-    "additionalProperties" : false,
-    "required" : [ "movies" ],
-    "properties" : {
-      "movies" : { r"$ref" : "#/definitions/movie_map" }
+    "title": "movie data",
+    "additionalProperties": false,
+    "required": ["movies"],
+    "properties": {
+      "movies": {r"$ref": "#/definitions/movie_map"}
     },
-    "definitions" : {
-      "movie" : {
+    "definitions": {
+      "movie": {
         "additionalProperties": false,
-        "required" : [ "title", "year_made", "rating" ],
+        "required": ["title", "year_made", "rating"],
         "properties": {
-          "title" : { "type" : "string" },
-          "year_made" : { "type" : "integer" },
-          "rating" : { "type" : "integer" }
+          "title": {"type": "string"},
+          "year_made": {"type": "integer"},
+          "rating": {"type": "integer"}
         }
       },
-      "movie_map" : {
+      "movie_map": {
         "type": "object",
-        "additionalProperties": { r"$ref": "#/definitions/movie" },
+        "additionalProperties": {r"$ref": "#/definitions/movie"},
         "default": {}
       }
     }
   };
 
   var movies = {
-    "movies" : {
-      "the mission" : {
-        "title":"The Mission",
-        "year_made":1986,
-        "rating":5
-      },
-      "troll 2" : {
-        "title":"Troll 2",
-        "year_made":1990,
-        "rating":2
-      }
+    "movies": {
+      "the mission": {"title": "The Mission", "year_made": 1986, "rating": 5},
+      "troll 2": {"title": "Troll 2", "year_made": 1990, "rating": 2}
     }
   };
 
-  Schema.createSchema(movieSchema)
-    .then((schema) {
-      var validator = new Validator(schema);
-      bool validates = validator.validate(movies);
-      if(!validates) {
-        print("Errors: ${validator.errors}");
-      } else {
-        print('$movies:\nvalidates!');
-      }
-    });
-
+  Schema.createSchema(movieSchema).then((schema) {
+    var validator = new Validator(schema);
+    bool validates = validator.validate(movies);
+    if (!validates) {
+      print("Errors: ${validator.errors}");
+    } else {
+      print('$movies:\nvalidates!');
+    }
+  });
 }
diff --git a/json_schema/example/from_json/validate_json_from_data.dart b/json_schema/example/from_json/validate_json_from_data.dart
index 6640c08..38d032e 100644
--- a/json_schema/example/from_json/validate_json_from_data.dart
+++ b/json_schema/example/from_json/validate_json_from_data.dart
@@ -1,30 +1,61 @@
 #!/usr/bin/env dart
+// Copyright 2013-2018 Workiva Inc.
+//
+// Licensed under the Boost Software License (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.boost.org/LICENSE_1_0.txt
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// This software or document includes material copied from or derived
+// from JSON-Schema-Test-Suite (https://github.com/json-schema-org/JSON-Schema-Test-Suite),
+// Copyright (c) 2012 Julian Berman, which is licensed under the following terms:
+//
+//     Copyright (c) 2012 Julian Berman
+//
+//     Permission is hereby granted, free of charge, to any person obtaining a copy
+//     of this software and associated documentation files (the "Software"), to deal
+//     in the Software without restriction, including without limitation the rights
+//     to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+//     copies of the Software, and to permit persons to whom the Software is
+//     furnished to do so, subject to the following conditions:
+//
+//     The above copyright notice and this permission notice shall be included in
+//     all copies or substantial portions of the Software.
+//
+//     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+//     IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+//     FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+//     AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+//     LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+//     OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+//     THE SOFTWARE.
 
 import "package:json_schema/json_schema.dart";
 import "package:logging/logging.dart";
 
 main() {
-
-  Logger.root.onRecord.listen((LogRecord rec) =>
-    print('${rec.level.name}: ${rec.time}: ${rec.message}'));
+  Logger.root.onRecord.listen((LogRecord rec) => print('${rec.level.name}: ${rec.time}: ${rec.message}'));
   Logger.root.level = Level.SHOUT;
 
   //////////////////////////////////////////////////////////////////////
   // Define schema in code
   //////////////////////////////////////////////////////////////////////
-  var mustBeIntegerSchema = {
-    "type" : "integer"
-  };
+  var mustBeIntegerSchema = {"type": "integer"};
 
   var n = 3;
   var decimals = 3.14;
   var str = 'hi';
 
-  Schema.createSchema(mustBeIntegerSchema)
-    .then((schema) {
-      print('$n => ${schema.validate(n)}');
-      print('$decimals => ${schema.validate(decimals)}');
-      print('$str => ${schema.validate(str)}');
-    });
-
+  Schema.createSchema(mustBeIntegerSchema).then((schema) {
+    print('$n => ${schema.validate(n)}');
+    print('$decimals => ${schema.validate(decimals)}');
+    print('$str => ${schema.validate(str)}');
+  });
 }
diff --git a/json_schema/example/from_url/validate_instance_from_url.dart b/json_schema/example/from_url/validate_instance_from_url.dart
index a9a2934..67b4d0c 100644
--- a/json_schema/example/from_url/validate_instance_from_url.dart
+++ b/json_schema/example/from_url/validate_instance_from_url.dart
@@ -1,45 +1,76 @@
 #!/usr/bin/env dart
+// Copyright 2013-2018 Workiva Inc.
+//
+// Licensed under the Boost Software License (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.boost.org/LICENSE_1_0.txt
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// This software or document includes material copied from or derived
+// from JSON-Schema-Test-Suite (https://github.com/json-schema-org/JSON-Schema-Test-Suite),
+// Copyright (c) 2012 Julian Berman, which is licensed under the following terms:
+//
+//     Copyright (c) 2012 Julian Berman
+//
+//     Permission is hereby granted, free of charge, to any person obtaining a copy
+//     of this software and associated documentation files (the "Software"), to deal
+//     in the Software without restriction, including without limitation the rights
+//     to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+//     copies of the Software, and to permit persons to whom the Software is
+//     furnished to do so, subject to the following conditions:
+//
+//     The above copyright notice and this permission notice shall be included in
+//     all copies or substantial portions of the Software.
+//
+//     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+//     IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+//     FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+//     AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+//     LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+//     OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+//     THE SOFTWARE.
 
 import "dart:convert" as convert;
 import "package:json_schema/json_schema.dart";
 import "package:logging/logging.dart";
 
 main() {
-
-  Logger.root.onRecord.listen((LogRecord rec) =>
-    print('${rec.level.name}: ${rec.time}: ${rec.message}'));
+  Logger.root.onRecord.listen((LogRecord rec) => print('${rec.level.name}: ${rec.time}: ${rec.message}'));
   Logger.root.level = Level.SHOUT;
 
   //////////////////////////////////////////////////////////////////////
   // Pull in schema from web
   //////////////////////////////////////////////////////////////////////
   String url = "http://json-schema.org/draft-04/schema";
-  Schema.createSchemaFromUrl(url)
-    .then((Schema schema) {
+  Schema.createSchemaFromUrl(url).then((Schema schema) {
+    // TODO: Figure out the redirect issues here
+    //   if(false) {
+    //     print('''Does schema validate itself?
+    //       ${schema.validate(schema.schemaMap)}''');
+    //   }
 
-      // TODO: Figure out the redirect issues here
-      if(false) {
-        print('''Does schema validate itself?
-          ${schema.validate(schema.schemaMap)}''');
-      }
-
-      var validSchema = { "type" : "integer" };
-      print('''Does schema validate valid schema $validSchema?
+    var validSchema = {"type": "integer"};
+    print('''Does schema validate valid schema $validSchema?
   ${schema.validate(validSchema)}''');
 
-      var invalidSchema = { "type" : "nibble" };
-      print('''Does schema validate invalid schema $invalidSchema?
+    var invalidSchema = {"type": "nibble"};
+    print('''Does schema validate invalid schema $invalidSchema?
   ${schema.validate(invalidSchema)}''');
-
-    });
+  });
 
   //////////////////////////////////////////////////////////////////////
   // Pull in schema from file in current directory
   //////////////////////////////////////////////////////////////////////
   url = "grades_schema.json";
-  Schema.createSchemaFromUrl(url)
-    .then((schema) {
-      var grades = convert.JSON.decode('''
+  Schema.createSchemaFromUrl(url).then((schema) {
+    var grades = convert.JSON.decode('''
 {
     "semesters": [
         {
@@ -64,7 +95,7 @@
       ]
 }''');
 
-      print('''Does grades schema validate $grades
+    print('''Does grades schema validate $grades
   ${schema.validate(grades)}''');
-    });
+  });
 }
diff --git a/json_schema/lib/json_schema.dart b/json_schema/lib/json_schema.dart
index a5fcd99..ed49845 100644
--- a/json_schema/lib/json_schema.dart
+++ b/json_schema/lib/json_schema.dart
@@ -1,3 +1,41 @@
+// Copyright 2013-2018 Workiva Inc.
+//
+// Licensed under the Boost Software License (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.boost.org/LICENSE_1_0.txt
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// This software or document includes material copied from or derived
+// from JSON-Schema-Test-Suite (https://github.com/json-schema-org/JSON-Schema-Test-Suite),
+// Copyright (c) 2012 Julian Berman, which is licensed under the following terms:
+//
+//     Copyright (c) 2012 Julian Berman
+//
+//     Permission is hereby granted, free of charge, to any person obtaining a copy
+//     of this software and associated documentation files (the "Software"), to deal
+//     in the Software without restriction, including without limitation the rights
+//     to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+//     copies of the Software, and to permit persons to whom the Software is
+//     furnished to do so, subject to the following conditions:
+//
+//     The above copyright notice and this permission notice shall be included in
+//     all copies or substantial portions of the Software.
+//
+//     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+//     IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+//     FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+//     AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+//     LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+//     OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+//     THE SOFTWARE.
+
 /// Support for validating json instances against a json schema
 library json_schema.json_schema;
 
@@ -31,8 +69,7 @@
 
   static const SchemaType STRING = const SchemaType._(6);
 
-  static List<SchemaType> get values =>
-      const <SchemaType>[ARRAY, BOOLEAN, INTEGER, NUMBER, NULL, OBJECT, STRING];
+  static List<SchemaType> get values => const <SchemaType>[ARRAY, BOOLEAN, INTEGER, NUMBER, NULL, OBJECT, STRING];
 
   final int value;
 
diff --git a/json_schema/lib/schema_dot.dart b/json_schema/lib/schema_dot.dart
index 90d8c9d..487bcdc 100644
--- a/json_schema/lib/schema_dot.dart
+++ b/json_schema/lib/schema_dot.dart
@@ -1,3 +1,41 @@
+// Copyright 2013-2018 Workiva Inc.
+//
+// Licensed under the Boost Software License (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.boost.org/LICENSE_1_0.txt
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// This software or document includes material copied from or derived
+// from JSON-Schema-Test-Suite (https://github.com/json-schema-org/JSON-Schema-Test-Suite),
+// Copyright (c) 2012 Julian Berman, which is licensed under the following terms:
+//
+//     Copyright (c) 2012 Julian Berman
+//
+//     Permission is hereby granted, free of charge, to any person obtaining a copy
+//     of this software and associated documentation files (the "Software"), to deal
+//     in the Software without restriction, including without limitation the rights
+//     to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+//     copies of the Software, and to permit persons to whom the Software is
+//     furnished to do so, subject to the following conditions:
+//
+//     The above copyright notice and this permission notice shall be included in
+//     all copies or substantial portions of the Software.
+//
+//     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+//     IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+//     FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+//     AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+//     LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+//     OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+//     THE SOFTWARE.
+
 /// Functionality to create Graphviz input dot file from schema
 library json_schema.schema_dot;
 
@@ -51,14 +89,11 @@
     var schemaTypeList = schema.schemaTypeList;
     if (schemaTypeList == null) {
       if (schema.oneOf.length > 0) {
-        result =
-            "oneOf:${schema.oneOf.map((schema) => schemaType(schema)).toList()}";
+        result = "oneOf:${schema.oneOf.map((schema) => schemaType(schema)).toList()}";
       } else if (schema.anyOf.length > 0) {
-        result =
-            "anyOf:${schema.anyOf.map((schema) => schemaType(schema)).toList()}";
+        result = "anyOf:${schema.anyOf.map((schema) => schemaType(schema)).toList()}";
       } else if (schema.allOf.length > 0) {
-        result =
-            "allOf:${schema.allOf.map((schema) => schemaType(schema)).toList()}";
+        result = "allOf:${schema.allOf.map((schema) => schemaType(schema)).toList()}";
       } else if (schema.defaultValue != null) {
         result = "default=${schema.defaultValue}";
       } else if (schema.ref != null) {
@@ -151,8 +186,7 @@
       schema.anyOf.forEach((anyOfSchema) {
         String port = "${i++}";
         makeSchemaLink(port, schema, anyOfSchema);
-        anyOf.add(wrap(abbreviatedString("${schemaType(anyOfSchema)}", 30),
-            color: 'grey', port: port));
+        anyOf.add(wrap(abbreviatedString("${schemaType(anyOfSchema)}", 30), color: 'grey', port: port));
       });
     }
     return anyOf;
@@ -166,8 +200,7 @@
       schema.oneOf.forEach((oneOfSchema) {
         String port = "${i++}";
         makeSchemaLink(port, schema, oneOfSchema);
-        oneOf.add(wrap(abbreviatedString("${schemaType(oneOfSchema)}", 30),
-            color: 'grey', port: port));
+        oneOf.add(wrap(abbreviatedString("${schemaType(oneOfSchema)}", 30), color: 'grey', port: port));
       });
     }
     return oneOf;
@@ -181,8 +214,7 @@
       schema.allOf.forEach((allOfSchema) {
         String port = "${i++}";
         makeSchemaLink(port, schema, allOfSchema);
-        allOf.add(wrap(abbreviatedString("${schemaType(allOfSchema)}", 30),
-            color: 'grey', port: port));
+        allOf.add(wrap(abbreviatedString("${schemaType(allOfSchema)}", 30), color: 'grey', port: port));
       });
     }
     return allOf;
@@ -213,9 +245,7 @@
   makeSchemaPort(String port, Schema schema) => '"${schema.path}":"$port"';
 
   makeSchemaLink(String port, Schema src, Schema target) {
-    if (schemaShown(target))
-      links.add(
-          '${makeSchemaPort(port, src)} -> ${makeSchemaPort("@path", target)}');
+    if (schemaShown(target)) links.add('${makeSchemaPort(port, src)} -> ${makeSchemaPort("@path", target)}');
   }
 
   List<String> get additionalPropertiesSchema {
@@ -225,8 +255,7 @@
       result.add(wrap('Additional Properties', color: 'lemonchiffon'));
       String port = "mustBe";
       makeSchemaLink(port, schema, other);
-      result.add(wrapRowDistinct('Must Be: ',
-          abbreviatedString(schemaType(other).toString(), 30), port));
+      result.add(wrapRowDistinct('Must Be: ', abbreviatedString(schemaType(other).toString(), 30), port));
     }
     return result;
   }
@@ -242,14 +271,11 @@
         String port = "@$prop";
         if (schemaShown(propertySchema)) {
           makeSchemaLink(port, schema, propertySchema);
-        } else if (propertySchema.items is Schema &&
-            schemaShown(propertySchema.items)) {
+        } else if (propertySchema.items is Schema && schemaShown(propertySchema.items)) {
           makeSchemaLink(port, schema, propertySchema.items);
         }
         props.add(wrapRowDistinct(
-            "$requiredPrefix$prop",
-            abbreviatedString(schemaType(propertySchema).toString(), 30),
-            port));
+            "$requiredPrefix$prop", abbreviatedString(schemaType(propertySchema).toString(), 30), port));
       });
     }
     return props;
@@ -258,8 +284,8 @@
   List<String> get definitionEntries {
     List<String> definitions = [];
     if (schema.definitions.length > 0) {
-      definitions.add(
-          '<tr><td bgcolor="wheat" align="center" colspan="2"><font color="black">Definitions</font></td></tr>');
+      definitions
+          .add('<tr><td bgcolor="wheat" align="center" colspan="2"><font color="black">Definitions</font></td></tr>');
       var sortedDefinitions = new List.from(schema.definitions.keys)..sort();
       sortedDefinitions.forEach((key) {
         definitions.add(wrapRowDistinct(key, '', "${schema.path}@$key"));
@@ -275,13 +301,9 @@
   String wrapRowDistinct(String first, String second, [String port = '']) =>
       '<tr><td align="left" port="$port">$first</td>$first<td bgcolor="grey" align="right">$second</td></tr>';
 
-  String get title => schema.title != null
-      ? abbreviatedString("title=${schema.title}", 30)
-      : null;
+  String get title => schema.title != null ? abbreviatedString("title=${schema.title}", 30) : null;
 
-  String get description => schema.description != null
-      ? abbreviatedString("descr=${schema.description}", 30)
-      : null;
+  String get description => schema.description != null ? abbreviatedString("descr=${schema.description}", 30) : null;
 
   String abbreviatedString(String s, [int len = 15]) {
     if (s == null) return s;
diff --git a/json_schema/lib/src/json_schema/schema.dart b/json_schema/lib/src/json_schema/schema.dart
index 8270071..3fcf953 100644
--- a/json_schema/lib/src/json_schema/schema.dart
+++ b/json_schema/lib/src/json_schema/schema.dart
@@ -1,3 +1,41 @@
+// Copyright 2013-2018 Workiva Inc.
+//
+// Licensed under the Boost Software License (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.boost.org/LICENSE_1_0.txt
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// This software or document includes material copied from or derived
+// from JSON-Schema-Test-Suite (https://github.com/json-schema-org/JSON-Schema-Test-Suite),
+// Copyright (c) 2012 Julian Berman, which is licensed under the following terms:
+//
+//     Copyright (c) 2012 Julian Berman
+//
+//     Permission is hereby granted, free of charge, to any person obtaining a copy
+//     of this software and associated documentation files (the "Software"), to deal
+//     in the Software without restriction, including without limitation the rights
+//     to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+//     copies of the Software, and to permit persons to whom the Software is
+//     furnished to do so, subject to the following conditions:
+//
+//     The above copyright notice and this permission notice shall be included in
+//     all copies or substantial portions of the Software.
+//
+//     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+//     IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+//     FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+//     AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+//     LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+//     OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+//     THE SOFTWARE.
+
 part of json_schema.json_schema;
 
 /// Constructed with a json schema, either as string or Map. Validation of
@@ -75,10 +113,7 @@
         request.followRedirects = true;
         return request.close();
       }).then((HttpClientResponse response) {
-        return response
-            .transform(new convert.Utf8Decoder())
-            .join()
-            .then((schemaText) {
+        return response.transform(new convert.Utf8Decoder()).join().then((schemaText) {
           Map map = convert.JSON.decode(schemaText);
           return createSchema(map);
         });
@@ -88,15 +123,13 @@
           .readAsString()
           .then((text) => createSchema(convert.JSON.decode(text)));
     } else {
-      throw new FormatException(
-          "Url schemd must be http, file, or empty: $schemaUrl");
+      throw new FormatException("Url schemd must be http, file, or empty: $schemaUrl");
     }
   }
 
   /// Create a schema from a [data]
   ///  Typically [data] is result of JSON.decode(jsonSchemaString)
-  static Future<Schema> createSchema(Map data) =>
-      new Schema._fromRootMap(data)._thisCompleter.future;
+  static Future<Schema> createSchema(Map data) => new Schema._fromRootMap(data)._thisCompleter.future;
 
   /// Validate [instance] against this schema
   bool validate(dynamic instance) => new Validator(this).validate(instance);
@@ -104,8 +137,7 @@
   bool get exclusiveMaximum => _exclusiveMaximum == null || _exclusiveMaximum;
   bool get exclusiveMinimum => _exclusiveMinimum == null || _exclusiveMinimum;
 
-  bool propertyRequired(String property) =>
-      _requiredProperties != null && _requiredProperties.contains(property);
+  bool propertyRequired(String property) => _requiredProperties != null && _requiredProperties.contains(property);
 
   /// Given path, follow all references to an end path pointing to schema
   String endPath(String path) {
@@ -124,20 +156,13 @@
     return _refMap[path];
   }
 
-  FormatException _boolError(String key, dynamic instance) =>
-      _error("$key must be boolean: $instance");
-  FormatException _numError(String key, dynamic instance) =>
-      _error("$key must be num: $instance");
-  FormatException _intError(String key, dynamic instance) =>
-      _error("$key must be int: $instance");
-  FormatException _stringError(String key, dynamic instance) =>
-      _error("$key must be string: $instance");
-  FormatException _objectError(String key, dynamic instance) =>
-      _error("$key must be object: $instance");
-  FormatException _arrayError(String key, dynamic instance) =>
-      _error("$key must be array: $instance");
-  FormatException _schemaError(String key, dynamic instance) =>
-      _error("$key must be valid schema object: $instance");
+  FormatException _boolError(String key, dynamic instance) => _error("$key must be boolean: $instance");
+  FormatException _numError(String key, dynamic instance) => _error("$key must be num: $instance");
+  FormatException _intError(String key, dynamic instance) => _error("$key must be int: $instance");
+  FormatException _stringError(String key, dynamic instance) => _error("$key must be string: $instance");
+  FormatException _objectError(String key, dynamic instance) => _error("$key must be object: $instance");
+  FormatException _arrayError(String key, dynamic instance) => _error("$key must be array: $instance");
+  FormatException _schemaError(String key, dynamic instance) => _error("$key must be valid schema object: $instance");
 
   FormatException _error(String msg) {
     msg = "$_path: $msg";
@@ -188,10 +213,8 @@
     _exclusiveMinimum = value;
   }
 
-  _getMaxLength(dynamic value) =>
-      _maxLength = _requireNonNegativeInt('maxLength', value);
-  _getMinLength(dynamic value) =>
-      _minLength = _requireNonNegativeInt('minLength', value);
+  _getMaxLength(dynamic value) => _maxLength = _requireNonNegativeInt('maxLength', value);
+  _getMinLength(dynamic value) => _minLength = _requireNonNegativeInt('minLength', value);
 
   _getPattern(dynamic value) {
     if (value is! String) throw _stringError("pattern", value);
@@ -209,10 +232,8 @@
 
   _getProperties(dynamic value) {
     if (value is Map) {
-      value.forEach((property, subSchema) => _makeSchema(
-          "$_path/properties/$property",
-          subSchema,
-          (rhs) => _properties[property] = rhs));
+      value.forEach((property, subSchema) =>
+          _makeSchema("$_path/properties/$property", subSchema, (rhs) => _properties[property] = rhs));
     } else {
       throw _objectError("properties", value);
     }
@@ -225,8 +246,7 @@
       int index = 0;
       _itemsList = new List(value.length);
       for (int i = 0; i < value.length; i++) {
-        _makeSchema(
-            "$_path/items/${index++}", value[i], (rhs) => _itemsList[i] = rhs);
+        _makeSchema("$_path/items/${index++}", value[i], (rhs) => _itemsList[i] = rhs);
       }
     } else {
       throw _error("items must be object or array: $value");
@@ -237,17 +257,14 @@
     if (value is bool) {
       _additionalItems = value;
     } else if (value is Map) {
-      _makeSchema(
-          "$_path/additionalItems", value, (rhs) => _additionalItems = rhs);
+      _makeSchema("$_path/additionalItems", value, (rhs) => _additionalItems = rhs);
     } else {
       throw _error("additionalItems must be boolean or object: $value");
     }
   }
 
-  _getMaxItems(dynamic value) =>
-      _maxItems = _requireNonNegativeInt('maxItems', value);
-  _getMinItems(dynamic value) =>
-      _minItems = _requireNonNegativeInt('minItems', value);
+  _getMaxItems(dynamic value) => _maxItems = _requireNonNegativeInt('maxItems', value);
+  _getMinItems(dynamic value) => _minItems = _requireNonNegativeInt('minItems', value);
   _getUniqueItems(dynamic value) {
     if (value is! bool) throw _boolError("uniqueItems", value);
     _uniqueItems = value;
@@ -255,50 +272,42 @@
 
   _getRequired(dynamic value) {
     if (value is! List) throw _arrayError("required", value);
-    if (value.length == 0)
-      throw _error("required must be a non-empty array: $value");
+    if (value.length == 0) throw _error("required must be a non-empty array: $value");
     _requiredProperties = new List.from(value);
   }
 
-  _getMaxProperties(dynamic value) =>
-      _maxProperties = _requireNonNegativeInt('maxProperties', value);
-  _getMinProperties(dynamic value) =>
-      _minProperties = _requireNonNegativeInt('minProperties', value);
+  _getMaxProperties(dynamic value) => _maxProperties = _requireNonNegativeInt('maxProperties', value);
+  _getMinProperties(dynamic value) => _minProperties = _requireNonNegativeInt('minProperties', value);
   _getAdditionalProperties(dynamic value) {
     if (value is bool) {
       _additionalProperties = value;
     } else if (value is Map) {
-      _makeSchema("$_path/additionalProperties", value,
-          (rhs) => _additionalPropertiesSchema = rhs);
+      _makeSchema("$_path/additionalProperties", value, (rhs) => _additionalPropertiesSchema = rhs);
     } else {
-      throw _error(
-          "additionalProperties must be a bool or valid schema object: $value");
+      throw _error("additionalProperties must be a bool or valid schema object: $value");
     }
   }
 
   _getPatternProperties(dynamic value) {
     if (value is! Map) throw _objectError("patternProperties", value);
 
-    value.forEach((k, v) => _makeSchema("$_path/patternProperties/$k", v,
-        (rhs) => _patternProperties[new RegExp(k)] = rhs));
+    value.forEach(
+        (k, v) => _makeSchema("$_path/patternProperties/$k", v, (rhs) => _patternProperties[new RegExp(k)] = rhs));
   }
 
   _getDependencies(dynamic value) {
     if (value is Map) {
       value.forEach((k, v) {
         if (v is Map) {
-          _makeSchema("$_path/dependencies/$k", v,
-              (rhs) => _schemaDependencies[k] = rhs);
+          _makeSchema("$_path/dependencies/$k", v, (rhs) => _schemaDependencies[k] = rhs);
         } else if (v is List) {
-          if (v.length == 0)
-            throw _error("property dependencies must be non-empty array");
+          if (v.length == 0) throw _error("property dependencies must be non-empty array");
 
           Set uniqueDeps = new Set();
           v.forEach((propDep) {
             if (propDep is! String) throw _stringError("propertyDependency", v);
 
-            if (uniqueDeps.contains(propDep))
-              throw _error("property dependencies must be unique: $v");
+            if (uniqueDeps.contains(propDep)) throw _error("property dependencies must be unique: $v");
 
             _propertyDependencies.putIfAbsent(k, () => []).add(propDep);
             uniqueDeps.add(propDep);
@@ -314,13 +323,11 @@
 
   _getEnum(dynamic value) {
     if (value is List) {
-      if (value.length == 0)
-        throw _error("enum must be a non-empty array: $value");
+      if (value.length == 0) throw _error("enum must be a non-empty array: $value");
       int i = 0;
       value.forEach((v) {
         for (int j = i + 1; j < value.length; j++) {
-          if (_jsonEqual(value[i], value[j]))
-            throw _error("enum values must be unique: $value [$i]==[$j]");
+          if (_jsonEqual(value[i], value[j])) throw _error("enum values must be unique: $value [$i]==[$j]");
         }
         i++;
         _enumValues.add(v);
@@ -352,12 +359,9 @@
     }
   }
 
-  _getAllOf(dynamic value) =>
-      _requireListOfSchema("allOf", value, (schema) => _allOf.add(schema));
-  _getAnyOf(dynamic value) =>
-      _requireListOfSchema("anyOf", value, (schema) => _anyOf.add(schema));
-  _getOneOf(dynamic value) =>
-      _requireListOfSchema("oneOf", value, (schema) => _oneOf.add(schema));
+  _getAllOf(dynamic value) => _requireListOfSchema("allOf", value, (schema) => _allOf.add(schema));
+  _getAnyOf(dynamic value) => _requireListOfSchema("anyOf", value, (schema) => _anyOf.add(schema));
+  _getOneOf(dynamic value) => _requireListOfSchema("oneOf", value, (schema) => _oneOf.add(schema));
   _getNot(dynamic value) {
     if (value is Map) {
       _makeSchema("$_path/not", value, (rhs) => _notSchema = rhs);
@@ -368,8 +372,7 @@
 
   _getDefinitions(dynamic value) {
     if (value is Map) {
-      value.forEach((k, v) => _makeSchema(
-          "$_path/definitions/$k", v, (rhs) => _definitions[k] = rhs));
+      value.forEach((k, v) => _makeSchema("$_path/definitions/$k", v, (rhs) => _definitions[k] = rhs));
     } else {
       throw _objectError("definition", value);
     }
@@ -380,8 +383,7 @@
       _ref = value;
       if (_ref.length == 0) throw _error("\$ref must be non-empty string");
       if (_ref[0] != '#') {
-        var refSchemaFuture = createSchemaFromUrl(_ref)
-            .then((schema) => _addSchema(_ref, schema));
+        var refSchemaFuture = createSchemaFromUrl(_ref).then((schema) => _addSchema(_ref, schema));
         _retrievalRequests.add(refSchemaFuture);
       }
     } else {
@@ -413,8 +415,7 @@
   }
 
   _getTitle(dynamic value) => _title = _requireString("title", value);
-  _getDescription(dynamic value) =>
-      _description = _requireString("description", value);
+  _getDescription(dynamic value) => _description = _requireString("description", value);
   _getDefault(dynamic value) => _defaultValue = value;
   _getFormat(dynamic value) {
     _format = _requireString("format", value);
@@ -473,18 +474,14 @@
       }
     });
 
-    if (_exclusiveMinimum != null && _minimum == null)
-      throw _error("exclusiveMinimum requires minimum");
+    if (_exclusiveMinimum != null && _minimum == null) throw _error("exclusiveMinimum requires minimum");
 
-    if (_exclusiveMaximum != null && _maximum == null)
-      throw _error("exclusiveMaximum requires maximum");
+    if (_exclusiveMaximum != null && _maximum == null) throw _error("exclusiveMaximum requires maximum");
 
     if (_root == this) {
       _schemaAssignments.forEach((assignment) => assignment());
       if (_retrievalRequests.isNotEmpty) {
-        Future
-            .wait(_retrievalRequests)
-            .then((_) => _thisCompleter.complete(_resolvePath('#')));
+        Future.wait(_retrievalRequests).then((_) => _thisCompleter.complete(_resolvePath('#')));
       } else {
         _thisCompleter.complete(_resolvePath('#'));
       }
@@ -512,8 +509,7 @@
   }
 
   String _endPath(String path) {
-    if (_pathsEncountered.contains(path))
-      throw _error("Encountered path cycle ${_pathsEncountered}, adding $path");
+    if (_pathsEncountered.contains(path)) throw _error("Encountered path cycle ${_pathsEncountered}, adding $path");
 
     var referredTo = _schemaRefs[path];
     if (referredTo == null) {
@@ -529,8 +525,7 @@
     Schema result = _refMap[path];
     if (result == null) {
       var schema = _freeFormMap[path];
-      if (schema is! Map)
-        throw _schemaError("free-form property $original at $path", schema);
+      if (schema is! Map) throw _schemaError("free-form property $original at $path", schema);
       return new Schema._fromMap(_root, schema, path);
     }
     return result;
@@ -552,8 +547,7 @@
     return false;
   }
 
-  static String _normalizePath(String path) =>
-      path.replaceAll('~', '~0').replaceAll('/', '~1').replaceAll('%', '%25');
+  static String _normalizePath(String path) => path.replaceAll('~', '~0').replaceAll('/', '~1').replaceAll('%', '%25');
 
   Schema _createSubSchema(dynamic schemaDefinition, String path) {
     assert(!_schemaRefs.containsKey(path));
diff --git a/json_schema/lib/src/json_schema/validator.dart b/json_schema/lib/src/json_schema/validator.dart
index 93e3528..5dedd7d 100644
--- a/json_schema/lib/src/json_schema/validator.dart
+++ b/json_schema/lib/src/json_schema/validator.dart
@@ -1,3 +1,41 @@
+// Copyright 2013-2018 Workiva Inc.
+//
+// Licensed under the Boost Software License (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.boost.org/LICENSE_1_0.txt
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// This software or document includes material copied from or derived
+// from JSON-Schema-Test-Suite (https://github.com/json-schema-org/JSON-Schema-Test-Suite),
+// Copyright (c) 2012 Julian Berman, which is licensed under the following terms:
+//
+//     Copyright (c) 2012 Julian Berman
+//
+//     Permission is hereby granted, free of charge, to any person obtaining a copy
+//     of this software and associated documentation files (the "Software"), to deal
+//     in the Software without restriction, including without limitation the rights
+//     to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+//     copies of the Software, and to permit persons to whom the Software is
+//     furnished to do so, subject to the following conditions:
+//
+//     The above copyright notice and this permission notice shall be included in
+//     all copies or substantial portions of the Software.
+//
+//     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+//     IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+//     FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+//     AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+//     LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+//     OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+//     THE SOFTWARE.
+
 part of json_schema.json_schema;
 
 /// Initialized with schema, validates instances against it
@@ -10,8 +48,7 @@
 
   /// Validate the [instance] against the this validator's schema
   bool validate(dynamic instance, [bool reportMultipleErrors = false]) {
-    _logger
-        .info("Validating ${instance.runtimeType}:$instance on ${_rootSchema}");
+    _logger.info("Validating ${instance.runtimeType}:$instance on ${_rootSchema}");
 
     _reportMultipleErrors = reportMultipleErrors;
     _errors = [];
@@ -194,8 +231,7 @@
 
   void _validateAnyOf(Schema schema, instance) {
     if (!schema._anyOf.any((s) => new Validator(s).validate(instance))) {
-      _err(
-          "${schema._path}/anyOf: anyOf violated ($instance, ${schema._anyOf})");
+      _err("${schema._path}/anyOf: anyOf violated ($instance, ${schema._anyOf})");
     }
   }
 
@@ -226,8 +262,7 @@
         break;
       case 'uri':
         {
-          var isValid =
-              (_uriValidator != null) ? _uriValidator : _defaultUriValidator;
+          var isValid = (_uriValidator != null) ? _uriValidator : _defaultUriValidator;
 
           if (!isValid(instance)) {
             _err("'uri' format not accepted $instance");
@@ -236,9 +271,7 @@
         break;
       case 'email':
         {
-          var isValid = (_emailValidator != null)
-              ? _emailValidator
-              : _defaultEmailValidator;
+          var isValid = (_emailValidator != null) ? _emailValidator : _defaultEmailValidator;
 
           if (!isValid(instance)) {
             _err("'email' format not accepted $instance");
@@ -274,8 +307,7 @@
   }
 
   void _objectPropertyValidation(Schema schema, Map instance) {
-    bool propMustValidate =
-        schema._additionalProperties != null && !schema._additionalProperties;
+    bool propMustValidate = schema._additionalProperties != null && !schema._additionalProperties;
 
     instance.forEach((k, v) {
       bool propCovered = false;
@@ -329,27 +361,22 @@
     int minProps = schema._minProperties;
     int maxProps = schema._maxProperties;
     if (numProps < minProps) {
-      _err(
-          "${schema._path}: minProperties violated (${numProps} < ${minProps})");
+      _err("${schema._path}: minProperties violated (${numProps} < ${minProps})");
     } else if (maxProps != null && numProps > maxProps) {
-      _err(
-          "${schema._path}: maxProperties violated (${numProps} > ${maxProps})");
+      _err("${schema._path}: maxProperties violated (${numProps} > ${maxProps})");
     }
     if (schema._requiredProperties != null) {
       schema._requiredProperties.forEach((prop) {
         if (!instance.containsKey(prop)) {
-          _err(
-              "${schema._path}: required prop missing: ${prop} from $instance");
+          _err("${schema._path}: required prop missing: ${prop} from $instance");
         }
       });
     }
     _objectPropertyValidation(schema, instance);
 
-    if (schema._propertyDependencies != null)
-      _propertyDependenciesValidation(schema, instance);
+    if (schema._propertyDependencies != null) _propertyDependenciesValidation(schema, instance);
 
-    if (schema._schemaDependencies != null)
-      _schemaDependenciesValidation(schema, instance);
+    if (schema._schemaDependencies != null) _schemaDependenciesValidation(schema, instance);
   }
 
   void _validate(Schema schema, dynamic instance) {
@@ -385,8 +412,7 @@
 RegExp _emailRe = new RegExp(r'^[_A-Za-z0-9-\+]+(\.[_A-Za-z0-9-]+)*'
     r'@'
     r'[A-Za-z0-9-]+(\.[A-Za-z0-9]+)*(\.[A-Za-z]{2,})$');
-var _defaultEmailValidator =
-    (String email) => _emailRe.firstMatch(email) != null;
+var _defaultEmailValidator = (String email) => _emailRe.firstMatch(email) != null;
 var _emailValidator = _defaultEmailValidator;
 RegExp _ipv4Re = new RegExp(r'^(\d|[1-9]\d|1\d\d|2([0-4]\d|5[0-5]))\.'
     r'(\d|[1-9]\d|1\d\d|2([0-4]\d|5[0-5]))\.'
@@ -419,6 +445,7 @@
     return false;
   }
 }
+
 RegExp _hostnameRe = new RegExp(r'^(?=.{1,255}$)'
     r'[0-9A-Za-z](?:(?:[0-9A-Za-z]|-){0,61}[0-9A-Za-z])?'
     r'(?:\.[0-9A-Za-z](?:(?:[0-9A-Za-z]|-){0,61}[0-9A-Za-z])?)*\.?$');
diff --git a/json_schema/pubspec.yaml b/json_schema/pubspec.yaml
index 277557b..d7a14c5 100644
--- a/json_schema/pubspec.yaml
+++ b/json_schema/pubspec.yaml
@@ -1,39 +1,24 @@
 name: json_schema
-version: 1.0.7
-author: Daniel Davidson <dbdavidson@yahoo.com>
-homepage: https://github.com/patefacio/json_schema
+version: 1.0.8
+
+authors:
+  - Michael Carter <michael.carter@workiva.com>
+  - Daniel Davidson <dbdavidson@yahoo.com>
+  
+homepage: https://github.com/workiva/json_schema
 description: >
   Provide support for validating instances against json schema
 environment:
-  sdk: '>=1.8.2 <2.0.0'
+  sdk: ">=1.8.2 <2.0.0"
 
 dependencies:
-
-# custom <json_schema dependencies>
-
-  path: "^1.3.0"
-  logging: ">=0.9.3<0.12.0"
   args: ">=0.11.0 <2.0.0"
-
-# end <json_schema dependencies>
+  logging: ">=0.9.3<0.12.0"
+  path: "^1.3.0"
 
 dev_dependencies:
-
-# custom <json_schema dev dependencies>
-
-  test: "^0.12.13"
-  yaml: "^2.1.0"
   coverage: ">=0.7.6"
-
-# end <json_schema dev dependencies>
-
-dependency_overrides:
-# custom <json_schema dependency overrides>
-
-# end <json_schema dependency overrides>
-
-transformers:
-
-# custom <json_schema transformers>
-# end <json_schema transformers>
-
+  dart_dev: any
+  dart_style: any
+  dependency_validator: ^1.0.0
+  test: "^0.12.13"
diff --git a/json_schema/smithy.yaml b/json_schema/smithy.yaml
new file mode 100644
index 0000000..b9debae
--- /dev/null
+++ b/json_schema/smithy.yaml
@@ -0,0 +1,12 @@
+project: dart
+language: dart
+
+# dart 1.24.2
+runner_image: drydock-prod.workiva.net/workiva/smithy-runner-generator:179735
+
+script:
+  - pub get
+
+artifacts:
+  build:
+    - ./pubspec.lock
\ No newline at end of file
diff --git a/json_schema/tool/dev.dart b/json_schema/tool/dev.dart
new file mode 100644
index 0000000..c3c6044
--- /dev/null
+++ b/json_schema/tool/dev.dart
@@ -0,0 +1,68 @@
+// Copyright 2013-2018 Workiva Inc.
+//
+// Licensed under the Boost Software License (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.boost.org/LICENSE_1_0.txt
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// This software or document includes material copied from or derived
+// from JSON-Schema-Test-Suite (https://github.com/json-schema-org/JSON-Schema-Test-Suite),
+// Copyright (c) 2012 Julian Berman, which is licensed under the following terms:
+//
+//     Copyright (c) 2012 Julian Berman
+//
+//     Permission is hereby granted, free of charge, to any person obtaining a copy
+//     of this software and associated documentation files (the "Software"), to deal
+//     in the Software without restriction, including without limitation the rights
+//     to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+//     copies of the Software, and to permit persons to whom the Software is
+//     furnished to do so, subject to the following conditions:
+//
+//     The above copyright notice and this permission notice shall be included in
+//     all copies or substantial portions of the Software.
+//
+//     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+//     IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+//     FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+//     AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+//     LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+//     OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+//     THE SOFTWARE.
+
+import 'package:dart_dev/dart_dev.dart' show dev, config, TestRunnerConfig, Environment;
+
+main(List<String> args) async {
+  config.analyze
+    ..entryPoints = const ['bin/', 'lib/', 'test/', 'tool/']
+    ..fatalWarnings = true
+    ..strong = true;
+
+  config.copyLicense.directories = const ['bin/', 'example/', 'lib/', 'test/', 'tool/'];
+
+  config.coverage..reportOn = ['lib/'];
+
+  config.format
+    ..lineLength = 120
+    ..paths = const ['bin/', 'dot_samples/', 'example', 'lib/', 'test/', 'tool/'];
+
+  config.format.exclude = const [
+    'test/unit/generated_runner_test.dart',
+    'test/unit/browser/generated_runner_test.dart',
+    'test/unit/vm/generated_runner_test.dart',
+  ];
+
+  config.genTestRunner.configs = [
+    new TestRunnerConfig(directory: 'test/unit/vm', env: Environment.vm, filename: 'generated_runner_test'),
+  ];
+
+  config.test.unitTests = const ['test/unit/vm/generated_runner_test.dart'];
+
+  await dev(args);
+}
diff --git a/json_schema/tool/travis.sh b/json_schema/tool/travis.sh
deleted file mode 100755
index adc8fc7..0000000
--- a/json_schema/tool/travis.sh
+++ /dev/null
@@ -1,14 +0,0 @@
-#!/bin/bash
-
-# Fast fail the script on failures.
-set -e
-
-# Skipping this until at least we have a dev release that aligns with dart_style version
-# $(dirname -- "$0")/ensure_dartfmt.sh
-
-# Run the tests.
-dart test/runner.dart
-
-# Run the build.dart file - just to make sure it works
-$(dirname $(readlink -f `which dart`))/dartanalyzer lib/*.dart test/*.dart
-
diff --git a/multi_server_socket/.gitignore b/multi_server_socket/.gitignore
new file mode 100644
index 0000000..7dbf035
--- /dev/null
+++ b/multi_server_socket/.gitignore
@@ -0,0 +1,15 @@
+# Don’t commit the following directories created by pub.
+.buildlog
+.pub/
+build/
+packages
+.packages
+
+# Or the files created by dart2js.
+*.dart.js
+*.js_
+*.js.deps
+*.js.map
+
+# Include when developing application packages.
+pubspec.lock
\ No newline at end of file
diff --git a/multi_server_socket/.travis.yml b/multi_server_socket/.travis.yml
new file mode 100644
index 0000000..7882eed
--- /dev/null
+++ b/multi_server_socket/.travis.yml
@@ -0,0 +1,24 @@
+language: dart
+sudo: false
+
+dart:
+  - stable
+  - dev
+
+dart_task:
+  - test
+  - dartanalyzer
+  - dartfmt
+
+matrix:
+  include:
+  - dart: stable
+    dart_task: dartfmt
+
+# Only building master means that we don't run two builds for each pull request.
+branches:
+  only: [master]
+
+cache:
+  directories:
+    - $HOME/.pub-cache
diff --git a/multi_server_socket/BUILD.gn b/multi_server_socket/BUILD.gn
new file mode 100644
index 0000000..844ba49
--- /dev/null
+++ b/multi_server_socket/BUILD.gn
@@ -0,0 +1,15 @@
+# This file is generated by importer.py for multi_server_socket-1.0.1
+
+import("//build/dart/dart_library.gni")
+
+dart_library("multi_server_socket") {
+  package_name = "multi_server_socket"
+
+  source_dir = "lib"
+
+  disable_analysis = true
+
+  deps = [
+    "//third_party/dart-pkg/pub/async",
+  ]
+}
diff --git a/multi_server_socket/CHANGELOG.md b/multi_server_socket/CHANGELOG.md
new file mode 100644
index 0000000..3e7587d
--- /dev/null
+++ b/multi_server_socket/CHANGELOG.md
@@ -0,0 +1,7 @@
+## 1.0.1
+
+* Support `package:async` v2.
+
+## 1.0.0
+
+* Initial release.
diff --git a/multi_server_socket/LICENSE b/multi_server_socket/LICENSE
new file mode 100644
index 0000000..389ce98
--- /dev/null
+++ b/multi_server_socket/LICENSE
@@ -0,0 +1,26 @@
+Copyright 2017, the Dart project authors. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+    * Neither the name of Google Inc. nor the names of its
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/multi_server_socket/README.md b/multi_server_socket/README.md
new file mode 100644
index 0000000..012d1c4
--- /dev/null
+++ b/multi_server_socket/README.md
@@ -0,0 +1,23 @@
+An implementation of `dart:io`'s [ServerSocket][] that wraps multiple servers
+and forwards methods to all of them. It's useful for listening on multiple
+network interfaces while still having a unified way of controlling the servers.
+In particular, it supports serving on both the IPv4 and IPv6 loopback addresses
+using [MultiServerSocket.loopback][].
+
+```dart
+import 'package:multi_server_socket/multi_server_socket.dart';
+
+main() async {
+  // Sockets connecting to either http://127.0.0.1:8080 and http://[::1]:8080
+  // will be emitted by [server].
+  var server = await MultiServerSocket.loopback(8080);
+
+  server.listen((socket) {
+    // Communicate with [socket].
+  });
+}
+```
+
+[ServerSocket]: https://api.dartlang.org/apidocs/channels/stable/dartdoc-viewer/dart-io.ServerSocket
+
+[MultiServerSocket.loopback]: https://www.dartdocs.org/documentation/multi_server_socket/latest/multi_server_socket/MultiServerSocket-class.html
diff --git a/multi_server_socket/analysis_options.yaml b/multi_server_socket/analysis_options.yaml
new file mode 100644
index 0000000..a10d4c5
--- /dev/null
+++ b/multi_server_socket/analysis_options.yaml
@@ -0,0 +1,2 @@
+analyzer:
+  strong-mode: true
diff --git a/multi_server_socket/lib/multi_server_socket.dart b/multi_server_socket/lib/multi_server_socket.dart
new file mode 100644
index 0000000..90b7926
--- /dev/null
+++ b/multi_server_socket/lib/multi_server_socket.dart
@@ -0,0 +1,96 @@
+// 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:async';
+import 'dart:io';
+
+import 'package:async/async.dart';
+
+import 'src/utils.dart';
+
+/// The error code for an error caused by a port already being in use.
+final int _addressInUseErrno = () {
+  if (Platform.isWindows) return 10048;
+  if (Platform.isMacOS) return 48;
+  assert(Platform.isLinux);
+  return 98;
+}();
+
+/// An implementation of `dart:io`'s [ServerSocket] that wraps multiple servers
+/// and forwards methods to all of them.
+///
+/// This is useful for listening on multiple network interfaces while still
+/// having a unified way of controlling the servers. In particular, it supports
+/// serving on both the IPv4 and IPv6 loopback addresses using
+/// [MultiServerSocket.loopback].
+class MultiServerSocket extends StreamView<Socket> implements ServerSocket {
+  /// The wrapped servers.
+  final Set<ServerSocket> _servers;
+
+  /// Returns the port that one of the wrapped servers is listening on.
+  ///
+  /// If the wrapped servers are listening on different ports, it's not defined
+  /// which port is returned.
+  int get port => _servers.first.port;
+
+  /// Returns the address that one of the wrapped servers is listening on.
+  ///
+  /// If the wrapped servers are listening on different addresses, it's not
+  /// defined which address is returned.
+  InternetAddress get address => _servers.first.address;
+
+  /// Creates a [MultiServerSocket] wrapping [servers].
+  ///
+  /// None of the servers should be listened to when this is called.
+  MultiServerSocket(Iterable<ServerSocket> servers)
+      : _servers = servers.toSet(),
+        super(StreamGroup.merge(servers));
+
+  /// Creates a [ServerSocket] listening on all available loopback addresses for
+  /// this computer.
+  ///
+  /// See [ServerSocket.bind].
+  static Future<ServerSocket> loopback(int port,
+      {int backlog, bool v6Only: false, bool shared: false}) {
+    backlog ??= 0;
+
+    return _loopback(port, 5, backlog, v6Only, shared);
+  }
+
+  /// A helper method for initializing loopback servers.
+  static Future<ServerSocket> _loopback(int port, int remainingRetries,
+      int backlog, bool v6Only, bool shared) async {
+    if (!await supportsIPv4) {
+      return await ServerSocket.bind(InternetAddress.LOOPBACK_IP_V6, port,
+          backlog: backlog, v6Only: v6Only, shared: shared);
+    }
+
+    var v4Server = await ServerSocket.bind(InternetAddress.LOOPBACK_IP_V4, port,
+        backlog: backlog, v6Only: v6Only, shared: shared);
+    if (!await supportsIPv6) return v4Server;
+
+    try {
+      // Reuse the IPv4 server's port so that if [port] is 0, both servers use
+      // the same ephemeral port.
+      var v6Server = await ServerSocket.bind(
+          InternetAddress.LOOPBACK_IP_V6, v4Server.port,
+          backlog: backlog, v6Only: v6Only, shared: shared);
+      return new MultiServerSocket([v4Server, v6Server]);
+    } on SocketException catch (error) {
+      if (error.osError.errorCode != _addressInUseErrno) rethrow;
+      if (port != 0) rethrow;
+      if (remainingRetries == 0) rethrow;
+
+      // A port being available on IPv4 doesn't necessarily mean that the same
+      // port is available on IPv6. If it's not (which is rare in practice),
+      // we try again until we find one that's available on both.
+      v4Server.close();
+      return await _loopback(
+          port, remainingRetries - 1, backlog, v6Only, shared);
+    }
+  }
+
+  Future<ServerSocket> close() =>
+      Future.wait(_servers.map((server) => server.close())).then((_) => this);
+}
diff --git a/multi_server_socket/lib/src/utils.dart b/multi_server_socket/lib/src/utils.dart
new file mode 100644
index 0000000..21c335c
--- /dev/null
+++ b/multi_server_socket/lib/src/utils.dart
@@ -0,0 +1,28 @@
+// 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.
+
+import 'dart:async';
+import 'dart:io';
+
+/// Returns whether this computer supports binding to IPv6 addresses.
+final Future<bool> supportsIPv6 = () async {
+  try {
+    var socket = await ServerSocket.bind(InternetAddress.LOOPBACK_IP_V6, 0);
+    socket.close();
+    return true;
+  } on SocketException catch (_) {
+    return false;
+  }
+}();
+
+/// Returns whether this computer supports binding to IPv4 addresses.
+final Future<bool> supportsIPv4 = () async {
+  try {
+    var socket = await ServerSocket.bind(InternetAddress.LOOPBACK_IP_V4, 0);
+    socket.close();
+    return true;
+  } on SocketException catch (_) {
+    return false;
+  }
+}();
diff --git a/multi_server_socket/pubspec.yaml b/multi_server_socket/pubspec.yaml
new file mode 100644
index 0000000..d9bfc3c
--- /dev/null
+++ b/multi_server_socket/pubspec.yaml
@@ -0,0 +1,12 @@
+name: multi_server_socket
+version: 1.0.1
+author: "Dart Team <misc@dartlang.org>"
+homepage: http://github.com/dart-lang/multi_server_socket
+description:
+  A dart:io ServerSocket wrapper that listens on multiple ports.
+dependencies:
+  async: ">=1.2.0 <3.0.0"
+dev_dependencies:
+  test: "^0.12.0"
+environment:
+  sdk: ">=1.13.0 <2.0.0"
diff --git a/protobuf/BUILD.gn b/protobuf/BUILD.gn
index 15a2f0e..79b61b0 100644
--- a/protobuf/BUILD.gn
+++ b/protobuf/BUILD.gn
@@ -1,4 +1,4 @@
-# This file is generated by importer.py for protobuf-0.5.5
+# This file is generated by importer.py for protobuf-0.7.0
 
 import("//build/dart/dart_library.gni")
 
diff --git a/protobuf/CHANGELOG.md b/protobuf/CHANGELOG.md
index ff768bf..583d4e0 100644
--- a/protobuf/CHANGELOG.md
+++ b/protobuf/CHANGELOG.md
@@ -1,3 +1,17 @@
+## 0.7.0
+
+* Added fast getters for common types.
+* Only pass index instead of both tag and index to accessors.
+* Delegate more methods to underlying list in PbList.
+* Small fixes for Dart 2.0.
+
+## 0.6.0
+
+* Added enumValues to FieldInfo. Fixes #63.
+* Small performance optimization when deserializing repeated messages
+  from JSON.
+* Type annotations for strong mode.
+
 ## 0.5.5
 
 * Use real generic syntax instead of comment-based.
diff --git a/protobuf/LICENSE b/protobuf/LICENSE
index 774c842..ee99930 100644
--- a/protobuf/LICENSE
+++ b/protobuf/LICENSE
@@ -2,6 +2,7 @@
 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions are
 met:
+
     * Redistributions of source code must retain the above copyright
       notice, this list of conditions and the following disclaimer.
     * Redistributions in binary form must reproduce the above
@@ -11,6 +12,7 @@
     * Neither the name of Google Inc. nor the names of its
       contributors may be used to endorse or promote products derived
       from this software without specific prior written permission.
+
 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
diff --git a/protobuf/lib/meta.dart b/protobuf/lib/meta.dart
index 340817b..6be707d 100644
--- a/protobuf/lib/meta.dart
+++ b/protobuf/lib/meta.dart
@@ -50,6 +50,9 @@
   'unknownFields',
   'clone',
   r'$_get',
+  r'$_getI64',
+  r'$_getN',
+  r'$_getS',
   r'$_has',
   r'$_setBool',
   r'$_setBytes',
diff --git a/protobuf/lib/protobuf.dart b/protobuf/lib/protobuf.dart
index 6c4965e..a6d5c1e 100644
--- a/protobuf/lib/protobuf.dart
+++ b/protobuf/lib/protobuf.dart
@@ -5,7 +5,7 @@
 library protobuf;
 
 import 'dart:async' show Future;
-import 'dart:collection' show ListMixin;
+import 'dart:collection' show ListBase;
 import 'dart:convert' show BASE64, JSON, Utf8Codec;
 import 'dart:math' as math;
 import 'dart:typed_data' show TypedData, Uint8List, ByteData, Endianness;
diff --git a/protobuf/lib/src/protobuf/builder_info.dart b/protobuf/lib/src/protobuf/builder_info.dart
index f04eee0..dec83b9 100644
--- a/protobuf/lib/src/protobuf/builder_info.dart
+++ b/protobuf/lib/src/protobuf/builder_info.dart
@@ -7,6 +7,7 @@
 /// Per-message type setup.
 class BuilderInfo {
   final String messageName;
+  final List<FieldInfo> byIndex = <FieldInfo>[];
   final Map<int, FieldInfo> fieldInfo = new Map<int, FieldInfo>();
   final Map<String, FieldInfo> byTagAsString = <String, FieldInfo>{};
   final Map<String, FieldInfo> byName = <String, FieldInfo>{};
@@ -16,21 +17,35 @@
 
   BuilderInfo(this.messageName);
 
-  void add<T>(int tagNumber, String name, int fieldType, dynamic defaultOrMaker,
-      CreateBuilderFunc subBuilder, ValueOfFunc valueOf) {
-    var index = fieldInfo.length;
-    addField(new FieldInfo<T>(name, tagNumber, index, fieldType, defaultOrMaker,
-        subBuilder, valueOf));
+  void add<T>(
+      int tagNumber,
+      String name,
+      int fieldType,
+      dynamic defaultOrMaker,
+      CreateBuilderFunc subBuilder,
+      ValueOfFunc valueOf,
+      List<ProtobufEnum> enumValues) {
+    var index = byIndex.length;
+    _addField(new FieldInfo<T>(name, tagNumber, index, fieldType,
+        defaultOrMaker, subBuilder, valueOf, enumValues));
   }
 
-  void addRepeated<T>(int tagNumber, String name, int fieldType,
-      CheckFunc check, CreateBuilderFunc subBuilder, ValueOfFunc valueOf) {
-    var index = fieldInfo.length;
-    addField(new FieldInfo<T>.repeated(
-        name, tagNumber, index, fieldType, check, subBuilder, valueOf));
+  void addRepeated<T>(
+      int tagNumber,
+      String name,
+      int fieldType,
+      CheckFunc<T> check,
+      CreateBuilderFunc subBuilder,
+      ValueOfFunc valueOf,
+      List<ProtobufEnum> enumValues) {
+    var index = byIndex.length;
+    _addField(new FieldInfo<T>.repeated(name, tagNumber, index, fieldType,
+        check, subBuilder, valueOf, enumValues));
   }
 
-  void addField(FieldInfo fi) {
+  void _addField(FieldInfo fi) {
+    byIndex.add(fi);
+    assert(byIndex[fi.index] == fi);
     fieldInfo[fi.tagNumber] = fi;
     byTagAsString["${fi.tagNumber}"] = fi;
     byName[fi.name] = fi;
@@ -39,14 +54,44 @@
   void a<T>(int tagNumber, String name, int fieldType,
       [dynamic defaultOrMaker,
       CreateBuilderFunc subBuilder,
-      ValueOfFunc valueOf]) {
-    add<T>(tagNumber, name, fieldType, defaultOrMaker, subBuilder, valueOf);
+      ValueOfFunc valueOf,
+      List<ProtobufEnum> enumValues]) {
+    add<T>(tagNumber, name, fieldType, defaultOrMaker, subBuilder, valueOf,
+        enumValues);
+  }
+
+  /// Adds PbFieldType.OS String with no default value to reduce generated
+  /// code size.
+  void aOS(int tagNumber, String name) {
+    add<String>(tagNumber, name, PbFieldType.OS, null, null, null, null);
+  }
+
+  /// Adds PbFieldType.PS String with no default value.
+  void pPS(int tagNumber, String name) {
+    addRepeated<String>(tagNumber, name, PbFieldType.PS,
+        getCheckFunction(PbFieldType.PS), null, null, null);
+  }
+
+  /// Adds PbFieldType.QS String with no default value.
+  void aQS(int tagNumber, String name) {
+    add<String>(tagNumber, name, PbFieldType.QS, null, null, null, null);
+  }
+
+  /// Adds Int64 field with Int64.ZERO default.
+  void aInt64(int tagNumber, String name) {
+    add<Int64>(tagNumber, name, PbFieldType.O6, Int64.ZERO, null, null, null);
+  }
+
+  /// Adds a boolean with no default value.
+  void aOB(int tagNumber, String name) {
+    add<bool>(tagNumber, name, PbFieldType.OB, null, null, null, null);
   }
 
   // Enum.
   void e<T>(int tagNumber, String name, int fieldType, dynamic defaultOrMaker,
-      ValueOfFunc valueOf) {
-    add<T>(tagNumber, name, fieldType, defaultOrMaker, null, valueOf);
+      ValueOfFunc valueOf, List<ProtobufEnum> enumValues) {
+    add<T>(
+        tagNumber, name, fieldType, defaultOrMaker, null, valueOf, enumValues);
   }
 
   // Repeated message.
@@ -54,21 +99,24 @@
   void m<T>(int tagNumber, String name, CreateBuilderFunc subBuilder,
       MakeDefaultFunc makeDefault) {
     add<T>(tagNumber, name, PbFieldType._REPEATED_MESSAGE, makeDefault,
-        subBuilder, null);
+        subBuilder, null, null);
   }
 
   // Repeated, not a message, group, or enum.
   void p<T>(int tagNumber, String name, int fieldType) {
     assert(!_isGroupOrMessage(fieldType) && !_isEnum(fieldType));
-    addRepeated<T>(
-        tagNumber, name, fieldType, getCheckFunction(fieldType), null, null);
+    addRepeated<T>(tagNumber, name, fieldType, getCheckFunction(fieldType),
+        null, null, null);
   }
 
   // Repeated message, group, or enum.
-  void pp<T>(int tagNumber, String name, int fieldType, CheckFunc check,
-      [CreateBuilderFunc subBuilder, ValueOfFunc valueOf]) {
+  void pp<T>(int tagNumber, String name, int fieldType, CheckFunc<T> check,
+      [CreateBuilderFunc subBuilder,
+      ValueOfFunc valueOf,
+      List<ProtobufEnum> enumValues]) {
     assert(_isGroupOrMessage(fieldType) || _isEnum(fieldType));
-    addRepeated<T>(tagNumber, name, fieldType, check, subBuilder, valueOf);
+    addRepeated<T>(
+        tagNumber, name, fieldType, check, subBuilder, valueOf, enumValues);
   }
 
   bool containsTagNumber(int tagNumber) => fieldInfo.containsKey(tagNumber);
diff --git a/protobuf/lib/src/protobuf/extension.dart b/protobuf/lib/src/protobuf/extension.dart
index 0348a87..59e350f 100644
--- a/protobuf/lib/src/protobuf/extension.dart
+++ b/protobuf/lib/src/protobuf/extension.dart
@@ -11,15 +11,18 @@
   Extension(this.extendee, String name, int tagNumber, int fieldType,
       [dynamic defaultOrMaker,
       CreateBuilderFunc subBuilder,
-      ValueOfFunc valueOf])
+      ValueOfFunc valueOf,
+      List<ProtobufEnum> enumValues])
       : super(name, tagNumber, null, fieldType, defaultOrMaker, subBuilder,
-            valueOf);
+            valueOf, enumValues);
 
-  Extension.repeated(
-      this.extendee, String name, int tagNumber, int fieldType, CheckFunc check,
-      [CreateBuilderFunc subBuilder, ValueOfFunc valueOf])
-      : super.repeated(
-            name, tagNumber, null, fieldType, check, subBuilder, valueOf);
+  Extension.repeated(this.extendee, String name, int tagNumber, int fieldType,
+      CheckFunc<T> check,
+      [CreateBuilderFunc subBuilder,
+      ValueOfFunc valueOf,
+      List<ProtobufEnum> enumValues])
+      : super.repeated(name, tagNumber, null, fieldType, check, subBuilder,
+            valueOf, enumValues);
 
   int get hashCode => extendee.hashCode * 31 + tagNumber;
 
diff --git a/protobuf/lib/src/protobuf/field_error.dart b/protobuf/lib/src/protobuf/field_error.dart
index 100c7d5..7644653 100644
--- a/protobuf/lib/src/protobuf/field_error.dart
+++ b/protobuf/lib/src/protobuf/field_error.dart
@@ -118,58 +118,58 @@
 
 // check functions for repeated fields
 
-void _checkNotNull(val) {
+void _checkNotNull(Object val) {
   if (val == null) {
     throw new ArgumentError("Can't add a null to a repeated field");
   }
 }
 
-void _checkBool(bool val) {
+void _checkBool(Object val) {
   if (val is! bool) throw _createFieldTypeError(val, 'a bool');
 }
 
-void _checkBytes(List<int> val) {
+void _checkBytes(Object val) {
   if (val is! List<int>) throw _createFieldTypeError(val, 'a List<int>');
 }
 
-void _checkString(String val) {
+void _checkString(Object val) {
   if (val is! String) throw _createFieldTypeError(val, 'a String');
 }
 
-void _checkFloat(double val) {
+void _checkFloat(Object val) {
   _checkDouble(val);
   if (!_isFloat32(val)) throw _createFieldRangeError(val, 'a float');
 }
 
-void _checkDouble(double val) {
+void _checkDouble(Object val) {
   if (val is! double) throw _createFieldTypeError(val, 'a double');
 }
 
-void _checkInt(int val) {
+void _checkInt(Object val) {
   if (val is! int) throw _createFieldTypeError(val, 'an int');
 }
 
-void _checkSigned32(int val) {
+void _checkSigned32(Object val) {
   _checkInt(val);
   if (!_isSigned32(val)) throw _createFieldRangeError(val, 'a signed int32');
 }
 
-void _checkUnsigned32(int val) {
+void _checkUnsigned32(Object val) {
   _checkInt(val);
   if (!_isUnsigned32(val)) {
     throw _createFieldRangeError(val, 'an unsigned int32');
   }
 }
 
-void _checkAnyInt64(Int64 val) {
+void _checkAnyInt64(Object val) {
   if (val is! Int64) throw _createFieldTypeError(val, 'an Int64');
 }
 
-_checkAnyEnum(ProtobufEnum val) {
+void _checkAnyEnum(Object val) {
   if (val is! ProtobufEnum) throw _createFieldTypeError(val, 'a ProtobufEnum');
 }
 
-_checkAnyMessage(GeneratedMessage val) {
+void _checkAnyMessage(Object val) {
   if (val is! GeneratedMessage) {
     throw _createFieldTypeError(val, 'a GeneratedMessage');
   }
@@ -181,11 +181,11 @@
 RangeError _createFieldRangeError(val, String wantedType) =>
     new RangeError('Value ($val) is not ${wantedType}');
 
-bool _inRange(min, value, max) => (min <= value) && (value <= max);
+bool _isSigned32(int value) => (-2147483648 <= value) && (value <= 2147483647);
 
-bool _isSigned32(int value) => _inRange(-2147483648, value, 2147483647);
-bool _isUnsigned32(int value) => _inRange(0, value, 4294967295);
+bool _isUnsigned32(int value) => (0 <= value) && (value <= 4294967295);
+
 bool _isFloat32(double value) =>
     value.isNaN ||
     value.isInfinite ||
-    _inRange(-3.4028234663852886E38, value, 3.4028234663852886E38);
+    (-3.4028234663852886E38 <= value) && (value <= 3.4028234663852886E38);
diff --git a/protobuf/lib/src/protobuf/field_info.dart b/protobuf/lib/src/protobuf/field_info.dart
index 8e8d08a..b036ddc 100644
--- a/protobuf/lib/src/protobuf/field_info.dart
+++ b/protobuf/lib/src/protobuf/field_info.dart
@@ -20,6 +20,10 @@
   // see GeneratedMessage._getEmptyMessage
   final CreateBuilderFunc subBuilder;
 
+  // List of all enum enumValues.
+  // (Not used for other types.)
+  final List<ProtobufEnum> enumValues;
+
   // Looks up the enum value given its integer code.
   // (Not used for other types.)
   // see GeneratedMessage._getValueOfFunc
@@ -27,10 +31,10 @@
 
   // Verifies an item being added to a repeated field
   // (Not used for non-repeated fields.)
-  final CheckFunc check;
+  final CheckFunc<T> check;
 
   FieldInfo(this.name, this.tagNumber, this.index, int type,
-      [dynamic defaultOrMaker, this.subBuilder, this.valueOf])
+      [dynamic defaultOrMaker, this.subBuilder, this.valueOf, this.enumValues])
       : this.type = type,
         this.makeDefault = findMakeDefault(type, defaultOrMaker),
         this.check = null {
@@ -40,10 +44,9 @@
   }
 
   FieldInfo.repeated(this.name, this.tagNumber, this.index, int type,
-      CheckFunc check, this.subBuilder,
-      [this.valueOf])
+      this.check, this.subBuilder,
+      [this.valueOf, this.enumValues])
       : this.type = type,
-        this.check = check,
         this.makeDefault = (() => new PbList<T>(check: check)) {
     assert(name != null);
     assert(tagNumber != null);
@@ -60,6 +63,8 @@
 
   bool get isRequired => _isRequired(type);
   bool get isRepeated => _isRepeated(type);
+  bool get isGroupOrMessage => _isGroupOrMessage(type);
+  bool get isEnum => _isEnum(type);
 
   /// Returns a read-only default value for a field.
   /// (Unlike getField, doesn't create a repeated field.)
@@ -80,7 +85,7 @@
       return message._fieldSet._hasRequiredValues();
     }
 
-    List list = value;
+    List<GeneratedMessage> list = value;
     if (list.isEmpty) return true;
 
     // For message types that (recursively) contain no required fields,
diff --git a/protobuf/lib/src/protobuf/field_set.dart b/protobuf/lib/src/protobuf/field_set.dart
index 15e6a25..34e57c9 100644
--- a/protobuf/lib/src/protobuf/field_set.dart
+++ b/protobuf/lib/src/protobuf/field_set.dart
@@ -27,13 +27,17 @@
 
   _FieldSet(this._message, BuilderInfo meta, this._eventPlugin)
       : this._meta = meta,
-        _values = _makeValueList(meta.fieldInfo);
+        _values = _makeValueList(meta.byIndex.length);
 
-  static _makeValueList(Map<int, FieldInfo> infos) {
-    if (infos.isEmpty) return const [];
-    return new List(infos.length);
+  static _makeValueList(int length) {
+    if (length == 0) return _zeroList;
+    return new List(length);
   }
 
+  // Use a fixed length list and not a constant list to ensure that _values
+  // always has the same implementation type.
+  static List _zeroList = new List(0);
+
   // Metadata about multiple fields
 
   String get _messageName => _meta.messageName;
@@ -69,6 +73,9 @@
   /// Returns FieldInfo for a non-extension field, or null if not found.
   FieldInfo _nonExtensionInfo(int tagNumber) => _meta.fieldInfo[tagNumber];
 
+  /// Returns FieldInfo for a non-extension field.
+  FieldInfo _nonExtensionInfoByIndex(int index) => _meta.byIndex[index];
+
   /// Returns the FieldInfo for a regular or extension field.
   /// throws ArgumentException if no info is found.
   FieldInfo _ensureInfo(int tagNumber) {
@@ -138,7 +145,7 @@
 
   bool _hasField(int tagNumber) {
     var fi = _nonExtensionInfo(tagNumber);
-    if (fi != null) return _$has(fi.index, tagNumber);
+    if (fi != null) return _$has(fi.index);
     if (!_hasExtensions) return false;
     return _extensions._hasField(tagNumber);
   }
@@ -235,17 +242,43 @@
   // Generated method implementations
 
   /// The implementation of a generated getter.
-  T _$get<T>(int index, int tagNumber, T defaultValue) {
-    assert(_nonExtensionInfo(tagNumber).index == index);
+  T _$get<T>(int index, T defaultValue) {
     var value = _values[index];
     if (value != null) return value as T;
     if (defaultValue != null) return defaultValue;
-    return _getDefault(_nonExtensionInfo(tagNumber)) as T;
+    return _getDefault(_nonExtensionInfoByIndex(index)) as T;
   }
 
-  /// The implementation of a generated has method.
-  bool _$has(int index, int tagNumber) {
-    assert(_nonExtensionInfo(tagNumber).index == index);
+  /// The implementation of a generated getter. Common case for submessages.
+  T _$getN<T>(int index) {
+    var value = _values[index];
+    if (value != null) return value as T;
+    return _getDefault(_nonExtensionInfoByIndex(index)) as T;
+  }
+
+  /// The implementation of a generated getter for String fields.
+  String _$getS(int index, String defaultValue) {
+    var value = _values[index];
+    if (value == null) {
+      if (defaultValue != null) return defaultValue;
+      value = _getDefault(_nonExtensionInfoByIndex(index));
+    }
+    String result = value;
+    return result;
+  }
+
+  /// The implementation of a generated getter for Int64 fields.
+  Int64 _$getI64(int index) {
+    var value = _values[index];
+    if (value == null) {
+      value = _getDefault(_nonExtensionInfoByIndex(index));
+    }
+    Int64 result = value;
+    return result;
+  }
+
+  /// The implementation of a generated 'has' method.
+  bool _$has(int index) {
     var value = _values[index];
     if (value == null) return false;
     if (value is List) return value.isNotEmpty;
@@ -257,25 +290,24 @@
   /// In production, does no validation other than a null check.
   /// Only handles non-repeated, non-extension fields.
   /// Also, doesn't handle enums or messages which need per-type validation.
-  void _$set(int index, int tagNumber, value) {
-    assert(_nonExtensionInfo(tagNumber).index == index);
-    assert(!_nonExtensionInfo(tagNumber).isRepeated);
-    assert(_$check(tagNumber, value));
+  void _$set(int index, value) {
+    assert(!_nonExtensionInfoByIndex(index).isRepeated);
+    assert(_$check(index, value));
     if (_isReadOnly) {
       throw new UnsupportedError(
           "attempted to call a setter on a read-only message ($_messageName)");
     }
     if (value == null) {
-      _$check(tagNumber, value); // throw exception for null value
+      _$check(index, value); // throw exception for null value
     }
     if (_hasObservers) {
-      _eventPlugin.beforeSetField(_nonExtensionInfo(tagNumber), value);
+      _eventPlugin.beforeSetField(_nonExtensionInfoByIndex(index), value);
     }
     _values[index] = value;
   }
 
-  bool _$check(int tagNumber, var newValue) {
-    _validateField(_nonExtensionInfo(tagNumber), newValue);
+  bool _$check(int index, var newValue) {
+    _validateField(_nonExtensionInfoByIndex(index), newValue);
     return true; // Allows use in an assertion.
   }
 
@@ -486,12 +518,16 @@
 
     if (fi.isRepeated) {
       if (mustClone) {
+        // fieldValue must be a PbList of GeneratedMessage.
+        PbList<GeneratedMessage> pbList = fieldValue;
         // Copy the mapped values to a List to avoid redundant cloning (since
         // PbList.addAll iterates over its argument twice).
         _ensureRepeatedField(fi)
-            .addAll(new List.from(fieldValue.map(_cloneMessage)));
+            .addAll(new List.from(pbList.map(_cloneMessage)));
       } else {
-        _ensureRepeatedField(fi).addAll(fieldValue);
+        // fieldValue must be at least a PbList.
+        PbList pbList = fieldValue;
+        _ensureRepeatedField(fi).addAll(pbList);
       }
       return;
     }
diff --git a/protobuf/lib/src/protobuf/generated_message.dart b/protobuf/lib/src/protobuf/generated_message.dart
index e4657e5..338fbc5 100644
--- a/protobuf/lib/src/protobuf/generated_message.dart
+++ b/protobuf/lib/src/protobuf/generated_message.dart
@@ -276,56 +276,65 @@
   ///
   /// Throws an [:ArgumentError:] if [value] is [:null:]. To clear a field of
   /// it's current value, use [clearField] instead.
-  void setField(int tagNumber, value) => _fieldSet._setField(tagNumber, value);
+  void setField(int tagNumber, value) {
+    _fieldSet._setField(tagNumber, value);
+    return; // ignore: dead_code
+    return; // ignore: dead_code
+  }
 
   /// For generated code only.
-  T $_get<T>(int index, int tagNumber, T defaultValue) =>
-      _fieldSet._$get<T>(index, tagNumber, defaultValue);
+  T $_get<T>(int index, T defaultValue) =>
+      _fieldSet._$get<T>(index, defaultValue);
 
   /// For generated code only.
-  bool $_has(int index, int tagNumber) => _fieldSet._$has(index, tagNumber);
+  T $_getN<T>(int index) => _fieldSet._$getN<T>(index);
 
   /// For generated code only.
-  void $_setBool(int index, int tagNumber, bool value) =>
-      _fieldSet._$set(index, tagNumber, value);
+  String $_getS(int index, String defaultValue) =>
+      _fieldSet._$getS(index, defaultValue);
 
   /// For generated code only.
-  void $_setBytes(int index, int tagNumber, List<int> value) =>
-      _fieldSet._$set(index, tagNumber, value);
+  Int64 $_getI64(int index) => _fieldSet._$getI64(index);
 
   /// For generated code only.
-  void $_setString(int index, int tagNumber, String value) =>
-      _fieldSet._$set(index, tagNumber, value);
+  bool $_has(int index) => _fieldSet._$has(index);
 
   /// For generated code only.
-  void $_setFloat(int index, int tagNumber, double value) {
+  void $_setBool(int index, bool value) => _fieldSet._$set(index, value);
+
+  /// For generated code only.
+  void $_setBytes(int index, List<int> value) => _fieldSet._$set(index, value);
+
+  /// For generated code only.
+  void $_setString(int index, String value) => _fieldSet._$set(index, value);
+
+  /// For generated code only.
+  void $_setFloat(int index, double value) {
     if (value == null || !_isFloat32(value)) {
-      _fieldSet._$check(tagNumber, value);
+      _fieldSet._$check(index, value);
     }
-    _fieldSet._$set(index, tagNumber, value);
+    _fieldSet._$set(index, value);
   }
 
   /// For generated code only.
-  void $_setDouble(int index, int tagNumber, double value) =>
-      _fieldSet._$set(index, tagNumber, value);
+  void $_setDouble(int index, double value) => _fieldSet._$set(index, value);
 
   /// For generated code only.
-  void $_setSignedInt32(int index, int tagNumber, int value) {
+  void $_setSignedInt32(int index, int value) {
     if (value == null || !_isSigned32(value)) {
-      _fieldSet._$check(tagNumber, value);
+      _fieldSet._$check(index, value);
     }
-    _fieldSet._$set(index, tagNumber, value);
+    _fieldSet._$set(index, value);
   }
 
   /// For generated code only.
-  void $_setUnsignedInt32(int index, int tagNumber, int value) {
+  void $_setUnsignedInt32(int index, int value) {
     if (value == null || !_isUnsigned32(value)) {
-      _fieldSet._$check(tagNumber, value);
+      _fieldSet._$check(index, value);
     }
-    _fieldSet._$set(index, tagNumber, value);
+    _fieldSet._$set(index, value);
   }
 
   /// For generated code only.
-  void $_setInt64(int index, int tagNumber, Int64 value) =>
-      _fieldSet._$set(index, tagNumber, value);
+  void $_setInt64(int index, Int64 value) => _fieldSet._$set(index, value);
 }
diff --git a/protobuf/lib/src/protobuf/json.dart b/protobuf/lib/src/protobuf/json.dart
index 4b4b99d..62d276e 100644
--- a/protobuf/lib/src/protobuf/json.dart
+++ b/protobuf/lib/src/protobuf/json.dart
@@ -5,11 +5,12 @@
 part of protobuf;
 
 Map<String, dynamic> _writeToJsonMap(_FieldSet fs) {
-  convertToMap(fieldValue, fieldType) {
+  convertToMap(fieldValue, int fieldType) {
     int baseType = PbFieldType._baseType(fieldType);
 
     if (_isRepeated(fieldType)) {
-      return new List.from(fieldValue.map((e) => convertToMap(e, baseType)));
+      PbList pbList = fieldValue;
+      return new List.from(pbList.map((e) => convertToMap(e, baseType)));
     }
 
     switch (baseType) {
@@ -67,8 +68,10 @@
 // (Called recursively on nested messages.)
 void _mergeFromJsonMap(
     _FieldSet fs, Map<String, dynamic> json, ExtensionRegistry registry) {
-  for (String key in json.keys) {
-    var fi = fs._meta.byTagAsString[key];
+  Iterable<String> keys = json.keys;
+  var meta = fs._meta;
+  for (String key in keys) {
+    var fi = meta.byTagAsString[key];
     if (fi == null) {
       if (registry == null) continue; // Unknown tag; skip
       fi = registry.getExtension(fs._messageName, int.parse(key));
@@ -83,9 +86,14 @@
 }
 
 void _appendJsonList(
-    _FieldSet fs, List json, FieldInfo fi, ExtensionRegistry registry) {
+    _FieldSet fs, List jsonList, FieldInfo fi, ExtensionRegistry registry) {
   List repeated = fs._ensureRepeatedField(fi);
-  for (var value in json) {
+  // Micro optimization. Using "for in" generates the following and iterator
+  // alloc:
+  //   for (t1 = J.get$iterator$ax(json), t2 = fi.tagNumber, t3 = fi.type,
+  //       t4 = J.getInterceptor$ax(repeated); t1.moveNext$0();)
+  for (int i = 0, len = jsonList.length; i < len; i++) {
+    var value = jsonList[i];
     var convertedValue =
         _convertJsonValue(fs, value, fi.tagNumber, fi.type, registry);
     if (convertedValue != null) {
@@ -97,10 +105,15 @@
 void _setJsonField(
     _FieldSet fs, json, FieldInfo fi, ExtensionRegistry registry) {
   var value = _convertJsonValue(fs, json, fi.tagNumber, fi.type, registry);
-  if (value != null) {
+  if (value == null) return;
+  // _convertJsonValue throws exception when it fails to do conversion.
+  // Therefore we run _validateField for debug builds only to validate
+  // correctness of conversion.
+  assert(() {
     fs._validateField(fi, value);
-    fs._setFieldUnchecked(fi, value);
-  }
+    return true;
+  }());
+  fs._setFieldUnchecked(fi, value);
 }
 
 /// Converts [value] from the Json format to the Dart data type
@@ -183,16 +196,16 @@
     case PbFieldType._FIXED64_BIT:
     case PbFieldType._SFIXED64_BIT:
       if (value is int) return new Int64(value);
-      if (value is String) return Int64.parseRadix(value, 10);
+      if (value is String) return Int64.parseInt(value);
       expectedType = 'int or stringified int';
       break;
     case PbFieldType._GROUP_BIT:
     case PbFieldType._MESSAGE_BIT:
       if (value is Map) {
+        Map<String, dynamic> messageValue = value;
         GeneratedMessage subMessage =
             fs._meta._makeEmptyMessage(tagNumber, registry);
-        _mergeFromJsonMap(
-            subMessage._fieldSet, value as Map<String, dynamic>, registry);
+        _mergeFromJsonMap(subMessage._fieldSet, messageValue, registry);
         return subMessage;
       }
       expectedType = 'nested message or group';
diff --git a/protobuf/lib/src/protobuf/mixins/map_mixin.dart b/protobuf/lib/src/protobuf/mixins/map_mixin.dart
index 0032552..7079aa4 100644
--- a/protobuf/lib/src/protobuf/mixins/map_mixin.dart
+++ b/protobuf/lib/src/protobuf/mixins/map_mixin.dart
@@ -6,12 +6,13 @@
 
 import "package:protobuf/protobuf.dart" show BuilderInfo;
 
-/// A PbMapMixin provides an experimental implementation of the
-/// Map interface for a GeneratedMessage.
+/// Note that this class does not claim to implement [Map]. Instead, this needs
+/// to be specified using a dart_options.imports clause specifying MapMixin as a
+/// parent mixin to PbMapMixin.
 ///
-/// This mixin is enabled via an option in
-/// dart_options.proto in dart-protoc-plugin.
-abstract class PbMapMixin implements Map {
+/// Since PbMapMixin is built in, this is done automatically, so this mixin can
+/// be enabled by specifying only a dart_options.mixin option.
+abstract class PbMapMixin {
   // GeneratedMessage properties and methods used by this mixin.
 
   BuilderInfo get info_;
@@ -20,7 +21,6 @@
   getField(int tagNumber);
   void setField(int tagNumber, var value);
 
-  @override
   operator [](key) {
     if (key is! String) return null;
     var tag = getTagNumber(key);
@@ -28,7 +28,6 @@
     return getField(tag);
   }
 
-  @override
   operator []=(key, val) {
     var tag = getTagNumber(key as String);
     if (tag == null) {
@@ -38,16 +37,12 @@
     setField(tag, val);
   }
 
-  @override
-  get keys => info_.byName.keys;
+  Iterable<String> get keys => info_.byName.keys;
 
-  @override
   bool containsKey(Object key) => info_.byName.containsKey(key);
 
-  @override
-  get length => info_.byName.length;
+  int get length => info_.byName.length;
 
-  @override
   remove(key) {
     throw new UnsupportedError(
         "remove() not supported by ${info_.messageName}");
diff --git a/protobuf/lib/src/protobuf/pb_list.dart b/protobuf/lib/src/protobuf/pb_list.dart
index b4c8a9c..85f7025 100644
--- a/protobuf/lib/src/protobuf/pb_list.dart
+++ b/protobuf/lib/src/protobuf/pb_list.dart
@@ -4,11 +4,11 @@
 
 part of protobuf;
 
-typedef CheckFunc(x);
+typedef void CheckFunc<E>(E x);
 
-class PbList<E> extends Object with ListMixin<E> implements List<E> {
+class PbList<E> extends ListBase<E> {
   final List<E> _wrappedList;
-  final CheckFunc check;
+  final CheckFunc<E> check;
 
   PbList({this.check: _checkNotNull}) : _wrappedList = <E>[] {
     assert(check != null);
@@ -44,11 +44,93 @@
   /// `f` on each element of this `PbList` in iteration order.
   Iterable<T> map<T>(T f(E e)) => _wrappedList.map<T>(f);
 
+  /// Returns a new lazy [Iterable] with all elements that satisfy the predicate
+  /// [test].
+  Iterable<E> where(bool test(E element)) => _wrappedList.where(test);
+
+  /// Expands each element of this [Iterable] into zero or more elements.
+  Iterable<T> expand<T>(Iterable<T> f(E element)) => _wrappedList.expand(f);
+
+  /// Returns true if the collection contains an element equal to [element].
+  bool contains(Object element) => _wrappedList.contains(element);
+
   /// Applies the function [f] to each element of this list in iteration order.
   void forEach(void f(E element)) {
     _wrappedList.forEach(f);
   }
 
+  /// Reduces a collection to a single value by iteratively combining elements
+  /// of the collection using the provided function.
+  E reduce(E combine(E value, E element)) => _wrappedList.reduce(combine);
+
+  /// Reduces a collection to a single value by iteratively combining each
+  /// element of the collection with an existing value.
+  T fold<T>(T initialValue, T combine(dynamic previousValue, E element)) =>
+      _wrappedList.fold(initialValue, combine);
+
+  /// Checks whether every element of this iterable satisfies [test].
+  bool every(bool test(E element)) => _wrappedList.every(test);
+
+  /// Converts each element to a [String] and concatenates the strings.
+  String join([String separator = ""]) => _wrappedList.join(separator);
+
+  /// Checks whether any element of this iterable satisfies [test].
+  bool any(bool test(E element)) => _wrappedList.any(test);
+
+  /// Creates a [List] containing the elements of this [Iterable].
+  List<E> toList({bool growable: true}) =>
+      _wrappedList.toList(growable: growable);
+
+  /// Creates a [Set] containing the same elements as this iterable.
+  Set<E> toSet() => _wrappedList.toSet();
+
+  /// Returns `true` if there are no elements in this collection.
+  bool get isEmpty => _wrappedList.isEmpty;
+
+  /// Returns `true` if there is at least one element in this collection.
+  bool get isNotEmpty => _wrappedList.isNotEmpty;
+
+  /// Returns a lazy iterable of the [count] first elements of this iterable.
+  Iterable<E> take(int count) => _wrappedList.take(count);
+
+  /// Returns a lazy iterable of the leading elements satisfying [test].
+  Iterable<E> takeWhile(bool test(E value)) => _wrappedList.takeWhile(test);
+
+  /// Returns an [Iterable] that provides all but the first [count] elements.
+  Iterable<E> skip(int count) => _wrappedList.skip(count);
+
+  /// Returns an `Iterable` that skips leading elements while [test] is
+  /// satisfied.
+  Iterable<E> skipWhile(bool test(E value)) => _wrappedList.skipWhile(test);
+
+  /// Returns the first element.
+  E get first => _wrappedList.first;
+
+  /// Returns the last element.
+  E get last => _wrappedList.last;
+
+  /// Checks that this iterable has only one element, and returns that element.
+  E get single => _wrappedList.single;
+
+  /// Returns the first element that satisfies the given predicate [test].
+  E firstWhere(bool test(E element), {E orElse()}) =>
+      _wrappedList.firstWhere(test, orElse: orElse);
+
+  /// Returns the last element that satisfies the given predicate [test].
+  E lastWhere(bool test(E element), {E orElse()}) =>
+      _wrappedList.lastWhere(test, orElse: orElse);
+
+  /// Returns the single element that satisfies [test].
+  // TODO(jakobr): Implement once Dart 2 corelib changes have landed.
+  //E singleWhere(bool test(E element), {E orElse()}) =>
+  //    _wrappedList.singleWhere(test, orElse: orElse);
+
+  /// Returns the [index]th element.
+  E elementAt(int index) => _wrappedList.elementAt(index);
+
+  /// Returns a string representation of (some of) the elements of `this`.
+  String toString() => _wrappedList.toString();
+
   /// Returns the element at the given [index] in the list or throws an
   /// [IndexOutOfRangeException] if [index] is out of bounds.
   E operator [](int index) => _wrappedList[index];
@@ -60,14 +142,17 @@
     _wrappedList[index] = value;
   }
 
+  /// Returns the number of elements in this collection.
+  int get length => _wrappedList.length;
+
   /// Unsupported -- violated non-null constraint imposed by protobufs.
   ///
   /// Changes the length of the list. If [newLength] is greater than the current
   /// [length], entries are initialized to [:null:]. Throws an
   /// [UnsupportedError] if the list is not extendable.
-  void set length(int newLength) {
+  set length(int newLength) {
     if (newLength > length) {
-      throw new ArgumentError('Extending protobuf lists is not supported');
+      throw new UnsupportedError('Extending protobuf lists is not supported');
     }
     _wrappedList.length = newLength;
   }
@@ -87,15 +172,28 @@
     _wrappedList.addAll(collection);
   }
 
-  /// Copies [:end - start:] elements of the [from] array, starting from
-  /// [skipCount], into [:this:], starting at [start].
-  /// Throws an [UnsupportedError] if the list is not extendable.
-  void setRange(int start, int end, Iterable<E> from, [int skipCount = 0]) {
-    // NOTE: In case `take()` returns less than `end - start` elements, the
-    // _wrappedList will fail with a `StateError`.
-    from.skip(skipCount).take(end - start).forEach(_validate);
-    _wrappedList.setRange(start, end, from, skipCount);
-  }
+  /// Returns an [Iterable] of the objects in this list in reverse order.
+  Iterable<E> get reversed => _wrappedList.reversed;
+
+  /// Sorts this list according to the order specified by the [compare]
+  /// function.
+  void sort([int compare(E a, E b)]) => _wrappedList.sort(compare);
+
+  /// Shuffles the elements of this list randomly.
+  void shuffle([math.Random random]) => _wrappedList.shuffle(random);
+
+  // TODO(jakobr): E instead of Object once dart-lang/sdk#31311 is fixed.
+  /// Returns the first index of [element] in this list.
+  int indexOf(Object element, [int start = 0]) =>
+      _wrappedList.indexOf(element, start);
+
+  // TODO(jakobr): E instead of Object once dart-lang/sdk#31311 is fixed.
+  /// Returns the last index of [element] in this list.
+  int lastIndexOf(Object element, [int start]) =>
+      _wrappedList.lastIndexOf(element, start);
+
+  /// Removes all objects from this list; the length of the list becomes zero.
+  void clear() => _wrappedList.clear();
 
   /// Inserts a new element in the list.
   /// The element must be valid (and not nullable) for the PbList type.
@@ -121,8 +219,59 @@
     _wrappedList.setAll(index, iterable);
   }
 
-  /// Returns the number of elements in this collection.
-  int get length => _wrappedList.length;
+  /// Removes the first occurrence of [value] from this list.
+  bool remove(Object value) => _wrappedList.remove(value);
+
+  /// Removes the object at position [index] from this list.
+  E removeAt(int index) => _wrappedList.removeAt(index);
+
+  /// Pops and returns the last object in this list.
+  E removeLast() => _wrappedList.removeLast();
+
+  /// Removes all objects from this list that satisfy [test].
+  void removeWhere(bool test(E element)) => _wrappedList.removeWhere(test);
+
+  /// Removes all objects from this list that fail to satisfy [test].
+  void retainWhere(bool test(E element)) => _wrappedList.retainWhere(test);
+
+  /// Returns a new list containing the objects from [start] inclusive to [end]
+  /// exclusive.
+  List<E> sublist(int start, [int end]) => _wrappedList.sublist(start, end);
+
+  /// Returns an [Iterable] that iterates over the objects in the range [start]
+  /// inclusive to [end] exclusive.
+  Iterable<E> getRange(int start, int end) => _wrappedList.getRange(start, end);
+
+  /// Copies [:end - start:] elements of the [from] array, starting from
+  /// [skipCount], into [:this:], starting at [start].
+  /// Throws an [UnsupportedError] if the list is not extendable.
+  void setRange(int start, int end, Iterable<E> from, [int skipCount = 0]) {
+    // NOTE: In case `take()` returns less than `end - start` elements, the
+    // _wrappedList will fail with a `StateError`.
+    from.skip(skipCount).take(end - start).forEach(_validate);
+    _wrappedList.setRange(start, end, from, skipCount);
+  }
+
+  /// Removes the objects in the range [start] inclusive to [end] exclusive.
+  void removeRange(int start, int end) => _wrappedList.removeRange(start, end);
+
+  /// Sets the objects in the range [start] inclusive to [end] exclusive to the
+  /// given [fillValue].
+  void fillRange(int start, int end, [E fillValue]) {
+    _validate(fillValue);
+    _wrappedList.fillRange(start, end, fillValue);
+  }
+
+  /// Removes the objects in the range [start] inclusive to [end] exclusive and
+  /// inserts the contents of [replacement] in its place.
+  void replaceRange(int start, int end, Iterable<E> replacement) {
+    final values = replacement.toList();
+    replacement.forEach(_validate);
+    _wrappedList.replaceRange(start, end, values);
+  }
+
+  /// Returns an unmodifiable [Map] view of `this`.
+  Map<int, E> asMap() => _wrappedList.asMap();
 
   void _validate(E val) {
     check(val);
diff --git a/protobuf/pubspec.yaml b/protobuf/pubspec.yaml
index 48ae1b4..b5f017a 100644
--- a/protobuf/pubspec.yaml
+++ b/protobuf/pubspec.yaml
@@ -1,10 +1,10 @@
 name: protobuf
-version: 0.5.5
+version: 0.7.0
 author: Dart Team <misc@dartlang.org>
 description: Runtime library for protocol buffers support.
 homepage: https://github.com/dart-lang/protobuf
 environment:
-  sdk: '>=1.21.0 <2.0.0-dev.infinity'
+  sdk: '>=1.21.0 <2.0.0'
 dependencies:
   fixnum: '>=0.9.0 <0.11.0'
 dev_dependencies:
diff --git a/quiver/BUILD.gn b/quiver/BUILD.gn
index daa1af4..7654c58 100644
--- a/quiver/BUILD.gn
+++ b/quiver/BUILD.gn
@@ -1,4 +1,4 @@
-# This file is generated by importer.py for quiver-0.27.0
+# This file is generated by importer.py for quiver-0.28.0
 
 import("//build/dart/dart_library.gni")
 
diff --git a/quiver/CHANGELOG.md b/quiver/CHANGELOG.md
index 0209ff5..73a4854 100644
--- a/quiver/CHANGELOG.md
+++ b/quiver/CHANGELOG.md
@@ -1,3 +1,9 @@
+#### 0.28.0 - 2018-01-19
+
+   * BREAKING CHANGE: The signature of `MultiMap`'s `update` stub has changed
+     from `V update(K key, C update(C value), {C ifAbsent()})` to
+     `C update(K key, C update(C value), {C ifAbsent()})`.
+
 #### 0.27.0 - 2018-01-03
 
    * BREAKING CHANGE: all classes that implement `Iterable`, `List`, `Map`,
diff --git a/quiver/README.md b/quiver/README.md
index e051d3c..1b9fb26 100644
--- a/quiver/README.md
+++ b/quiver/README.md
@@ -17,7 +17,7 @@
 We recommend the following version constraint:
 
     dependencies:
-      quiver: '>=0.27.0 <0.28.0'
+      quiver: '>=0.28.0 <0.29.0'
 
 # Main Libraries
 
diff --git a/quiver/lib/src/collection/multimap.dart b/quiver/lib/src/collection/multimap.dart
index 3b6271f..9affd16 100644
--- a/quiver/lib/src/collection/multimap.dart
+++ b/quiver/lib/src/collection/multimap.dart
@@ -338,7 +338,7 @@
   @override
   // TODO: Dart 2.0 requires this method to be implemented.
   // ignore: override_on_non_overriding_method
-  V update(K key, C update(C value), {C ifAbsent()}) {
+  C update(K key, C update(C value), {C ifAbsent()}) {
     throw new UnimplementedError("update");
   }
 
diff --git a/quiver/pubspec.yaml b/quiver/pubspec.yaml
index 52bf68c..442ba17 100644
--- a/quiver/pubspec.yaml
+++ b/quiver/pubspec.yaml
@@ -1,5 +1,5 @@
 name: quiver
-version: 0.27.0
+version: 0.28.0
 authors:
 - Justin Fagnani <justinfagnani@google.com>
 - Yegor Jbanov <yjbanov@google.com>
diff --git a/test/BUILD.gn b/test/BUILD.gn
index 2d18fc2..30af258 100644
--- a/test/BUILD.gn
+++ b/test/BUILD.gn
@@ -1,4 +1,4 @@
-# This file is generated by importer.py for test-0.12.26
+# This file is generated by importer.py for test-0.12.30+1
 
 import("//build/dart/dart_library.gni")
 
@@ -10,35 +10,37 @@
   disable_analysis = true
 
   deps = [
-    "//third_party/dart-pkg/pub/stack_trace",
-    "//third_party/dart-pkg/pub/node_preamble",
-    "//third_party/dart-pkg/pub/args",
     "//third_party/dart-pkg/pub/shelf_web_socket",
     "//third_party/dart-pkg/pub/barback",
-    "//third_party/dart-pkg/pub/matcher",
-    "//third_party/dart-pkg/pub/glob",
+    "//third_party/dart-pkg/pub/multi_server_socket",
     "//third_party/dart-pkg/pub/shelf_packages_handler",
-    "//third_party/dart-pkg/pub/http_multi_server",
-    "//third_party/dart-pkg/pub/collection",
-    "//third_party/dart-pkg/pub/js",
     "//third_party/dart-pkg/pub/meta",
-    "//third_party/dart/pkg/analyzer",
     "//third_party/dart-pkg/pub/io",
     "//third_party/dart-pkg/pub/term_glyph",
-    "//third_party/dart-pkg/pub/path",
-    "//third_party/dart-pkg/pub/stream_channel",
-    "//third_party/dart-pkg/pub/pool",
+    "//third_party/dart-pkg/pub/source_span",
     "//third_party/dart-pkg/pub/source_maps",
     "//third_party/dart-pkg/pub/shelf_static",
-    "//third_party/dart-pkg/pub/source_map_stack_trace",
     "//third_party/dart-pkg/pub/pub_semver",
-    "//third_party/dart-pkg/pub/yaml",
-    "//third_party/dart-pkg/pub/source_span",
-    "//third_party/dart-pkg/pub/package_resolver",
     "//third_party/dart-pkg/pub/web_socket_channel",
+    "//third_party/dart-pkg/pub/yaml",
     "//third_party/dart-pkg/pub/string_scanner",
     "//third_party/dart-pkg/pub/shelf",
     "//third_party/dart-pkg/pub/boolean_selector",
+    "//third_party/dart-pkg/pub/stack_trace",
+    "//third_party/dart-pkg/pub/node_preamble",
+    "//third_party/dart-pkg/pub/matcher",
+    "//third_party/dart-pkg/pub/glob",
+    "//third_party/dart-pkg/pub/args",
+    "//third_party/dart-pkg/pub/http_multi_server",
+    "//third_party/dart-pkg/pub/collection",
+    "//third_party/dart-pkg/pub/js",
+    "//third_party/dart/pkg/analyzer",
+    "//third_party/dart-pkg/pub/path",
+    "//third_party/dart-pkg/pub/stream_channel",
+    "//third_party/dart-pkg/pub/pool",
+    "//third_party/dart-pkg/pub/typed_data",
+    "//third_party/dart-pkg/pub/source_map_stack_trace",
+    "//third_party/dart-pkg/pub/package_resolver",
     "//third_party/dart-pkg/pub/async",
   ]
 }
diff --git a/test/CHANGELOG.md b/test/CHANGELOG.md
index 9478222..6ed8fb5 100644
--- a/test/CHANGELOG.md
+++ b/test/CHANGELOG.md
@@ -1,3 +1,58 @@
+## 0.12.30+1
+
+* Internal changes.
+
+## 0.12.30
+
+* Platform selectors for operating systems now work for Node.js tests
+  ([#742][]).
+
+* `fail()` is now typed to return `Null`, so it can be used in the same places
+  as a raw `throw`.
+
+* Run Chrome in headless mode unless debugging is enabled.
+
+[#742]: https://github.com/dart-lang/test/issues/742
+
+## 0.12.29+1
+
+* Fix strong mode runtime cast failures.
+
+## 0.12.29
+
+* Node.js tests can now import modules from a top-level `node_modules`
+  directory, if one exists.
+
+* Raw `console.log()` calls no longer crash Node.js tests.
+
+* When a browser crashes, include its standard output in the error message.
+
+## 0.12.28+1
+
+* Add a `pumpEventQueue()` function to make it easy to wait until all
+  asynchronous tasks are complete.
+
+* Add a `neverCalled` getter that returns a function that causes the test to
+  fail if it's ever called.
+
+## 0.12.27+1
+
+* Increase the timeout for loading tests to 12 minutes.
+
+## 0.12.27
+
+* When `addTearDown()` is called within a call to `setUpAll()`, it runs its
+  callback after *all* tests instead of running it after the `setUpAll()`
+  callback.
+
+* When running in an interactive terminal, the test runner now prints status
+  lines as wide as the terminal and no wider.
+
+## 0.12.26+1
+
+* Fix lower bound on package `stack_trace`. Now 1.6.0.
+* Manually close browser process streams to prevent test hangs.
+
 ## 0.12.26
 
 * The `spawnHybridUri()` function now allows root-relative URLs, which are
@@ -53,13 +108,13 @@
 
 ## 0.12.23+1
 
-* Remove unused imports. 
+* Remove unused imports.
 
 ## 0.12.23
 
 * Add a `fold_stack_frames` field for `dart_test.yaml`. This will
   allow users to customize which packages' frames are folded.
-  
+
 ## 0.12.22+2
 
 * Properly allocate ports when debugging Chrome and Dartium in an IPv6-only
@@ -76,11 +131,11 @@
 ## 0.12.22
 
 * Add a `retry` option to `test()` and `group()` functions, as well
-  as `@Retry()`  annotation for test files and a `retry` 
+  as `@Retry()`  annotation for test files and a `retry`
   configuration field for `dart_test.yaml`.  A test with reties
   enabled will be re-run if it fails for a reason other than a
   `TestFailure`.
-  
+
 * Add a `--no-retry` runner flag that disables retries of failing tests.
 
 * Fix a "concurrent modification during iteration" error when calling
diff --git a/test/README.md b/test/README.md
index 2519e20..733595c 100644
--- a/test/README.md
+++ b/test/README.md
@@ -233,14 +233,14 @@
 * `blink`: Whether the test is running in a browser that uses the Blink
   rendering engine.
 
-* `windows`: Whether the test is running on Windows. If `vm` is false, this will
-  be `false` as well.
+* `windows`: Whether the test is running on Windows. This can only be `true` if
+  either `vm` or `node` is true.
 
-* `mac-os`: Whether the test is running on Mac OS. If `vm` is false, this will
-  be `false` as well.
+* `mac-os`: Whether the test is running on Mac OS. This can only be `true` if
+  either `vm` or `node` is true.
 
-* `linux`: Whether the test is running on Linux. If `vm` is false, this will be
-  `false` as well.
+* `linux`: Whether the test is running on Linux. This can only be `true` if
+  either `vm` or `node` is true.
 
 * `android`: Whether the test is running on Android. If `vm` is false, this will
   be `false` as well, which means that this *won't* be true if the test is
@@ -298,6 +298,9 @@
 
 [bool.fromEnvironment]: https://api.dartlang.org/stable/1.24.2/dart-core/bool/bool.fromEnvironment.html
 
+If a top-level `node_modules` directory exists, tests running on Node.js can
+import modules from it.
+
 ## Asynchronous Tests
 
 Tests written with `async`/`await` will work automatically. The test runner
diff --git a/test/dart_test.yaml b/test/dart_test.yaml
index c06b8c2..5743f40 100644
--- a/test/dart_test.yaml
+++ b/test/dart_test.yaml
@@ -1,5 +1,18 @@
-# Terse traces hide frames from test itself, which is bad.
-verbose_trace: true
+# Fold frames from helper packages we use in our tests, but not from test
+# itself.
+fold_stack_frames:
+  except:
+  - shelf_test_handler
+  - stream_channel
+  - test_descriptor
+  - test_process
+
+presets:
+  # "-P terse-trace" folds frames from test's implementation to make the output
+  # less verbose when
+  terse-trace:
+    fold_stack_frames:
+      except: [test]
 
 tags:
   browser:
diff --git a/test/doc/configuration.md b/test/doc/configuration.md
index 800cc5d..5fb70c1 100644
--- a/test/doc/configuration.md
+++ b/test/doc/configuration.md
@@ -402,7 +402,7 @@
 ### `fold_stack_frames`
 
 This field controls which packages' stack frames will be folded away
-when displaying stack traces. Packages contained in the `exclude` 
+when displaying stack traces. Packages contained in the `except`
 option will be folded. If `only` is provided, all packages not
 contained in this list will be folded. By default,
 frames from the `test` package and the `stream_channel`
diff --git a/test/doc/package_config.md b/test/doc/package_config.md
index 800cc5d..5fb70c1 100644
--- a/test/doc/package_config.md
+++ b/test/doc/package_config.md
@@ -402,7 +402,7 @@
 ### `fold_stack_frames`
 
 This field controls which packages' stack frames will be folded away
-when displaying stack traces. Packages contained in the `exclude` 
+when displaying stack traces. Packages contained in the `except`
 option will be folded. If `only` is provided, all packages not
 contained in this list will be folded. By default,
 frames from the `test` package and the `stream_channel`
diff --git a/test/lib/src/backend/declarer.dart b/test/lib/src/backend/declarer.dart
index 4e8851d..29490eb 100644
--- a/test/lib/src/backend/declarer.dart
+++ b/test/lib/src/backend/declarer.dart
@@ -155,11 +155,15 @@
         }
       }
 
-      await Invoker.current.waitForOutstandingCallbacks(() async {
-        await _runSetUps();
-        await body();
-      });
-    }, trace: _collectTraces ? new Trace.current(2) : null));
+      await runZoned(
+          () => Invoker.current.waitForOutstandingCallbacks(() async {
+                await _runSetUps();
+                await body();
+              }),
+          // Make the declarer visible to running tests so that they'll throw
+          // useful errors when calling `test()` and `group()` within a test.
+          zoneValues: {#test.declarer: this});
+    }, trace: _collectTraces ? new Trace.current(2) : null, guarded: false));
   }
 
   /// Creates a group of tests.
@@ -224,7 +228,14 @@
     _tearDownAlls.add(callback);
   }
 
+  /// Like [tearDownAll], but called from within a running [setUpAll] test to
+  /// dynamically add a [tearDownAll].
+  void addTearDownAll(callback()) => _tearDownAlls.add(callback);
+
   /// Finalizes and returns the group being declared.
+  ///
+  /// **Note**: The tests in this group must be run in a [Invoker.guard]
+  /// context; otherwise, test errors won't be captured.
   Group build() {
     _checkNotBuilt("build");
 
@@ -258,18 +269,30 @@
     if (_setUpAlls.isEmpty) return null;
 
     return new LocalTest(_prefix("(setUpAll)"), _metadata, () {
-      return Future.forEach(_setUpAlls, (setUp) => setUp());
-    }, trace: _setUpAllTrace);
+      return runZoned(() => Future.forEach(_setUpAlls, (setUp) => setUp()),
+          // Make the declarer visible to running scaffolds so they can add to
+          // the declarer's `tearDownAll()` list.
+          zoneValues: {#test.declarer: this});
+    }, trace: _setUpAllTrace, guarded: false, isScaffoldAll: true);
   }
 
   /// Returns a [Test] that runs the callbacks in [_tearDownAll].
   Test get _tearDownAll {
-    if (_tearDownAlls.isEmpty) return null;
+    // We have to create a tearDownAll if there's a setUpAll, since it might
+    // dynamically add tear-down code using [addTearDownAll].
+    if (_setUpAlls.isEmpty && _tearDownAlls.isEmpty) return null;
 
     return new LocalTest(_prefix("(tearDownAll)"), _metadata, () {
-      return Invoker.current.unclosable(() {
-        return Future.forEach(_tearDownAlls.reversed, errorsDontStopTest);
-      });
-    }, trace: _tearDownAllTrace);
+      return runZoned(() {
+        return Invoker.current.unclosable(() async {
+          while (_tearDownAlls.isNotEmpty) {
+            await errorsDontStopTest(_tearDownAlls.removeLast());
+          }
+        });
+      },
+          // Make the declarer visible to running scaffolds so they can add to
+          // the declarer's `tearDownAll()` list.
+          zoneValues: {#test.declarer: this});
+    }, trace: _tearDownAllTrace, guarded: false, isScaffoldAll: true);
   }
 }
diff --git a/test/lib/src/backend/invoker.dart b/test/lib/src/backend/invoker.dart
index 12295c5..e2a8b89 100644
--- a/test/lib/src/backend/invoker.dart
+++ b/test/lib/src/backend/invoker.dart
@@ -10,6 +10,7 @@
 import '../runner/load_suite.dart';
 import '../utils.dart';
 import 'closed_exception.dart';
+import 'declarer.dart';
 import 'group.dart';
 import 'live_test.dart';
 import 'live_test_controller.dart';
@@ -28,21 +29,38 @@
   final Metadata metadata;
   final Trace trace;
 
-  /// The test body.
-  final AsyncFunction _body;
+  /// Whether this is a test defined using `setUpAll()` or `tearDownAll()`.
+  final bool isScaffoldAll;
 
-  LocalTest(this.name, this.metadata, body(), {this.trace}) : _body = body;
+  /// The test body.
+  final Function() _body;
+
+  /// Whether the test is run in its own error zone.
+  final bool _guarded;
+
+  /// Creates a new [LocalTest].
+  ///
+  /// If [guarded] is `true`, the test is run in its own error zone, and any
+  /// errors that escape that zone cause the test to fail. If it's `false`, it's
+  /// the caller's responsiblity to invoke [LiveTest.run] in the context of a
+  /// call to [Invoker.guard].
+  LocalTest(this.name, this.metadata, this._body,
+      {this.trace, bool guarded: true, this.isScaffoldAll: false})
+      : _guarded = guarded;
+
+  LocalTest._(this.name, this.metadata, this._body, this.trace, this._guarded,
+      this.isScaffoldAll);
 
   /// Loads a single runnable instance of this test.
   LiveTest load(Suite suite, {Iterable<Group> groups}) {
-    var invoker = new Invoker._(suite, this, groups: groups);
+    var invoker = new Invoker._(suite, this, groups: groups, guarded: _guarded);
     return invoker.liveTest;
   }
 
   Test forPlatform(TestPlatform platform, {OperatingSystem os}) {
     if (!metadata.testOn.evaluate(platform, os: os)) return null;
-    return new LocalTest(name, metadata.forPlatform(platform, os: os), _body,
-        trace: trace);
+    return new LocalTest._(name, metadata.forPlatform(platform, os: os), _body,
+        trace, _guarded, isScaffoldAll);
   }
 }
 
@@ -58,6 +76,9 @@
   LiveTest get liveTest => _controller.liveTest;
   LiveTestController _controller;
 
+  /// Whether to run this test in its own error zone.
+  final bool _guarded;
+
   /// Whether the test can be closed in the current zone.
   bool get _closable => Zone.current[_closableKey];
 
@@ -118,6 +139,22 @@
     return Zone.current[#test.invoker];
   }
 
+  /// Runs [callback] in a zone where unhandled errors from [LiveTest]s are
+  /// caught and dispatched to the appropriate [Invoker].
+  static T guard<T>(T callback()) =>
+      runZoned(callback, zoneSpecification: new ZoneSpecification(
+          // Use [handleUncaughtError] rather than [onError] so we can
+          // capture [zone] and with it the outstanding callback counter for
+          // the zone in which [error] was thrown.
+          handleUncaughtError: (self, _, zone, error, stackTrace) {
+        var invoker = zone[#test.invoker];
+        if (invoker != null) {
+          self.parent.run(() => invoker._handleError(zone, error, stackTrace));
+        } else {
+          self.parent.handleUncaughtError(error, stackTrace);
+        }
+      }));
+
   /// The zone that the top level of [_test.body] is running in.
   ///
   /// Tracking this ensures that [_timeoutTimer] isn't created in a
@@ -135,7 +172,9 @@
   /// Messages to print if and when this test fails.
   final _printsOnFailure = <String>[];
 
-  Invoker._(Suite suite, LocalTest test, {Iterable<Group> groups}) {
+  Invoker._(Suite suite, LocalTest test,
+      {Iterable<Group> groups, bool guarded: true})
+      : _guarded = guarded {
     _controller = new LiveTestController(
         suite, test, _onRun, _onCloseCompleter.complete,
         groups: groups);
@@ -147,7 +186,12 @@
   /// run in the reverse of the order they're declared.
   void addTearDown(callback()) {
     if (closed) throw new ClosedException();
-    _tearDowns.add(callback);
+
+    if (_test.isScaffoldAll) {
+      Declarer.current.addTearDownAll(callback);
+    } else {
+      _tearDowns.add(callback);
+    }
   }
 
   /// Tells the invoker that there's a callback running that it should wait for
@@ -282,7 +326,15 @@
   void _handleError(Zone zone, error, [StackTrace stackTrace]) {
     // Ignore errors propagated from previous test runs
     if (_runCount != zone[#runCount]) return;
-    if (stackTrace == null) stackTrace = new Chain.current();
+
+    // Get the chain information from the zone in which the error was thrown.
+    zone.run(() {
+      if (stackTrace == null) {
+        stackTrace = new Chain.current();
+      } else {
+        stackTrace = new Chain.forTrace(stackTrace);
+      }
+    });
 
     // Store these here because they'll change when we set the state below.
     var shouldBeDone = liveTest.state.shouldBeDone;
@@ -334,60 +386,68 @@
 
     _runCount++;
     Chain.capture(() {
-      runZoned(() async {
-        _invokerZone = Zone.current;
-        _outstandingCallbackZones.add(Zone.current);
+      _guardIfGuarded(() {
+        runZoned(() async {
+          _invokerZone = Zone.current;
+          _outstandingCallbackZones.add(Zone.current);
 
-        // Run the test asynchronously so that the "running" state change has
-        // a chance to hit its event handler(s) before the test produces an
-        // error. If an error is emitted before the first state change is
-        // handled, we can end up with [onError] callbacks firing before the
-        // corresponding [onStateChkange], which violates the timing
-        // guarantees.
-        //
-        // Using [new Future] also avoids starving the DOM or other
-        // microtask-level events.
-        new Future(() async {
-          await _test._body();
-          await unclosable(_runTearDowns);
-          removeOutstandingCallback();
-        });
+          // Run the test asynchronously so that the "running" state change
+          // has a chance to hit its event handler(s) before the test produces
+          // an error. If an error is emitted before the first state change is
+          // handled, we can end up with [onError] callbacks firing before the
+          // corresponding [onStateChange], which violates the timing
+          // guarantees.
+          //
+          // Using [new Future] also avoids starving the DOM or other
+          // microtask-level events.
+          new Future(() async {
+            await _test._body();
+            await unclosable(_runTearDowns);
+            removeOutstandingCallback();
+          });
 
-        await _outstandingCallbacks.noOutstandingCallbacks;
-        if (_timeoutTimer != null) _timeoutTimer.cancel();
+          await _outstandingCallbacks.noOutstandingCallbacks;
+          if (_timeoutTimer != null) _timeoutTimer.cancel();
 
-        if (liveTest.state.result != Result.success &&
-            _runCount < liveTest.test.metadata.retry + 1) {
+          if (liveTest.state.result != Result.success &&
+              _runCount < liveTest.test.metadata.retry + 1) {
+            _controller
+                .message(new Message.print("Retry: ${liveTest.test.name}"));
+            _onRun();
+            return;
+          }
+
           _controller
-              .message(new Message.print("Retry: ${liveTest.test.name}"));
-          _onRun();
-          return;
-        }
+              .setState(new State(Status.complete, liveTest.state.result));
 
-        _controller.setState(new State(Status.complete, liveTest.state.result));
-
-        _controller.completer.complete();
-      },
-          zoneValues: {
-            #test.invoker: this,
-            // Use the invoker as a key so that multiple invokers can have different
-            // outstanding callback counters at once.
-            _counterKey: outstandingCallbacksForBody,
-            _closableKey: true,
-            #runCount: _runCount
-          },
-          zoneSpecification: new ZoneSpecification(
-              print: (self, parent, zone, line) =>
-                  _controller.message(new Message.print(line)),
-              // Use [handleUncaughtError] rather than [onError] so we can
-              // capture [zone] and with it the outstanding callback counter for
-              // the zone in which [error] was thrown.
-              handleUncaughtError: (self, _, zone, error, stackTrace) => self
-                  .parent
-                  .run(() => _handleError(zone, error, stackTrace))));
-    }, when: liveTest.test.metadata.chainStackTraces);
+          _controller.completer.complete();
+        },
+            zoneValues: {
+              #test.invoker: this,
+              // Use the invoker as a key so that multiple invokers can have
+              // different outstanding callback counters at once.
+              _counterKey: outstandingCallbacksForBody,
+              _closableKey: true,
+              #runCount: _runCount,
+            },
+            zoneSpecification: new ZoneSpecification(
+                print: (_, __, ___, line) => _print(line)));
+      });
+    }, when: liveTest.test.metadata.chainStackTraces, errorZone: false);
   }
 
+  /// Runs [callback], in a [Invoker.guard] context if [_guarded] is `true`.
+  void _guardIfGuarded(void callback()) {
+    if (_guarded) {
+      Invoker.guard(callback);
+    } else {
+      callback();
+    }
+  }
+
+  /// Prints [text] as a message to [_controller].
+  void _print(String text) => _controller.message(new Message.print(text));
+
   /// Run [_tearDowns] in reverse order.
   Future _runTearDowns() async {
     while (_tearDowns.isNotEmpty) {
diff --git a/test/lib/src/bootstrap/node.dart b/test/lib/src/bootstrap/node.dart
index 961377e..baf4283 100644
--- a/test/lib/src/bootstrap/node.dart
+++ b/test/lib/src/bootstrap/node.dart
@@ -3,7 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import "../runner/plugin/remote_platform_helpers.dart";
-import "../runner/node/stdio_channel.dart";
+import "../runner/node/socket_channel.dart";
 
 /// Bootstraps a browser test to communicate with the test runner.
 ///
@@ -11,5 +11,5 @@
 /// transformer which will bootstrap your test and call this method.
 void internalBootstrapNodeTest(Function getMain()) {
   var channel = serializeSuite(getMain);
-  stdioChannel().pipe(channel);
+  socketChannel().pipe(channel);
 }
diff --git a/test/lib/src/frontend/expect.dart b/test/lib/src/frontend/expect.dart
index 4272b69..5bdcd2b 100644
--- a/test/lib/src/frontend/expect.dart
+++ b/test/lib/src/frontend/expect.dart
@@ -5,6 +5,7 @@
 import 'dart:async';
 
 import 'package:matcher/matcher.dart';
+import 'package:meta/meta.dart';
 
 import '../backend/closed_exception.dart';
 import '../backend/invoker.dart';
@@ -156,12 +157,12 @@
     reason ??= '$e at $trace';
   }
   fail(formatter(actual, matcher, reason, matchState, verbose));
-  return _emptyFuture;
 }
 
 /// Convenience method for throwing a new [TestFailure] with the provided
 /// [message].
-void fail(String message) => throw new TestFailure(message);
+@alwaysThrows
+Null fail(String message) => throw new TestFailure(message);
 
 // The default error formatter.
 @Deprecated("Will be removed in 0.13.0.")
diff --git a/test/lib/src/frontend/expect_async.dart b/test/lib/src/frontend/expect_async.dart
index 9a37bdf..85f4d0a 100644
--- a/test/lib/src/frontend/expect_async.dart
+++ b/test/lib/src/frontend/expect_async.dart
@@ -5,11 +5,9 @@
 import 'dart:async';
 
 import '../backend/invoker.dart';
+import '../util/placeholder.dart';
 import 'expect.dart';
 
-/// An object used to detect unpassed arguments.
-const _PLACEHOLDER = const Object();
-
 // Function types returned by expectAsync# methods.
 
 typedef T Func0<T>();
@@ -157,39 +155,39 @@
   // argument count of zero.
   T max0() => max6();
 
-  T max1([Object a0 = _PLACEHOLDER]) => max6(a0);
+  T max1([Object a0 = placeholder]) => max6(a0);
 
-  T max2([Object a0 = _PLACEHOLDER, Object a1 = _PLACEHOLDER]) => max6(a0, a1);
+  T max2([Object a0 = placeholder, Object a1 = placeholder]) => max6(a0, a1);
 
   T max3(
-          [Object a0 = _PLACEHOLDER,
-          Object a1 = _PLACEHOLDER,
-          Object a2 = _PLACEHOLDER]) =>
+          [Object a0 = placeholder,
+          Object a1 = placeholder,
+          Object a2 = placeholder]) =>
       max6(a0, a1, a2);
 
   T max4(
-          [Object a0 = _PLACEHOLDER,
-          Object a1 = _PLACEHOLDER,
-          Object a2 = _PLACEHOLDER,
-          Object a3 = _PLACEHOLDER]) =>
+          [Object a0 = placeholder,
+          Object a1 = placeholder,
+          Object a2 = placeholder,
+          Object a3 = placeholder]) =>
       max6(a0, a1, a2, a3);
 
   T max5(
-          [Object a0 = _PLACEHOLDER,
-          Object a1 = _PLACEHOLDER,
-          Object a2 = _PLACEHOLDER,
-          Object a3 = _PLACEHOLDER,
-          Object a4 = _PLACEHOLDER]) =>
+          [Object a0 = placeholder,
+          Object a1 = placeholder,
+          Object a2 = placeholder,
+          Object a3 = placeholder,
+          Object a4 = placeholder]) =>
       max6(a0, a1, a2, a3, a4);
 
   T max6(
-          [Object a0 = _PLACEHOLDER,
-          Object a1 = _PLACEHOLDER,
-          Object a2 = _PLACEHOLDER,
-          Object a3 = _PLACEHOLDER,
-          Object a4 = _PLACEHOLDER,
-          Object a5 = _PLACEHOLDER]) =>
-      _run([a0, a1, a2, a3, a4, a5].where((a) => a != _PLACEHOLDER));
+          [Object a0 = placeholder,
+          Object a1 = placeholder,
+          Object a2 = placeholder,
+          Object a3 = placeholder,
+          Object a4 = placeholder,
+          Object a5 = placeholder]) =>
+      _run([a0, a1, a2, a3, a4, a5].where((a) => a != placeholder));
 
   /// Runs the wrapped function with [args] and returns its return value.
   T _run(Iterable args) {
diff --git a/test/lib/src/frontend/future_matchers.dart b/test/lib/src/frontend/future_matchers.dart
index 0284a4d..31f78ac 100644
--- a/test/lib/src/frontend/future_matchers.dart
+++ b/test/lib/src/frontend/future_matchers.dart
@@ -9,6 +9,7 @@
 import '../utils.dart';
 import 'async_matcher.dart';
 import 'expect.dart';
+import 'utils.dart';
 
 /// Matches a [Future] that completes successfully with a value.
 ///
@@ -86,31 +87,23 @@
 /// Note that this creates an asynchronous expectation. The call to
 /// `expect()` that includes this will return immediately and execution will
 /// continue.
-final Matcher doesNotComplete = const _DoesNotComplete(20);
+final Matcher doesNotComplete = const _DoesNotComplete();
 
 class _DoesNotComplete extends Matcher {
-  final int _timesToPump;
-  const _DoesNotComplete(this._timesToPump);
-
-  // TODO(grouma) - Make this a top level function
-  Future _pumpEventQueue(times) {
-    if (times == 0) return new Future.value();
-    return new Future(() => _pumpEventQueue(times - 1));
-  }
+  const _DoesNotComplete();
 
   Description describe(Description description) {
     description.add("does not complete");
     return description;
   }
 
-  @override
   bool matches(item, Map matchState) {
     if (item is! Future) return false;
     item.then((value) {
       fail('Future was not expected to complete but completed with a value of '
           '$value');
     });
-    expect(_pumpEventQueue(_timesToPump), completes);
+    expect(pumpEventQueue(), completes);
     return true;
   }
 
diff --git a/test/lib/src/frontend/never_called.dart b/test/lib/src/frontend/never_called.dart
new file mode 100644
index 0000000..b088579
--- /dev/null
+++ b/test/lib/src/frontend/never_called.dart
@@ -0,0 +1,67 @@
+// 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:async';
+
+import 'package:stack_trace/stack_trace.dart';
+
+import '../util/placeholder.dart';
+import '../utils.dart';
+import 'expect.dart';
+import 'future_matchers.dart';
+import 'utils.dart';
+
+/// Returns a function that causes the test to fail if it's called.
+///
+/// This can safely be passed in place of any callback that takes ten or fewer
+/// positional parameters. For example:
+///
+/// ```
+/// // Asserts that the stream never emits an event.
+/// stream.listen(neverCalled);
+/// ```
+///
+/// This also ensures that the test doesn't complete until a call to
+/// [pumpEventQueue] finishes, so that the callback has a chance to be called.
+T Function<T>(
+    [Object,
+    Object,
+    Object,
+    Object,
+    Object,
+    Object,
+    Object,
+    Object,
+    Object,
+    Object]) get neverCalled {
+  // Make sure the test stays alive long enough to call the function if it's
+  // going to.
+  expect(pumpEventQueue(), completes);
+
+  var zone = Zone.current;
+  return <T>(
+      [a1 = placeholder,
+      a2 = placeholder,
+      a3 = placeholder,
+      a4 = placeholder,
+      a5 = placeholder,
+      a6 = placeholder,
+      a7 = placeholder,
+      a8 = placeholder,
+      a9 = placeholder,
+      a10 = placeholder]) {
+    var arguments = [a1, a2, a3, a4, a5, a6, a7, a8, a9, a10]
+        .where((argument) => argument != placeholder)
+        .toList();
+
+    zone.handleUncaughtError(
+        new TestFailure(
+            "Callback should never have been called, but it was called with" +
+                (arguments.isEmpty
+                    ? " no arguments."
+                    : ":\n${bullet(arguments.map(prettyPrint))}")),
+        zone.run(() => new Chain.current()));
+    return null;
+  };
+}
diff --git a/test/lib/src/frontend/utils.dart b/test/lib/src/frontend/utils.dart
new file mode 100644
index 0000000..209c4d1
--- /dev/null
+++ b/test/lib/src/frontend/utils.dart
@@ -0,0 +1,22 @@
+// 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:async';
+
+/// Returns a [Future] that completes after the [event loop][] has run the given
+/// number of [times] (20 by default).
+///
+/// [event loop]: https://webdev.dartlang.org/articles/performance/event-loop#darts-event-loop-and-queues
+///
+/// Awaiting this approximates waiting until all asynchronous work (other than
+/// work that's waiting for external resources) completes.
+Future pumpEventQueue({int times}) {
+  times ??= 20;
+  if (times == 0) return new Future.value();
+  // Use [new Future] future to allow microtask events to finish. The [new
+  // Future.value] constructor uses scheduleMicrotask itself and would therefore
+  // not wait for microtask callbacks that are scheduled after invoking this
+  // method.
+  return new Future(() => pumpEventQueue(times: times - 1));
+}
diff --git a/test/lib/src/runner/browser/browser.dart b/test/lib/src/runner/browser/browser.dart
index e160231..1681a39 100644
--- a/test/lib/src/runner/browser/browser.dart
+++ b/test/lib/src/runner/browser/browser.dart
@@ -3,9 +3,11 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'dart:async';
+import 'dart:convert';
 import 'dart:io';
 
 import 'package:stack_trace/stack_trace.dart';
+import 'package:typed_data/typed_data.dart';
 
 import '../../utils.dart';
 import '../application_exception.dart';
@@ -51,11 +53,8 @@
   Future get onExit => _onExitCompleter.future;
   final _onExitCompleter = new Completer();
 
-  Future _drainAndIgnore(Stream s) async {
-    try {
-      await s.drain();
-    } on StateError catch (_) {}
-  }
+  /// Standard IO streams for the underlying browser process.
+  final _ioSubscriptions = <StreamSubscription>[];
 
   /// Creates a new browser.
   ///
@@ -71,9 +70,17 @@
       var process = await startBrowser();
       _processCompleter.complete(process);
 
+      var output = new Uint8Buffer();
+      drainOutput(Stream<List<int>> stream) {
+        try {
+          _ioSubscriptions
+              .add(stream.listen(output.addAll, cancelOnError: true));
+        } on StateError catch (_) {}
+      }
+
       // If we don't drain the stdout and stderr the process can hang.
-      await Future.wait(
-          [_drainAndIgnore(process.stdout), _drainAndIgnore(process.stderr)]);
+      drainOutput(process.stdout);
+      drainOutput(process.stderr);
 
       var exitCode = await process.exitCode;
 
@@ -92,8 +99,13 @@
       }
 
       if (!_closed && exitCode != 0) {
-        throw new ApplicationException(
-            "$name failed with exit code $exitCode.");
+        var outputString = UTF8.decode(output);
+        var message = "$name failed with exit code $exitCode.";
+        if (outputString.isNotEmpty) {
+          message += "\nStandard output:\n$outputString";
+        }
+
+        throw new ApplicationException(message);
       }
 
       _onExitCompleter.complete();
@@ -120,6 +132,13 @@
   Future close() {
     _closed = true;
 
+    // If we don't manually close the stream the test runner can hang.
+    // For example this happens with Chrome Headless.
+    // See SDK issue: https://github.com/dart-lang/sdk/issues/31264
+    for (var stream in _ioSubscriptions) {
+      stream.cancel();
+    }
+
     _process.then((process) {
       // Dartium has a difficult time being killed on Linux. To ensure it is
       // properly closed, find all children processes and kill those first.
diff --git a/test/lib/src/runner/browser/browser_manager.dart b/test/lib/src/runner/browser/browser_manager.dart
index 9f9e3c9..3472325 100644
--- a/test/lib/src/runner/browser/browser_manager.dart
+++ b/test/lib/src/runner/browser/browser_manager.dart
@@ -188,7 +188,7 @@
     }));
 
     _environment = _loadBrowserEnvironment();
-    _channel.stream.listen(_onMessage, onDone: close);
+    _channel.stream.listen((message) => _onMessage(message), onDone: close);
   }
 
   /// Loads [_BrowserEnvironment].
diff --git a/test/lib/src/runner/browser/chrome.dart b/test/lib/src/runner/browser/chrome.dart
index e2150e2..9fe727b 100644
--- a/test/lib/src/runner/browser/chrome.dart
+++ b/test/lib/src/runner/browser/chrome.dart
@@ -42,7 +42,19 @@
           "--no-default-browser-check",
           "--disable-default-apps",
           "--disable-translate",
-        ]..addAll(settings.arguments);
+        ];
+
+        if (!debug) {
+          args.addAll([
+            "--headless",
+            "--disable-gpu",
+            // We don't actually connect to the remote debugger, but Chrome will
+            // close as soon as the page is loaded if we don't turn it on.
+            "--remote-debugging-port=0"
+          ]);
+        }
+
+        args.addAll(settings.arguments);
 
         // Currently, Chrome doesn't provide any way of ensuring that this port
         // was successfully bound. It produces an error if the binding fails,
diff --git a/test/lib/src/runner/browser/content_shell.dart b/test/lib/src/runner/browser/content_shell.dart
index e52bf1f..682f6ea 100644
--- a/test/lib/src/runner/browser/content_shell.dart
+++ b/test/lib/src/runner/browser/content_shell.dart
@@ -107,7 +107,7 @@
       };
 
       if (!debug) return tryPort();
-      return getUnusedPort<Future<Process>>(tryPort);
+      return getUnusedPort<Process>(tryPort);
     }, observatoryCompleter.future, remoteDebuggerCompleter.future);
   }
 
diff --git a/test/lib/src/runner/configuration/load.dart b/test/lib/src/runner/configuration/load.dart
index cd9acf9..eee575f 100644
--- a/test/lib/src/runner/configuration/load.dart
+++ b/test/lib/src/runner/configuration/load.dart
@@ -286,7 +286,8 @@
 
     var paths = _getList("paths", (pathNode) {
       _validate(pathNode, "Paths must be strings.", (value) => value is String);
-      _validate(pathNode, "Paths must be relative.", p.url.isRelative);
+      _validate(pathNode, "Paths must be relative.",
+          (value) => p.url.isRelative(value));
 
       return _parseNode(pathNode, "path", p.fromUri);
     });
diff --git a/test/lib/src/runner/hybrid_listener.dart b/test/lib/src/runner/hybrid_listener.dart
index a8f1678..8dad2ab 100644
--- a/test/lib/src/runner/hybrid_listener.dart
+++ b/test/lib/src/runner/hybrid_listener.dart
@@ -14,8 +14,8 @@
 
 /// A sink transformer that wraps data and error events so that errors can be
 /// decoded after being JSON-serialized.
-final _transformer =
-    new StreamSinkTransformer.fromHandlers(handleData: (data, sink) {
+final _transformer = new StreamSinkTransformer<dynamic, dynamic>.fromHandlers(
+    handleData: (data, sink) {
   ensureJsonEncodable(data);
   sink.add({"type": "data", "data": data});
 }, handleError: (error, stackTrace, sink) {
diff --git a/test/lib/src/runner/load_suite.dart b/test/lib/src/runner/load_suite.dart
index 308357a..1241ad2 100644
--- a/test/lib/src/runner/load_suite.dart
+++ b/test/lib/src/runner/load_suite.dart
@@ -19,6 +19,14 @@
 import 'plugin/environment.dart';
 import 'runner_suite.dart';
 
+/// The timeout for loading a test suite.
+///
+/// We want this to be long enough that even a very large application being
+/// compiled with dart2js doesn't trigger it, but short enough that it fires
+/// before the host kills it. For example, Google's Forge service has a
+/// 15-minute timeout.
+final _timeout = new Duration(minutes: 12);
+
 /// A [Suite] emitted by a [Loader] that provides a test-like interface for
 /// loading a test file.
 ///
@@ -75,31 +83,29 @@
       invoker.addOutstandingCallback();
 
       invoke(() async {
-        try {
-          var suite = await body();
-          if (completer.isCompleted) {
-            // If the load test has already been closed, close the suite it
-            // generated.
-            suite?.close();
-            return;
-          }
-
-          completer
-              .complete(suite == null ? null : new Pair(suite, Zone.current));
-          invoker.removeOutstandingCallback();
-        } catch (error, stackTrace) {
-          registerException(error, stackTrace);
-          if (!completer.isCompleted) completer.complete();
+        var suite = await body();
+        if (completer.isCompleted) {
+          // If the load test has already been closed, close the suite it
+          // generated.
+          suite?.close();
+          return;
         }
-      });
 
-      // If the test is forcibly closed, exit immediately. It doesn't have any
-      // cleanup to do that won't be handled by Loader.close.
-      invoker.onClose.then((_) {
-        if (completer.isCompleted) return;
-        completer.complete();
+        completer
+            .complete(suite == null ? null : new Pair(suite, Zone.current));
         invoker.removeOutstandingCallback();
       });
+
+      // If the test completes before the body callback, either an out-of-band
+      // error occurred or the test was canceled. Either way, we return a `null`
+      // suite.
+      invoker.liveTest.onComplete.then((_) {
+        if (!completer.isCompleted) completer.complete();
+      });
+
+      // If the test is forcibly closed, let it complete, since load tests don't
+      // have timeouts.
+      invoker.onClose.then((_) => invoker.removeOutstandingCallback());
     }, completer.future, path: path, platform: platform);
   }
 
@@ -130,9 +136,7 @@
       : super(
             new Group.root([
               new LocalTest(
-                  name,
-                  new Metadata(timeout: new Timeout(new Duration(minutes: 5))),
-                  body)
+                  name, new Metadata(timeout: new Timeout(_timeout)), body)
             ]),
             path: path,
             platform: platform);
diff --git a/test/lib/src/runner/loader.dart b/test/lib/src/runner/loader.dart
index 5f0e8ae..31b1a99 100644
--- a/test/lib/src/runner/loader.dart
+++ b/test/lib/src/runner/loader.dart
@@ -15,7 +15,6 @@
 import '../backend/invoker.dart';
 import '../backend/test_platform.dart';
 import '../util/io.dart';
-import '../utils.dart';
 import 'browser/platform.dart';
 import 'configuration.dart';
 import 'configuration/suite.dart';
diff --git a/test/lib/src/runner/node/platform.dart b/test/lib/src/runner/node/platform.dart
index c6e7633..520639b 100644
--- a/test/lib/src/runner/node/platform.dart
+++ b/test/lib/src/runner/node/platform.dart
@@ -7,6 +7,7 @@
 import 'dart:convert';
 
 import 'package:async/async.dart';
+import 'package:multi_server_socket/multi_server_socket.dart';
 import 'package:node_preamble/preamble.dart' as preamble;
 import 'package:package_resolver/package_resolver.dart';
 import 'package:path/path.dart' as p;
@@ -91,15 +92,22 @@
   /// source map for the compiled suite.
   Future<Pair<StreamChannel, StackTraceMapper>> _loadChannel(String path,
       TestPlatform platform, SuiteConfiguration suiteConfig) async {
-    var pair = await _spawnProcess(path, platform, suiteConfig);
+    var server = await MultiServerSocket.loopback(0);
+
+    var pair = await _spawnProcess(path, platform, suiteConfig, server.port);
     var process = pair.first;
 
-    // Node normally doesn't emit any standard error, but if it does we forward
-    // it to the print handler so it's associated with the load test.
+    // Forward Node's standard IO to the print handler so it's associated with
+    // the load test.
+    //
+    // TODO(nweiz): Associate this with the current test being run, if any.
+    process.stdout.transform(lineSplitter).listen(print);
     process.stderr.transform(lineSplitter).listen(print);
 
-    var channel = new StreamChannel.withGuarantees(
-            process.stdout, process.stdin)
+    var socket = await server.first;
+    // TODO(nweiz): Remove the DelegatingStreamSink wrapper when sdk#31504 is
+    // fixed.
+    var channel = new StreamChannel(socket, new DelegatingStreamSink(socket))
         .transform(new StreamChannelTransformer.fromCodec(UTF8))
         .transform(chunksToLines)
         .transform(jsonDocument)
@@ -115,8 +123,11 @@
   ///
   /// Returns that channel along with a [StackTraceMapper] representing the
   /// source map for the compiled suite.
-  Future<Pair<Process, StackTraceMapper>> _spawnProcess(String path,
-      TestPlatform platform, SuiteConfiguration suiteConfig) async {
+  Future<Pair<Process, StackTraceMapper>> _spawnProcess(
+      String path,
+      TestPlatform platform,
+      SuiteConfiguration suiteConfig,
+      int socketPort) async {
     var dir = new Directory(_compiledDir).createTempSync('test_').path;
     var jsPath = p.join(dir, p.basename(path) + ".node_test.dart.js");
 
@@ -146,7 +157,8 @@
             sdkRoot: p.toUri(sdkDir));
       }
 
-      return new Pair(await _startProcess(platform, jsPath), mapper);
+      return new Pair(
+          await _startProcess(platform, jsPath, socketPort), mapper);
     }
 
     var url = _config.pubServeUrl.resolveUri(
@@ -165,15 +177,22 @@
           sdkRoot: p.toUri('packages/\$sdk'));
     }
 
-    return new Pair(await _startProcess(platform, jsPath), mapper);
+    return new Pair(await _startProcess(platform, jsPath, socketPort), mapper);
   }
 
   /// Starts the Node.js process for [platform] with [jsPath].
-  Future<Process> _startProcess(TestPlatform platform, String jsPath) async {
+  Future<Process> _startProcess(
+      TestPlatform platform, String jsPath, int socketPort) async {
     var settings = _settings[platform];
+
+    var nodeModules = p.absolute('node_modules');
+    var nodePath = Platform.environment["NODE_PATH"];
+    nodePath = nodePath == null ? nodeModules : "$nodePath:$nodeModules";
+
     try {
-      return await Process.start(
-          settings.executable, settings.arguments.toList()..add(jsPath));
+      return await Process.start(settings.executable,
+          settings.arguments.toList()..add(jsPath)..add(socketPort.toString()),
+          environment: {'NODE_PATH': nodePath});
     } catch (error, stackTrace) {
       await new Future.error(
           new ApplicationException(
diff --git a/test/lib/src/runner/node/socket_channel.dart b/test/lib/src/runner/node/socket_channel.dart
new file mode 100644
index 0000000..322f192
--- /dev/null
+++ b/test/lib/src/runner/node/socket_channel.dart
@@ -0,0 +1,44 @@
+// 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.
+
+@JS()
+library _;
+
+import 'package:js/js.dart';
+import 'package:stream_channel/stream_channel.dart';
+
+import '../../utils.dart';
+
+@JS("require")
+external _Net _require(String module);
+
+@JS("process.argv")
+external List<String> get _args;
+
+@JS()
+class _Net {
+  external _Socket connect(int port);
+}
+
+@JS()
+class _Socket {
+  external setEncoding(String encoding);
+  external on(String event, void callback(String chunk));
+  external write(String data);
+}
+
+/// Returns a [StreamChannel] of JSON-encodable objects that communicates over a
+/// socket whose port is given by `process.argv[2]`.
+StreamChannel socketChannel() {
+  var controller = new StreamChannelController<String>(
+      allowForeignErrors: false, sync: true);
+  var net = _require("net");
+  var socket = net.connect(int.parse(_args[2]));
+  socket.setEncoding("utf8");
+
+  controller.local.stream.listen((chunk) => socket.write(chunk));
+  socket.on("data", allowInterop(controller.local.sink.add));
+
+  return controller.foreign.transform(chunksToLines).transform(jsonDocument);
+}
diff --git a/test/lib/src/runner/node/stdio_channel.dart b/test/lib/src/runner/node/stdio_channel.dart
deleted file mode 100644
index 5f16f3a..0000000
--- a/test/lib/src/runner/node/stdio_channel.dart
+++ /dev/null
@@ -1,47 +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.
-
-@JS()
-library _;
-
-import 'package:js/js.dart';
-import 'package:stream_channel/stream_channel.dart';
-
-import '../../utils.dart';
-
-@JS("require")
-external _Process _require(String module);
-
-@JS()
-class _Process {
-  external _Stdin get stdin;
-  external _Stdout get stdout;
-}
-
-@JS()
-class _Stdin {
-  external setEncoding(String encoding);
-  external on(String event, void callback(String chunk));
-}
-
-@JS()
-class _Stdout {
-  external setDefaultEncoding(String encoding);
-  external write(String chunk);
-}
-
-/// Returns a [StreamChannel] of JSON-encodable objects that communicates over
-/// the current process's stdout and stdin streams.
-StreamChannel stdioChannel() {
-  var controller = new StreamChannelController<String>(
-      allowForeignErrors: false, sync: true);
-  var process = _require("process");
-  process.stdin.setEncoding("utf8");
-  process.stdout.setDefaultEncoding("utf8");
-
-  controller.local.stream.listen((chunk) => process.stdout.write(chunk));
-  process.stdin.on("data", allowInterop(controller.local.sink.add));
-
-  return controller.foreign.transform(chunksToLines).transform(jsonDocument);
-}
diff --git a/test/lib/src/runner/plugin/platform_helpers.dart b/test/lib/src/runner/plugin/platform_helpers.dart
index b41e5ba..dba0f5d 100644
--- a/test/lib/src/runner/plugin/platform_helpers.dart
+++ b/test/lib/src/runner/plugin/platform_helpers.dart
@@ -15,7 +15,6 @@
 import '../../util/io.dart';
 import '../../util/remote_exception.dart';
 import '../../util/stack_trace_mapper.dart';
-import '../application_exception.dart';
 import '../configuration.dart';
 import '../configuration/suite.dart';
 import '../environment.dart';
@@ -23,8 +22,6 @@
 import '../runner_suite.dart';
 import '../runner_test.dart';
 
-final _deserializeTimeout = new Duration(minutes: 8);
-
 /// A helper method for creating a [RunnerSuiteController] containing tests
 /// that communicate over [channel].
 ///
@@ -53,7 +50,9 @@
   suiteChannel.sink.add({
     'platform': platform.serialize(),
     'metadata': suiteConfig.metadata.serialize(),
-    'os': platform == TestPlatform.vm ? currentOS.identifier : null,
+    'os': (platform == TestPlatform.vm || platform == TestPlatform.nodeJS)
+        ? currentOS.identifier
+        : null,
     'asciiGlyphs': Platform.isWindows,
     'path': path,
     'collectTraces': Configuration.current.reporter == 'json',
@@ -113,13 +112,7 @@
       });
 
   return new RunnerSuiteController(
-      environment,
-      suiteConfig,
-      await completer.future.timeout(_deserializeTimeout, onTimeout: () {
-        throw new ApplicationException(
-            "Timed out while loading the test suite.\n"
-            "It's likely that there's a missing import or syntax error.");
-      }),
+      environment, suiteConfig, await completer.future,
       path: path,
       platform: platform,
       os: currentOS,
diff --git a/test/lib/src/runner/remote_listener.dart b/test/lib/src/runner/remote_listener.dart
index 883101f..29f7ebc 100644
--- a/test/lib/src/runner/remote_listener.dart
+++ b/test/lib/src/runner/remote_listener.dart
@@ -9,6 +9,7 @@
 
 import '../backend/declarer.dart';
 import '../backend/group.dart';
+import '../backend/invoker.dart';
 import '../backend/live_test.dart';
 import '../backend/metadata.dart';
 import '../backend/operating_system.dart';
@@ -79,7 +80,7 @@
       verboseChain = metadata.verboseTrace;
       var declarer = new Declarer(
           metadata: metadata,
-          platformVariables: message['platformVariables'].toSet(),
+          platformVariables: new Set.from(message['platformVariables']),
           collectTraces: message['collectTraces'],
           noRetry: message['noRetry']);
 
@@ -97,7 +98,14 @@
               : OperatingSystem.find(message['os']),
           path: message['path']);
 
-      new RemoteListener._(suite, printZone)._listen(channel);
+      runZoned(() {
+        Invoker.guard(
+            () => new RemoteListener._(suite, printZone)._listen(channel));
+      },
+          // Make the declarer visible to running tests so that they'll throw
+          // useful errors when calling `test()` and `group()` within a test,
+          // and so they can add to the declarer's `tearDownAll()` list.
+          zoneValues: {#test.declarer: declarer});
     }, onError: (error, stackTrace) {
       _sendError(channel, error, stackTrace, verboseChain);
     }, zoneSpecification: new ZoneSpecification(print: (_, __, ___, line) {
@@ -108,8 +116,8 @@
     return controller.foreign;
   }
 
-  /// Returns a [Set] from a JSON serialized list.
-  static Set<String> _deserializeSet(List<String> list) {
+  /// Returns a [Set] from a JSON serialized list of strings.
+  static Set<String> _deserializeSet(List list) {
     if (list == null) return null;
     if (list.isEmpty) return null;
     return new Set.from(list);
diff --git a/test/lib/src/runner/reporter/compact.dart b/test/lib/src/runner/reporter/compact.dart
index cb4cc9a..2a18996 100644
--- a/test/lib/src/runner/reporter/compact.dart
+++ b/test/lib/src/runner/reporter/compact.dart
@@ -11,17 +11,13 @@
 import '../../backend/state.dart';
 import '../../utils.dart';
 import '../../utils.dart' as utils;
+import '../../util/io.dart';
 import '../configuration.dart';
 import '../engine.dart';
 import '../load_exception.dart';
 import '../load_suite.dart';
 import '../reporter.dart';
 
-/// The maximum console line length.
-///
-/// Lines longer than this will be cropped.
-const _lineLength = 100;
-
 /// A reporter that prints test results to the console in a single
 /// continuously-updating line.
 class CompactReporter implements Reporter {
@@ -251,7 +247,7 @@
       stdout.write(message);
 
       // Add extra padding to overwrite any load messages.
-      if (!_printedNewline) stdout.write(" " * (_lineLength - message.length));
+      if (!_printedNewline) stdout.write(" " * (lineLength - message.length));
       stdout.writeln();
     } else if (!success) {
       _progressLine('Some tests failed.', color: _red);
@@ -268,7 +264,7 @@
   /// Prints a line representing the current state of the tests.
   ///
   /// [message] goes after the progress report, and may be truncated to fit the
-  /// entire line within [_lineLength]. If [color] is passed, it's used as the
+  /// entire line within [lineLength]. If [color] is passed, it's used as the
   /// color for [message]. If [suffix] is passed, it's added to the end of
   /// [message].
   bool _progressLine(String message,
@@ -329,16 +325,16 @@
     buffer.write(': ');
     buffer.write(color);
 
-    // Ensure the line fits within [_lineLength]. [buffer] includes the color
+    // Ensure the line fits within [lineLength]. [buffer] includes the color
     // escape sequences too. Because these sequences are not visible characters,
     // we make sure they are not counted towards the limit.
     var length = withoutColors(buffer.toString()).length;
-    if (truncate) message = utils.truncate(message, _lineLength - length);
+    if (truncate) message = utils.truncate(message, lineLength - length);
     buffer.write(message);
     buffer.write(_noColor);
 
     // Pad the rest of the line so that it looks erased.
-    buffer.write(' ' * (_lineLength - withoutColors(buffer.toString()).length));
+    buffer.write(' ' * (lineLength - withoutColors(buffer.toString()).length));
     stdout.write(buffer.toString());
 
     _printedNewline = false;
diff --git a/test/lib/src/runner/reporter/expanded.dart b/test/lib/src/runner/reporter/expanded.dart
index 00d7915..eb0b99a 100644
--- a/test/lib/src/runner/reporter/expanded.dart
+++ b/test/lib/src/runner/reporter/expanded.dart
@@ -14,11 +14,6 @@
 import '../load_suite.dart';
 import '../reporter.dart';
 
-/// The maximum console line length.
-///
-/// Lines longer than this will be cropped.
-const _lineLength = 100;
-
 /// A reporter that prints each test on its own line.
 ///
 /// This is currently used in place of [CompactReporter] by `lib/test.dart`,
@@ -238,10 +233,9 @@
 
   /// Prints a line representing the current state of the tests.
   ///
-  /// [message] goes after the progress report, and may be truncated to fit the
-  /// entire line within [_lineLength]. If [color] is passed, it's used as the
-  /// color for [message]. If [suffix] is passed, it's added to the end of
-  /// [message].
+  /// [message] goes after the progress report. If [color] is passed, it's used
+  /// as the color for [message]. If [suffix] is passed, it's added to the end
+  /// of [message].
   void _progressLine(String message, {String color, String suffix}) {
     // Print nothing if nothing has changed since the last progress line.
     if (_engine.passed.length == _lastProgressPassed &&
diff --git a/test/lib/src/util/io.dart b/test/lib/src/util/io.dart
index 91a90fd..90fd561 100644
--- a/test/lib/src/util/io.dart
+++ b/test/lib/src/util/io.dart
@@ -18,6 +18,23 @@
 /// The ASCII code for a carriage return character.
 const _carriageReturn = 0xD;
 
+/// The default line length for output when there isn't a terminal attached to
+/// stdout.
+const _defaultLineLength = 200;
+
+/// The maximum line length for output.
+final int lineLength = () {
+  try {
+    return stdout.terminalColumns;
+  } on UnsupportedError {
+    // This can throw an [UnsupportedError] if we're running in a JS context
+    // where `dart:io` is unavaiable.
+    return _defaultLineLength;
+  } on StdoutException {
+    return _defaultLineLength;
+  }
+}();
+
 /// The root directory of the Dart SDK.
 final String sdkDir = p.dirname(p.dirname(Platform.resolvedExecutable));
 
@@ -103,6 +120,36 @@
   });
 }
 
+/// Wraps [text] so that it fits within [lineLength].
+///
+/// This preserves existing newlines and doesn't consider terminal color escapes
+/// part of a word's length. It only splits words on spaces, not on other sorts
+/// of whitespace.
+String wordWrap(String text) {
+  return text.split("\n").map((originalLine) {
+    var buffer = new StringBuffer();
+    var lengthSoFar = 0;
+    for (var word in originalLine.split(" ")) {
+      var wordLength = withoutColors(word).length;
+      if (wordLength > lineLength) {
+        if (lengthSoFar != 0) buffer.writeln();
+        buffer.writeln(word);
+      } else if (lengthSoFar == 0) {
+        buffer.write(word);
+        lengthSoFar = wordLength;
+      } else if (lengthSoFar + 1 + wordLength > lineLength) {
+        buffer.writeln();
+        buffer.write(word);
+        lengthSoFar = wordLength;
+      } else {
+        buffer.write(" $word");
+        lengthSoFar += 1 + wordLength;
+      }
+    }
+    return buffer.toString();
+  }).join("\n");
+}
+
 /// Print a warning containing [message].
 ///
 /// This automatically wraps lines if they get too long. If [color] is passed,
diff --git a/test/lib/src/util/placeholder.dart b/test/lib/src/util/placeholder.dart
new file mode 100644
index 0000000..862964f
--- /dev/null
+++ b/test/lib/src/util/placeholder.dart
@@ -0,0 +1,16 @@
+// 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.
+
+/// A class that's used as a default argument to detect whether an argument was
+/// passed.
+///
+/// We use a custom class for this rather than just `const Object()` so that
+/// callers can't accidentally pass the placeholder value.
+class _Placeholder {
+  const _Placeholder();
+}
+
+/// A placeholder to use as a default argument value to detect whether an
+/// argument was passed.
+const placeholder = const _Placeholder();
diff --git a/test/lib/src/utils.dart b/test/lib/src/utils.dart
index 2e06ef1..60d55e5 100644
--- a/test/lib/src/utils.dart
+++ b/test/lib/src/utils.dart
@@ -17,9 +17,6 @@
 import 'backend/invoker.dart';
 import 'backend/operating_system.dart';
 
-/// The maximum console line length.
-const _lineLength = 100;
-
 /// A typedef for a possibly-asynchronous function.
 ///
 /// The return type should only ever by [Future] or void.
@@ -36,8 +33,10 @@
         .listen(null, cancelOnError: cancelOnError));
 
 /// A [StreamChannelTransformer] that converts a chunked string channel to a
-/// line-by-line channel. Note that this is only safe for channels whose
-/// messages are guaranteed not to contain newlines.
+/// line-by-line channel.
+///
+/// Note that this is only safe for channels whose messages are guaranteed not
+/// to contain newlines.
 final chunksToLines = new StreamChannelTransformer(
     const LineSplitter(),
     new StreamSinkTransformer.fromHandlers(
@@ -140,37 +139,6 @@
 /// whether its first letter is a vowel.
 String a(String noun) => noun.startsWith(_vowel) ? "an $noun" : "a $noun";
 
-/// Wraps [text] so that it fits within [lineLength], which defaults to 100
-/// characters.
-///
-/// This preserves existing newlines and doesn't consider terminal color escapes
-/// part of a word's length.
-String wordWrap(String text, {int lineLength}) {
-  if (lineLength == null) lineLength = _lineLength;
-  return text.split("\n").map((originalLine) {
-    var buffer = new StringBuffer();
-    var lengthSoFar = 0;
-    for (var word in originalLine.split(" ")) {
-      var wordLength = withoutColors(word).length;
-      if (wordLength > lineLength) {
-        if (lengthSoFar != 0) buffer.writeln();
-        buffer.writeln(word);
-      } else if (lengthSoFar == 0) {
-        buffer.write(word);
-        lengthSoFar = wordLength;
-      } else if (lengthSoFar + 1 + wordLength > lineLength) {
-        buffer.writeln();
-        buffer.write(word);
-        lengthSoFar = wordLength;
-      } else {
-        buffer.write(" $word");
-        lengthSoFar += 1 + wordLength;
-      }
-    }
-    return buffer.toString();
-  }).join("\n");
-}
-
 /// A regular expression matching terminal color codes.
 final _colorCode = new RegExp('\u001b\\[[0-9;]+m');
 
diff --git a/test/lib/test.dart b/test/lib/test.dart
index 2550bef..39e4cbc 100644
--- a/test/lib/test.dart
+++ b/test/lib/test.dart
@@ -23,6 +23,7 @@
 export 'src/frontend/expect_async.dart';
 export 'src/frontend/future_matchers.dart';
 export 'src/frontend/on_platform.dart';
+export 'src/frontend/never_called.dart';
 export 'src/frontend/prints_matcher.dart';
 export 'src/frontend/skip.dart';
 export 'src/frontend/spawn_hybrid.dart';
@@ -33,6 +34,7 @@
 export 'src/frontend/throws_matcher.dart';
 export 'src/frontend/throws_matchers.dart';
 export 'src/frontend/timeout.dart';
+export 'src/frontend/utils.dart';
 
 /// The global declarer.
 ///
@@ -67,7 +69,8 @@
     ExpandedReporter.watch(engine,
         color: true, printPath: false, printPlatform: false);
 
-    var success = await engine.run();
+    var success = await runZoned(() => Invoker.guard(engine.run),
+        zoneValues: {#test.declarer: _globalDeclarer});
     // TODO(nweiz): Set the exit code on the VM when issue 6943 is fixed.
     if (success) return null;
     print('');
@@ -252,6 +255,9 @@
 ///
 /// The [callback] is run before any callbacks registered with [tearDown]. Like
 /// [tearDown], the most recently registered callback is run first.
+///
+/// If this is called from within a [setUpAll] or [tearDownAll] callback, it
+/// instead runs the function after *all* tests in the current test suite.
 void addTearDown(callback()) {
   if (Invoker.current == null) {
     throw new StateError("addTearDown() may only be called within a test.");
diff --git a/test/pubspec.yaml b/test/pubspec.yaml
index 2a8c344..80f14c1 100644
--- a/test/pubspec.yaml
+++ b/test/pubspec.yaml
@@ -1,5 +1,5 @@
 name: test
-version: 0.12.26
+version: 0.12.30+1
 author: Dart Team <misc@dartlang.org>
 description: A library for writing dart unit tests.
 homepage: https://github.com/dart-lang/test
@@ -16,7 +16,8 @@
   http_multi_server: '>=1.0.0 <3.0.0'
   io: '^0.3.0'
   js: '^0.6.0'
-  meta: '^1.0.0'
+  meta: '^1.1.0'
+  multi_server_socket: '^1.0.0'
   node_preamble: '^1.3.0'
   package_resolver: '^1.0.0'
   path: '^1.2.0'
@@ -29,10 +30,11 @@
   source_map_stack_trace: '^1.1.4'
   source_maps: '^0.10.2'
   source_span: '^1.4.0'
-  stack_trace: '^1.2.1'
+  stack_trace: '^1.9.0'
   stream_channel: '^1.6.0'
   string_scanner: '>=0.1.1 <2.0.0'
   term_glyph: '^1.0.0'
+  typed_data: '^1.0.0'
   web_socket_channel: '^1.0.0'
   yaml: '^2.0.0'