Update dart packagae

Fixed build

Change-Id: I9c9e25409b2be8c3f191c038eb37e9d1476394a9
diff --git a/pub/archive/BUILD.gn b/pub/archive/BUILD.gn
index 8b72178..2da32bf 100644
--- a/pub/archive/BUILD.gn
+++ b/pub/archive/BUILD.gn
@@ -1,4 +1,4 @@
-# This file is generated by importer.py for archive-1.0.27
+# This file is generated by importer.py for archive-1.0.28
 
 import("//build/dart/dart_package.gni")
 
diff --git a/pub/archive/README.md b/pub/archive/README.md
index d2cc090..4f10c0b 100755
--- a/pub/archive/README.md
+++ b/pub/archive/README.md
@@ -1,4 +1,5 @@
 # archive

+[![Build Status](https://travis-ci.org/brendan-duncan/archive.svg?branch=master)](https://travis-ci.org/brendan-duncan/archive)

 

 ## Overview

 

diff --git a/pub/archive/lib/src/gzip_encoder.dart b/pub/archive/lib/src/gzip_encoder.dart
index a88936b..f769c6d 100755
--- a/pub/archive/lib/src/gzip_encoder.dart
+++ b/pub/archive/lib/src/gzip_encoder.dart
@@ -24,7 +24,7 @@
   static const int OS_NTFS = 11;

   static const int OS_QDOS = 12;

   static const int OS_ACORN_RISCOS = 13;

-  static const int OS_UNKNOWN = 25;

+  static const int OS_UNKNOWN = 255;

 

   List<int> encode(List<int> data, {int level}) {

     OutputStream output = new OutputStream();

diff --git a/pub/archive/lib/src/util/mem_ptr.dart b/pub/archive/lib/src/util/mem_ptr.dart
index b5d4038..f14fea1 100755
--- a/pub/archive/lib/src/util/mem_ptr.dart
+++ b/pub/archive/lib/src/util/mem_ptr.dart
@@ -46,7 +46,7 @@
   operator[]=(int index, int value) => buffer[offset + index] = value;

 

   /**

-   * The number of bytes remianing in the buffer.

+   * The number of bytes remaining in the buffer.

    */

   int get length => _length - offset;

 

@@ -67,7 +67,7 @@
 

   /**

    * Set a range of bytes in this buffer to [value], at [start] offset from the

-   * current read poisiton, and [length] number of bytes.

+   * current read position, and [length] number of bytes.

    */

   void memset(int start, int length, int value) {

     buffer.fillRange(offset + start, offset + start + length, value);

diff --git a/pub/archive/lib/src/util/output_stream.dart b/pub/archive/lib/src/util/output_stream.dart
index e9fccea..37aada6 100755
--- a/pub/archive/lib/src/util/output_stream.dart
+++ b/pub/archive/lib/src/util/output_stream.dart
@@ -133,7 +133,8 @@
         blockSize = required;

       }

     }

-    Uint8List newBuffer = new Uint8List(_buffer.length + blockSize);

+    int newLength = (_buffer.length + blockSize) * 2;

+    Uint8List newBuffer = new Uint8List(newLength);

     newBuffer.setRange(0, _buffer.length, _buffer);

     _buffer = newBuffer;

   }

diff --git a/pub/archive/lib/src/zlib/deflate.dart b/pub/archive/lib/src/zlib/deflate.dart
index a20b547..7e2025b 100755
--- a/pub/archive/lib/src/zlib/deflate.dart
+++ b/pub/archive/lib/src/zlib/deflate.dart
@@ -37,6 +37,17 @@
   }

 

   /**

+   * Get the resulting compressed bytes without storing the resulting data to

+   * minimize memory usage.

+   */

+  List<int> takeBytes() {

+    _flushPending();

+    List<int> bytes = _output.getBytes();

+    _output.clear();

+    return bytes;

+  }

+

+  /**

    * Add more data to be deflated.

    */

   void addBytes(List<int> bytes, {int flush: FINISH}) {

diff --git a/pub/archive/pubspec.yaml b/pub/archive/pubspec.yaml
index 78f2be7..040247e 100755
--- a/pub/archive/pubspec.yaml
+++ b/pub/archive/pubspec.yaml
@@ -1,5 +1,5 @@
 name: archive

-version: 1.0.27

+version: 1.0.28

 author: Brendan Duncan <brendanduncan@gmail.com>

 description: Provides encoders and decoders for various archive and compression formats such as zip, tar, bzip2, gzip, and zlib.

 homepage: https://github.com/brendan-duncan/archive

diff --git a/pub/async/BUILD.gn b/pub/async/BUILD.gn
index e1ec0a4..df52430 100644
--- a/pub/async/BUILD.gn
+++ b/pub/async/BUILD.gn
@@ -1,4 +1,4 @@
-# This file is generated by importer.py for async-1.12.0
+# This file is generated by importer.py for async-1.13.0
 
 import("//build/dart/dart_package.gni")
 
diff --git a/pub/async/CHANGELOG.md b/pub/async/CHANGELOG.md
index c49a4bd..5685503 100644
--- a/pub/async/CHANGELOG.md
+++ b/pub/async/CHANGELOG.md
@@ -1,8 +1,22 @@
+## 1.13.0
+
+* Add `collectBytes` and `collectBytesCancelable` functions which collects
+  list-of-byte events into a single byte list.
+
+* Fix a bug where rejecting a `StreamQueueTransaction` would throw a
+  `StateError` if `StreamQueue.rest` had been called on one of its child queues.
+
+* `StreamQueue.withTransaction()` now properly returns whether or not the
+  transaction was committed.
+
 ## 1.12.0
 
 * Add an `AsyncCache` class that caches asynchronous operations for a period of
   time.
 
+* Add `StreamQueue.peek` and `StreamQueue.lookAheead`.
+  These allow users to look at events without consuming them.
+
 * Add `StreamQueue.startTransaction()` and `StreamQueue.withTransaction()`.
   These allow users to conditionally consume events based on their values.
 
diff --git a/pub/async/lib/async.dart b/pub/async/lib/async.dart
index c11f0b5..e090032 100644
--- a/pub/async/lib/async.dart
+++ b/pub/async/lib/async.dart
@@ -4,6 +4,7 @@
 
 export "src/async_cache.dart";
 export "src/async_memoizer.dart";
+export "src/byte_collector.dart";
 export "src/cancelable_operation.dart";
 export "src/delegate/event_sink.dart";
 export "src/delegate/future.dart";
diff --git a/pub/async/lib/src/byte_collector.dart b/pub/async/lib/src/byte_collector.dart
new file mode 100644
index 0000000..a8d2dbf
--- /dev/null
+++ b/pub/async/lib/src/byte_collector.dart
@@ -0,0 +1,72 @@
+// 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:typed_data";
+import "cancelable_operation.dart";
+
+/// Collects an asynchronous sequence of byte lists into a single list of bytes.
+///
+/// If the [source] stream emits an error event,
+/// the collection fails and the returned future completes with the same error.
+///
+/// If any of the input data are not valid bytes, they will be truncated to
+/// an eight-bit unsigned value in the resulting list.
+Future<Uint8List> collectBytes(Stream<List<int>> source) {
+  return _collectBytes(source, (_, result) => result);
+}
+
+/// Collects an asynchronous sequence of byte lists into a single list of bytes.
+///
+/// Returns a [CancelableOperation] that provides the result future and a way
+/// to cancel the collection early.
+///
+/// If the [source] stream emits an error event,
+/// the collection fails and the returned future completes with the same error.
+///
+/// If any of the input data are not valid bytes, they will be truncated to
+/// an eight-bit unsigned value in the resulting list.
+CancelableOperation<Uint8List> collectBytesCancelable(
+    Stream<List<int>> source) {
+  return _collectBytes(source, (subscription, result) =>
+      new CancelableOperation.fromFuture(result, onCancel: subscription.cancel)
+  );
+}
+
+/// Generalization over [collectBytes] and [collectBytesCancelable].
+///
+/// Performs all the same operations, but the final result is created
+/// by the [result] function, which has access to the stream subscription
+/// so it can cancel the operation.
+T _collectBytes<T>(
+    Stream<List<int>> source,
+    T result(StreamSubscription<List<int>> subscription,
+        Future<Uint8List> result)) {
+  var byteLists = <List<int>>[];
+  var length = 0;
+  var completer = new Completer<Uint8List>.sync();
+  var subscription = source.listen(
+      (bytes) {
+        byteLists.add(bytes);
+        length += bytes.length;
+      },
+      onError: completer.completeError,
+      onDone: () {
+        completer.complete(_collect(length, byteLists));
+      },
+      cancelOnError: true);
+  return result(subscription, completer.future);
+}
+
+// Join a lists of bytes with a known total length into a single [Uint8List].
+Uint8List _collect(int length, List<List<int>> byteLists) {
+  var result = new Uint8List(length);
+  int i = 0;
+  for (var byteList in byteLists) {
+    var end = i + byteList.length;
+    result.setRange(i, end, byteList);
+    i = end;
+  }
+  return result;
+}
diff --git a/pub/async/lib/src/stream_queue.dart b/pub/async/lib/src/stream_queue.dart
index 7b73eac..99e7436 100644
--- a/pub/async/lib/src/stream_queue.dart
+++ b/pub/async/lib/src/stream_queue.dart
@@ -131,6 +131,22 @@
     throw _failClosed();
   }
 
+
+  /// Look at the next [count] data events without consuming them.
+  ///
+  /// Works like [take] except that the events are left in the queue.
+  /// If one of the next [count] events is an error, the returned future
+  /// completes with this error, and the error is still left in the queue.
+  Future<List<T>> lookAhead(int count) {
+    if (count < 0) throw new RangeError.range(count, 0, null, "count");
+    if (!_isClosed) {
+      var request = new _LookAheadRequest<T>(count);
+      _addRequest(request);
+      return request.future;
+    }
+    throw _failClosed();
+  }
+
   /// Requests the next (yet unrequested) event from the stream.
   ///
   /// When the requested event arrives, the returned future is completed with
@@ -154,6 +170,19 @@
     throw _failClosed();
   }
 
+  /// Looks at the next (yet unrequested) event from the stream.
+  ///
+  /// Like [next] except that the event is not consumed.
+  /// If the next event is an error event, it stays in the queue.
+  Future<T> get peek {
+    if (!_isClosed) {
+      var nextRequest = new _PeekRequest<T>();
+      _addRequest(nextRequest);
+      return nextRequest.future;
+    }
+    throw _failClosed();
+  }
+
   /// Returns a stream of all the remaning events of the source stream.
   ///
   /// All requested [next], [skip] or [take] operations are completed
@@ -299,6 +328,7 @@
       } else {
         transaction.reject();
       }
+      return result;
     }, onError: (error) {
       transaction.commit(queue);
       throw error;
@@ -353,8 +383,8 @@
   /// `cancel`.
   ///
   /// After calling `cancel`, no further events can be requested.
-  /// None of [next], [rest], [skip], [take] or [cancel] may be
-  /// called again.
+  /// None of [lookAhead], [next], [peek], [rest], [skip], [take] or [cancel]
+  /// may be called again.
   Future cancel({bool immediate: false}) {
     if (_isClosed) throw _failClosed();
     _isClosed = true;
@@ -519,6 +549,7 @@
     if (_isDone) {
       return new Stream<T>.empty();
     }
+    _isDone = true;
 
     if (_subscription == null) {
       return _sourceStream;
@@ -526,7 +557,6 @@
 
     var subscription = _subscription;
     _subscription = null;
-    _isDone = true;
 
     var wasPaused = subscription.isPaused;
     var result = new SubscriptionStream<T>(subscription);
@@ -692,15 +722,42 @@
       return true;
     }
     if (isDone) {
-      var errorFuture =
-          new Future.sync(() => throw new StateError("No elements"));
-      _completer.complete(errorFuture);
+      _completer.completeError(new StateError("No elements"),
+                               StackTrace.current);
       return true;
     }
     return false;
   }
 }
 
+
+/// Request for a [StreamQueue.peek] call.
+///
+/// Completes the returned future when receiving the first event,
+/// and is then complete, but doesn't consume the event.
+class _PeekRequest<T> implements _EventRequest<T> {
+  /// Completer for the future returned by [StreamQueue.next].
+  final _completer = new Completer<T>();
+
+  _PeekRequest();
+
+  Future<T> get future => _completer.future;
+
+  bool update(QueueList<Result<T>> events, bool isDone) {
+    if (events.isNotEmpty) {
+      events.first.complete(_completer);
+      return true;
+    }
+    if (isDone) {
+      _completer.completeError(new StateError("No elements"),
+                               StackTrace.current);
+      return true;
+    }
+    return false;
+  }
+}
+
+
 /// Request for a [StreamQueue.skip] call.
 class _SkipRequest<T> implements _EventRequest<T> {
   /// Completer for the future returned by the skip call.
@@ -738,8 +795,8 @@
   }
 }
 
-/// Request for a [StreamQueue.take] call.
-class _TakeRequest<T> implements _EventRequest<T> {
+/// Common superclass for [_TakeRequest] and [_LookAheadRequest].
+abstract class _ListRequest<T> implements _EventRequest<T> {
   /// Completer for the future returned by the take call.
   final _completer = new Completer<List<T>>();
 
@@ -752,10 +809,16 @@
   /// this value.
   final int _eventsToTake;
 
-  _TakeRequest(this._eventsToTake);
+  _ListRequest(this._eventsToTake);
 
   /// The future completed when the correct number of events have been captured.
   Future<List<T>> get future => _completer.future;
+}
+
+
+/// Request for a [StreamQueue.take] call.
+class _TakeRequest<T> extends _ListRequest<T> {
+  _TakeRequest(int eventsToTake) : super(eventsToTake);
 
   bool update(QueueList<Result<T>> events, bool isDone) {
     while (_list.length < _eventsToTake) {
@@ -766,7 +829,7 @@
 
       var event = events.removeFirst();
       if (event.isError) {
-        _completer.completeError(event.asError.error, event.asError.stackTrace);
+        event.asError.complete(_completer);
         return true;
       }
       _list.add(event.asValue.value);
@@ -776,6 +839,30 @@
   }
 }
 
+
+/// Request for a [StreamQueue.lookAhead] call.
+class _LookAheadRequest<T> extends _ListRequest<T> {
+  _LookAheadRequest(int eventsToTake) : super(eventsToTake);
+
+  bool update(QueueList<Result<T>> events, bool isDone) {
+    while (_list.length < _eventsToTake) {
+      if (events.length == _list.length) {
+        if (isDone) break;
+        return false;
+      }
+      var event = events.elementAt(_list.length);
+      if (event.isError) {
+        event.asError.complete(_completer);
+        return true;
+      }
+      _list.add(event.asValue.value);
+    }
+    _completer.complete(_list);
+    return true;
+  }
+}
+
+
 /// Request for a [StreamQueue.cancel] call.
 ///
 /// The request needs no events, it just waits in the request queue
@@ -874,7 +961,7 @@
 /// Request for a [StreamQueue.startTransaction] call.
 ///
 /// This request isn't complete until the user calls
-/// [StreamQueueTransaction.commit] or [StreamQueue.rejectTransaction], at which
+/// [StreamQueueTransaction.commit] or [StreamQueueTransaction.reject], at which
 /// point it manually removes itself from the request queue and calls
 /// [StreamQueue._updateRequests].
 class _TransactionRequest<T> implements _EventRequest<T> {
diff --git a/pub/async/pubspec.yaml b/pub/async/pubspec.yaml
index ec62ff2..6fce524 100644
--- a/pub/async/pubspec.yaml
+++ b/pub/async/pubspec.yaml
@@ -1,5 +1,5 @@
 name: async
-version: 1.12.0
+version: 1.13.0
 author: Dart Team <misc@dartlang.org>
 description: Utility functions and classes related to the 'dart:async' library.
 homepage: https://www.github.com/dart-lang/async
@@ -10,4 +10,4 @@
   stack_trace: "^1.0.0"
   test: "^0.12.0"
 environment:
-  sdk: ">=1.19.0 <2.0.0"
+  sdk: ">=1.21.0 <2.0.0"
diff --git a/pub/dart_style/.status b/pub/dart_style/.status
deleted file mode 100644
index 5333c45..0000000
--- a/pub/dart_style/.status
+++ /dev/null
@@ -1,19 +0,0 @@
-# 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.
-
-# Don't run any test-like files that show up in packages directories. It
-# shouldn't be necessary to run "pub install" in these packages, but if you do
-# it shouldn't break the tests.
-packages/*/*: Skip
-*/packages/*/*: Skip
-*/*/packages/*/*: Skip
-*/*/*/packages/*/*: Skip
-*/*/*/*/packages/*/*: Skip
-*/*/*/*/*/packages/*/*: Skip
-
-# No need to run any of the built output.
-build/test/*: Skip
-
-[ $browser ]
-test/*: Skip # Tests only run on the VM since they use dart:io.
diff --git a/pub/dart_style/.test_config b/pub/dart_style/.test_config
new file mode 100644
index 0000000..531426a
--- /dev/null
+++ b/pub/dart_style/.test_config
@@ -0,0 +1,5 @@
+{
+  "test_package": {
+    "platforms": ["vm"]
+  }
+}
\ No newline at end of file
diff --git a/pub/dart_style/BUILD.gn b/pub/dart_style/BUILD.gn
index 0841c51..d04ab7a 100644
--- a/pub/dart_style/BUILD.gn
+++ b/pub/dart_style/BUILD.gn
@@ -1,4 +1,4 @@
-# This file is generated by importer.py for dart_style-0.2.15
+# This file is generated by importer.py for dart_style-0.2.16
 
 import("//build/dart/dart_package.gni")
 
diff --git a/pub/dart_style/CHANGELOG.md b/pub/dart_style/CHANGELOG.md
index 8795385..ec5fdd7 100644
--- a/pub/dart_style/CHANGELOG.md
+++ b/pub/dart_style/CHANGELOG.md
@@ -1,3 +1,7 @@
+# 0.2.16
+
+* Don't discard type arguments on method calls with closure arguments (#582).
+
 # 0.2.15
 
 * Support `covariant` modifier on methods.
diff --git a/pub/dart_style/bin/format.dart b/pub/dart_style/bin/format.dart
index b43bf5d..e1eabbc 100644
--- a/pub/dart_style/bin/format.dart
+++ b/pub/dart_style/bin/format.dart
@@ -14,7 +14,7 @@
 import 'package:dart_style/src/source_code.dart';
 
 // Note: The following line of code is modified by tool/grind.dart.
-const version = "0.2.15";
+const version = "0.2.16";
 
 void main(List<String> args) {
   var parser = new ArgParser(allowTrailingOptions: true);
diff --git a/pub/dart_style/lib/src/call_chain_visitor.dart b/pub/dart_style/lib/src/call_chain_visitor.dart
index e1fec05..9c40dca 100644
--- a/pub/dart_style/lib/src/call_chain_visitor.dart
+++ b/pub/dart_style/lib/src/call_chain_visitor.dart
@@ -410,6 +410,7 @@
   void _writeBlockCall(MethodInvocation invocation) {
     _visitor.token(invocation.operator);
     _visitor.token(invocation.methodName.token);
+    _visitor.visit(invocation.typeArguments);
     _visitor.visit(invocation.argumentList);
   }
 
diff --git a/pub/dart_style/pubspec.yaml b/pub/dart_style/pubspec.yaml
index ad7f415..20c7310 100644
--- a/pub/dart_style/pubspec.yaml
+++ b/pub/dart_style/pubspec.yaml
@@ -1,6 +1,6 @@
 name: dart_style
 # Note: See tool/grind.dart for how to bump the version.
-version: 0.2.15
+version: 0.2.16
 author: Dart Team <misc@dartlang.org>
 description: Opinionated, automatic Dart source code formatter.
 homepage: https://github.com/dart-lang/dart_style
diff --git a/pub/front_end/.analysis_options b/pub/front_end/.analysis_options
index a10d4c5..f0ac32f 100644
--- a/pub/front_end/.analysis_options
+++ b/pub/front_end/.analysis_options
@@ -1,2 +1,4 @@
 analyzer:
   strong-mode: true
+  language:
+    enableSuperMixins: true
diff --git a/pub/front_end/.history/pubspec_20170131134120.yaml b/pub/front_end/.history/pubspec_20170131134120.yaml
new file mode 100644
index 0000000..5f15860
--- /dev/null
+++ b/pub/front_end/.history/pubspec_20170131134120.yaml
@@ -0,0 +1,18 @@
+name: front_end
+version: 0.1.0-alpha.1
+author: Dart Team <misc@dartlang.org>
+description: Front end for compilation of Dart code.
+homepage: https://github.com/dart-lang/sdk/tree/master/pkg/front_end
+environment:
+  sdk: '>=1.12.0 <2.0.0'
+dependencies:
+  analyzer: 0.30.0-alpha.1
+  path: '^1.3.9'
+  source_span: '^1.2.3'
+dev_dependencies:
+  # TODO(sigmund): update to a version constraint once we roll the latest kernel
+  # to the repo.
+  kernel: {path: ../../pkg/kernel}
+  package_config: '^1.0.0'
+  test: ^0.12.0
+  test_reflective_loader: ^0.1.0
diff --git a/pub/front_end/.vscode/settings.json b/pub/front_end/.vscode/settings.json
new file mode 100644
index 0000000..14a8645
--- /dev/null
+++ b/pub/front_end/.vscode/settings.json
@@ -0,0 +1,3 @@
+{
+  "files.exclude": {}
+}
\ No newline at end of file
diff --git a/pub/front_end/BUILD.gn b/pub/front_end/BUILD.gn
index c610197..1f24e3a 100644
--- a/pub/front_end/BUILD.gn
+++ b/pub/front_end/BUILD.gn
@@ -1,4 +1,4 @@
-# This file is generated by importer.py for front_end-0.1.0-alpha.0
+# This file is generated by importer.py for front_end-0.1.0-alpha.1
 
 import("//build/dart/dart_package.gni")
 
diff --git a/pub/front_end/lib/compilation_error.dart b/pub/front_end/lib/compilation_error.dart
index a238575..5e30da1 100644
--- a/pub/front_end/lib/compilation_error.dart
+++ b/pub/front_end/lib/compilation_error.dart
@@ -18,8 +18,8 @@
   /// A text description of how the user can fix the error.  May be `null`.
   String get correction;
 
-  /// The source location where the error occurred.
-  SourceSpan get location;
+  /// The source span where the error occurred.
+  SourceSpan get span;
 
   /// A text description of the compile error.
   String get message;
diff --git a/pub/front_end/lib/compiler_options.dart b/pub/front_end/lib/compiler_options.dart
index f9f2f29..5c0cb11 100644
--- a/pub/front_end/lib/compiler_options.dart
+++ b/pub/front_end/lib/compiler_options.dart
@@ -6,6 +6,10 @@
 
 import 'compilation_error.dart';
 import 'file_system.dart';
+import 'physical_file_system.dart';
+
+/// Default error handler used by [CompielerOptions.onError].
+void defaultErrorHandler(CompilationError error) => throw error;
 
 /// Callback used to report errors encountered during compilation.
 typedef void ErrorHandler(CompilationError error);
@@ -14,76 +18,72 @@
 ///
 /// Not intended to be implemented or extended by clients.
 class CompilerOptions {
-  /// The path to the Dart SDK.
+  /// The URI of the root of the Dart SDK (typically a "file:" URI).
   ///
   /// If `null`, the SDK will be searched for using
   /// [Platform.resolvedExecutable] as a starting point.
   ///
   /// This option is mutually exclusive with [sdkSummary].
-  String sdkPath;
+  Uri sdkRoot;
 
   /// Callback to which compilation errors should be delivered.
   ///
-  /// If `null`, the first error will be reported by throwing an exception of
+  /// By default, the first error will be reported by throwing an exception of
   /// type [CompilationError].
-  ErrorHandler onError;
+  ErrorHandler onError = defaultErrorHandler;
 
-  /// Path to the ".packages" file.
+  /// URI of the ".packages" file (typically a "file:" URI).
   ///
   /// If `null`, the ".packages" file will be found via the standard
   /// package_config search algorithm.
-  String packagesFilePath;
+  ///
+  /// If the URI's path component is empty (e.g. `new Uri()`), no packages file
+  /// will be used.
+  Uri packagesFileUri;
 
-  /// Paths to the input summary files (excluding the SDK summary).  These files
-  /// should all be linked summaries.  They should also be closed, in the sense
-  /// that any libraries they reference should also appear in [inputSummaries]
-  /// or [sdkSummary].
-  List<String> inputSummaries = [];
+  /// URIs of input summary files (excluding the SDK summary; typically these
+  /// will be "file:" URIs).  These files should all be linked summaries.  They
+  /// should also be closed, in the sense that any libraries they reference
+  /// should also appear in [inputSummaries] or [sdkSummary].
+  List<Uri> inputSummaries = [];
 
-  /// Path to the SDK summary file.
+  /// URI of the SDK summary file (typically a "file:" URI).
   ///
   /// This should be a linked summary.  If `null`, the SDK summary will be
-  /// searched for at a default location within [sdkPath].
+  /// searched for at a default location within [sdkRoot].
   ///
-  /// This option is mutually exclusive with [sdkPath].  TODO(paulberry): if the
+  /// This option is mutually exclusive with [sdkRoot].  TODO(paulberry): if the
   /// VM does not contain a pickled copy of the SDK, we might need to change
   /// this.
-  String sdkSummary;
+  Uri sdkSummary;
 
   /// URI override map.
   ///
-  /// This is a map from Uri to file path.  Any URI override listed in this map
-  /// takes precedence over the URI resolution that would be implied by the
-  /// packages file (see [packagesFilePath]) and/or [bazelRoots].
+  /// This is a map from URIs that might appear in import/export/part statements
+  /// to URIs that should be used to locate the corresponding files in the
+  /// [fileSystem].  Any URI override listed in this map takes precedence over
+  /// the URI resolution that would be implied by the packages file (see
+  /// [packagesFileUri]) and/or [multiRoots].
   ///
   /// If a URI is not listed in this map, then the normal URI resolution
   /// algorithm will be used.
   ///
   /// TODO(paulberry): transition analyzer and dev_compiler to use the
-  /// "file:///bazel-root" mechanism, and then remove this.
+  /// "multi-root:" mechanism, and then remove this.
   @deprecated
-  Map<Uri, String> uriOverride = {};
+  Map<Uri, Uri> uriOverride = {};
 
-  /// Bazel roots.
+  /// Multi-roots.
   ///
-  /// Any Uri that resolves to "file:///bazel-root/$rest" will be searched for
-  /// at "$root/$rest" ("$root\\$rest" in Windows), where "$root" is drawn from
-  /// this list.  If the file is not found at any of those locations, the URI
-  /// "file:///bazel-root/$rest" will be used directly.
+  /// Any Uri that resolves to "multi-root:///$rest" will be searched for
+  /// at "$root/$rest", where "$root" is drawn from this list.
   ///
-  /// Intended use: if the Bazel workspace is located at path "$workspace", this
-  /// could be set to `['$workspace', '$workspace/bazel-bin',
-  /// '$workspace/bazel-genfiles']`, effectively overlaying source and generated
-  /// files.
-  List<String> bazelRoots = [];
-
-  /// Sets the platform bit, which determines which patch files should be
-  /// applied to the SDK.
-  ///
-  /// The value should be a power of two, and should match the `PLATFORM` bit
-  /// flags in sdk/lib/_internal/sdk_library_metadata/lib/libraries.dart.  If
-  /// zero, no patch files will be applied.
-  int platformBit;
+  /// Intended use: if the user has a Bazel workspace located at path
+  /// "$workspace", this could be set to the file URIs corresponding to the
+  /// paths for "$workspace", "$workspace/bazel-bin",
+  /// and "$workspace/bazel-genfiles", effectively overlaying source and
+  /// generated files.
+  List<Uri> multiRoots = [];
 
   /// The declared variables for use by configurable imports and constant
   /// evaluation.
@@ -91,12 +91,40 @@
 
   /// The [FileSystem] which should be used by the front end to access files.
   ///
-  /// TODO(paulberry): once an implementation of [FileSystem] has been created
-  /// which uses the actual physical file system, make that the default.
-  ///
   /// All file system access performed by the front end goes through this
   /// mechanism, with one exception: if no value is specified for
-  /// [packagesFilePath], the packages file is located using the actual physical
+  /// [packagesFileUri], the packages file is located using the actual physical
   /// file system.  TODO(paulberry): fix this.
-  FileSystem fileSystem;
+  FileSystem fileSystem = PhysicalFileSystem.instance;
+
+  /// Whether to generate code for the SDK when compiling a whole-program.
+  bool compileSdk = false;
+
+  /// Whether a modular build compiles only the files listed explicitly or if it
+  /// compiles dependencies as well.
+  ///
+  /// This option is intended only for modular APIs like `kernelForBuildUnit`.
+  /// These APIs by default ensure that builds are hermetic, where all files
+  /// that will be compiled are listed explicitly and all other dependencies
+  /// are covered by summary files.
+  ///
+  /// When this option is true, these APIs will treat any dependency that is
+  /// not described in a summary as if it was explictly listed as an input.
+  bool chaseDependencies = false;
+
+  /// Whether to intepret Dart sources in strong-mode.
+  bool strongMode = true;
+
+  // All options below are target-specific options.
+  //
+  // TODO(sigmund): revisit the right layout for these options. We might want to
+  // split them out into a separate bag of options or provide factories for
+  // common combinations of these options.
+
+  /// Patch files to apply on the core libraries for a specific target platform.
+  ///
+  /// Keys on this map are expected to be `dart:*` URIs. The values can be
+  /// either absolute or relative URIs. Absolute URIs are read directly, while
+  /// relative URIs are resolved from the [sdkRoot].
+  Map<Uri, List<Uri>> targetPatches = {};
 }
diff --git a/pub/front_end/lib/dependency_grapher.dart b/pub/front_end/lib/dependency_grapher.dart
new file mode 100644
index 0000000..6120490
--- /dev/null
+++ b/pub/front_end/lib/dependency_grapher.dart
@@ -0,0 +1,54 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+
+import 'package:front_end/compiler_options.dart';
+import 'package:front_end/src/base/processed_options.dart';
+import 'package:front_end/src/dependency_grapher_impl.dart' as impl;
+
+/// Generates a representation of the dependency graph of a program.
+///
+/// Given the Uri of one or more files, this function follows `import`,
+/// `export`, and `part` declarations to discover a graph of all files involved
+/// in the program.
+Future<Graph> graphForProgram(List<Uri> sources, CompilerOptions options) {
+  var processedOptions = new ProcessedOptions(options);
+  return impl.graphForProgram(sources, processedOptions);
+}
+
+/// A representation of the dependency graph of a program.
+///
+/// Not intended to be extended, implemented, or mixed in by clients.
+class Graph {
+  /// A list of all library cycles in the program, in topologically sorted order
+  /// (each cycle only depends on libraries in the cycles that precede it).
+  final topologicallySortedCycles = <LibraryCycleNode>[];
+}
+
+/// A representation of a single library cycle in the dependency graph of a
+/// program.
+///
+/// Not intended to be extended, implemented, or mixed in by clients.
+class LibraryCycleNode {
+  /// A map of all the libraries in the cycle, keyed by the URI of their
+  /// defining compilation unit.
+  final libraries = <Uri, LibraryNode>{};
+}
+
+/// A representation of a single library in the dependency graph of a program.
+///
+/// Not intended to be extended, implemented, or mixed in by clients.
+class LibraryNode {
+  /// The URI of this library's defining compilation unit.
+  final Uri uri;
+
+  /// A list of the URIs of all of this library's "part" files.
+  final parts = <Uri>[];
+
+  /// A list of all the other libraries this library directly depends on.
+  final dependencies = <LibraryNode>[];
+
+  LibraryNode(this.uri);
+}
diff --git a/pub/front_end/lib/file_system.dart b/pub/front_end/lib/file_system.dart
index cadf82f..6e57c26 100644
--- a/pub/front_end/lib/file_system.dart
+++ b/pub/front_end/lib/file_system.dart
@@ -18,22 +18,17 @@
 /// Not intended to be implemented or extended by clients.
 abstract class FileSystem {
   /// Returns a path context suitable for use with this [FileSystem].
+  ///
+  /// TODO(paulberry): try to eliminate all usages of this.  Since the
+  /// FileSystem API now uses URIs rather than paths, it should not be needed.
   path.Context get context;
 
-  /// Returns a [FileSystemEntity] corresponding to the given [path].
-  ///
-  /// Uses of `..` and `.` in path are normalized before returning (so, for
-  /// example, `entityForPath('./foo')` and `entityForPath('foo')` are
-  /// equivalent).  Relative paths are also converted to absolute paths.
-  ///
-  /// Does not check whether a file or folder exists at the given location.
-  FileSystemEntity entityForPath(String path);
-
   /// Returns a [FileSystemEntity] corresponding to the given [uri].
   ///
   /// Uses of `..` and `.` in the URI are normalized before returning.
   ///
-  /// If [uri] is not an absolute `file:` URI, an [Error] will be thrown.
+  /// If the URI scheme is not supported by this file system, an [Error] will be
+  /// thrown.
   ///
   /// Does not check whether a file or folder exists at the given location.
   FileSystemEntity entityForUri(Uri uri);
@@ -46,14 +41,12 @@
 ///
 /// Not intended to be implemented or extended by clients.
 abstract class FileSystemEntity {
-  /// Returns the absolute normalized path represented by this file system
+  /// Returns the absolute normalized URI represented by this file system
   /// entity.
   ///
-  /// Note: if the [FileSystemEntity] was created using
-  /// [FileSystem.entityForPath], this is not necessarily the same as the path
-  /// that was used to create the object, since the path might have been
-  /// normalized.
-  String get path;
+  /// Note: this is not necessarily the same as the URI that was passed to
+  /// [FileSystem.entityForUri], since the URI might have been normalized.
+  Uri get uri;
 
   /// Attempts to access this file system entity as a file and read its contents
   /// as raw bytes.
diff --git a/pub/front_end/lib/incremental_kernel_generator.dart b/pub/front_end/lib/incremental_kernel_generator.dart
new file mode 100644
index 0000000..3b3b429
--- /dev/null
+++ b/pub/front_end/lib/incremental_kernel_generator.dart
@@ -0,0 +1,102 @@
+// 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:front_end/src/base/processed_options.dart';
+import 'package:front_end/src/incremental_kernel_generator_impl.dart';
+import 'package:kernel/kernel.dart';
+
+import 'compiler_options.dart';
+
+/// Represents the difference between "old" and "new" states of a program.
+///
+/// Not intended to be implemented or extended by clients.
+class DeltaProgram {
+  /// The new state of the program.
+  ///
+  /// Libraries whose kernel representation is known to be unchanged since the
+  /// last [DeltaProgram] are not included.
+  final Map<Uri, Program> newState;
+
+  DeltaProgram(this.newState);
+
+  /// TODO(paulberry): add information about libraries that were removed.
+}
+
+/// Interface for generating an initial kernel representation of a program and
+/// keeping it up to date as incremental changes are made.
+///
+/// This class maintains an internal "previous program state"; each
+/// time [computeDelta] is called, it updates the previous program state and
+/// produces a representation of what has changed.  When there are few changes,
+/// a call to [computeDelta] should be much faster than compiling the whole
+/// program from scratch.
+///
+/// This class also maintains a set of "valid sources", which is a (possibly
+/// empty) subset of the sources constituting the previous program state.  Files
+/// in this set are assumed to be unchanged since the last call to
+/// [computeDelta].
+///
+/// Behavior is undefined if the client does not obey the following concurrency
+/// restrictions:
+/// - no two invocations of [computeDelta] may be outstanding at any given time.
+/// - neither [invalidate] nor [invalidateAll] may be called while an invocation
+///   of [computeDelta] is outstanding.
+///
+/// Not intended to be implemented or extended by clients.
+abstract class IncrementalKernelGenerator {
+  /// Creates an [IncrementalKernelGenerator] which is prepared to generate
+  /// kernel representations of the program whose main library is in the given
+  /// [source].
+  ///
+  /// No file system access is performed by this constructor; the initial
+  /// "previous program state" is an empty program containing no code, and the
+  /// initial set of valid sources is empty.  To obtain a kernel representation
+  /// of the program, call [computeDelta].
+  factory IncrementalKernelGenerator(Uri source, CompilerOptions options) =>
+      new IncrementalKernelGeneratorImpl(source, new ProcessedOptions(options));
+
+  /// Generates a kernel representation of the changes to the program, assuming
+  /// that all valid sources are unchanged since the last call to
+  /// [computeDelta].
+  ///
+  /// Source files in the set of valid sources are guaranteed not to be re-read
+  /// from disk; they are assumed to be unchanged regardless of the state of the
+  /// filesystem.
+  ///
+  /// If [watch] is not `null`, then when a source file is first used
+  /// by [computeDelta], [watch] is called with the Uri of that source
+  /// file and `used` == `true` indicating that the source file is being
+  /// used when compiling the program. The content of the file is not read
+  /// until the Future returned by [watch] completes. If during a subsequent
+  /// call to [computeDelta], a source file that was being used is no longer
+  /// used, then [watch] is called with the Uri of that source file and
+  /// `used` == `false` indicating that the source file is no longer needed.
+  /// Multiple invocations of [watch] may be running concurrently.
+  ///
+  /// If the future completes successfully, the previous file state is updated
+  /// and the set of valid sources is set to the set of all sources in the
+  /// program.
+  ///
+  /// If the future completes with an error (due to errors in the compiled
+  /// source code), the caller may consider the previous file state and the set
+  /// of valid sources to be unchanged; this means that once the user fixes the
+  /// errors, it is safe to call [computeDelta] again.
+  Future<DeltaProgram> computeDelta({Future<Null> watch(Uri uri, bool used)});
+
+  /// Remove any source file(s) associated with the given file path from the set
+  /// of valid sources.  This guarantees that those files will be re-read on the
+  /// next call to [computeDelta]).
+  void invalidate(String path);
+
+  /// Remove all source files from the set of valid sources.  This guarantees
+  /// that all files will be re-read on the next call to [computeDelta].
+  ///
+  /// Note that this does not erase the previous program state; the next time
+  /// [computeDelta] is called, if parts of the program are discovered to be
+  /// unchanged, parts of the previous program state will still be re-used to
+  /// speed up compilation.
+  void invalidateAll();
+}
diff --git a/pub/front_end/lib/incremental_resolved_ast_generator.dart b/pub/front_end/lib/incremental_resolved_ast_generator.dart
new file mode 100644
index 0000000..daeb8c1
--- /dev/null
+++ b/pub/front_end/lib/incremental_resolved_ast_generator.dart
@@ -0,0 +1,98 @@
+// 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:analyzer/dart/ast/ast.dart';
+import 'package:front_end/src/base/processed_options.dart';
+import 'package:front_end/src/incremental_resolved_ast_generator_impl.dart';
+
+import 'compiler_options.dart';
+
+/// Represents the difference between "old" and "new" states of a program.
+///
+/// Not intended to be implemented or extended by clients.
+class DeltaLibraries {
+  /// The new state of the program, as a two-layer map.
+  ///
+  /// The outer map key is the library URI.  The inner map key is the
+  /// compilation unit (part) URI.  The map values are the resolved compilation
+  /// units.
+  ///
+  /// Libraries whose resolved AST is known to be unchanged since the last
+  /// [DeltaLibraries] are not included.
+  final Map<Uri, Map<Uri, CompilationUnit>> newState;
+
+  DeltaLibraries(this.newState);
+
+  /// TODO(paulberry): add information about libraries that were removed.
+}
+
+/// Interface for generating an initial resolved representation of a program and
+/// keeping it up to date as incremental changes are made.
+///
+/// This class maintains an internal "previous program state"; each
+/// time [computeDelta] is called, it updates the previous program state and
+/// produces a representation of what has changed.  When there are few changes,
+/// a call to [computeDelta] should be much faster than compiling the whole
+/// program from scratch.
+///
+/// This class also maintains a set of "valid sources", which is a (possibly
+/// empty) subset of the sources constituting the previous program state.  Files
+/// in this set are assumed to be unchanged since the last call to
+/// [computeDelta].
+///
+/// Behavior is undefined if the client does not obey the following concurrency
+/// restrictions:
+/// - no two invocations of [computeDelta] may be outstanding at any given time.
+/// - neither [invalidate] nor [invalidateAll] may be called while an invocation
+///   of [computeDelta] is outstanding.
+///
+/// Not intended to be implemented or extended by clients.
+abstract class IncrementalResolvedAstGenerator {
+  /// Creates an [IncrementalResolvedAstGenerator] which is prepared to generate
+  /// resolved ASTs for the program whose main library is in the given
+  /// [source].
+  ///
+  /// No file system access is performed by this constructor; the initial
+  /// "previous program state" is an empty program containing no code, and the
+  /// initial set of valid sources is empty.  To obtain a resolved AST
+  /// representation of the program, call [computeDelta].
+  factory IncrementalResolvedAstGenerator(
+          Uri source, CompilerOptions options) =>
+      new IncrementalResolvedAstGeneratorImpl(
+          source, new ProcessedOptions(options));
+
+  /// Generates a resolved AST representation of the changes to the program,
+  /// assuming that all valid sources are unchanged since the last call to
+  /// [computeDelta].
+  ///
+  /// Source files in the set of valid sources are guaranteed not to be re-read
+  /// from disk; they are assumed to be unchanged regardless of the state of the
+  /// filesystem.
+  ///
+  /// If the future completes successfully, the previous file state is updated
+  /// and the set of valid sources is set to the set of all sources in the
+  /// program.
+  ///
+  /// If the future completes with an error (due to errors in the compiled
+  /// source code), the caller may consider the previous file state and the set
+  /// of valid sources to be unchanged; this means that once the user fixes the
+  /// errors, it is safe to call [computeDelta] again.
+  Future<DeltaLibraries> computeDelta();
+
+  /// Remove any source file(s) associated with the given file path from the set
+  /// of valid sources.  This guarantees that those files will be re-read on the
+  /// next call to [computeDelta]).
+  void invalidate(String path);
+
+  /// Remove all source files from the set of valid sources.  This guarantees
+  /// that all files will be re-read on the next call to [computeDelta].
+  ///
+  /// Note that this does not erase the previous program state; the next time
+  /// [computeDelta] is called, if parts of the program are discovered to be
+  /// unchanged, parts of the previous program state will still be re-used to
+  /// speed up compilation.
+  void invalidateAll();
+}
diff --git a/pub/front_end/lib/kernel_generator.dart b/pub/front_end/lib/kernel_generator.dart
index 3b35086..0ae2fb3 100644
--- a/pub/front_end/lib/kernel_generator.dart
+++ b/pub/front_end/lib/kernel_generator.dart
@@ -5,9 +5,18 @@
 /// Defines the front-end API for converting source code to Dart Kernel objects.
 library front_end.kernel_generator;
 
-import 'dart:async';
+import 'compilation_error.dart';
 import 'compiler_options.dart';
-import 'package:kernel/kernel.dart' as kernel;
+import 'dart:async';
+
+import 'package:analyzer/src/generated/source.dart' show SourceKind;
+import 'package:analyzer/src/generated/engine.dart' show AnalysisOptionsImpl;
+import 'package:analyzer/src/summary/package_bundle_reader.dart'
+    show InSummarySource;
+// TODO(sigmund): move loader logic under front_end/lib/src/kernel/
+import 'package:kernel/analyzer/loader.dart';
+import 'package:kernel/kernel.dart';
+import 'package:source_span/source_span.dart' show SourceSpan;
 
 /// Generates a kernel representation of the program whose main library is in
 /// the given [source].
@@ -18,41 +27,172 @@
 /// follows `import`, `export`, and `part` declarations to discover the whole
 /// program, and converts the result to Dart Kernel format.
 ///
-/// If summaries are provided in [options], they may be used to speed up
-/// analysis, but they will not take the place of Dart source code (since the
-/// Dart source code is still needed to access the contents of method bodies).
+/// If `compileSdk` in [options] is true, the generated program will include
+/// code for the SDK.
 ///
-/// TODO(paulberry): will the VM have a pickled version of the SDK inside it? If
-/// so, then maybe this method should not convert SDK libraries to kernel.
-Future<kernel.Program> kernelForProgram(Uri source, CompilerOptions options) =>
-    throw new UnimplementedError();
+/// If summaries are provided in [options], they may be used to speed up
+/// analysis. If in addition `compileSdk` is false, this will speed up
+/// compilation, as no source of the sdk will be generated.  Note however, that
+/// summaries for application code can also speed up analysis, but they will not
+/// take the place of Dart source code (since the Dart source code is still
+/// needed to access the contents of method bodies).
+Future<Program> kernelForProgram(Uri source, CompilerOptions options) async {
+  var loader = await _createLoader(options, entry: source);
+  // TODO(sigmund): delete this. At this time we have no need to explicitly list
+  // VM libraries, since they are normally found by chasing dependencies.
+  // `dart:_builtin` is an exception because it is used by the kernel
+  // transformers to inform the VM about where the main entrypoint is. This is
+  // expected to change, and we should be able to remove these lines at that
+  // point. We check for the presense of `dart:developer` in the targetPatches
+  // to ensure we only load this library while running on the VM.
+  if (options.compileSdk &&
+      options.targetPatches.containsKey(Uri.parse('dart:developer'))) {
+    loader.loadLibrary(Uri.parse('dart:_builtin'));
+  }
+  // TODO(sigmund): merge what we have in loadEverything and the logic below in
+  // kernelForBuildUnit so there is a single place where we crawl for
+  // dependencies.
+  Program program = loader.loadProgram(source, compileSdk: options.compileSdk);
+  _reportErrors(loader.errors, options.onError);
+  return program;
+}
 
-/// Generates a kernel representation of the build unit whose source files are
-/// in [sources].
+/// Generates a kernel representation for a build unit.
 ///
 /// Intended for modular compilation.
 ///
-/// [sources] should be the complete set of source files for a build unit
-/// (including both library and part files).  All of the library files are
-/// transformed into Dart Kernel Library objects.
+/// The build unit by default contains only the source files in [sources]
+/// (including library and part files), but if
+/// [CompilerOptions.chaseDependencies] is true, it may include some additional
+/// source files.  All of the library files are transformed into Dart Kernel
+/// Library objects.
 ///
-/// The compilation process is hermetic, meaning that the only files which will
-/// be read are those listed in [sources], [CompilerOptions.inputSummaries], and
-/// [CompilerOptions.sdkSummary].  If a source file attempts to refer to a file
-/// which is not obtainable from these paths, that will result in an error, even
-/// if the file exists on the filesystem.
+/// By default, the compilation process is hermetic, meaning that the only files
+/// which will be read are those listed in [sources],
+/// [CompilerOptions.inputSummaries], and [CompilerOptions.sdkSummary].  If a
+/// source file attempts to refer to a file which is not obtainable from these
+/// URIs, that will result in an error, even if the file exists on the
+/// filesystem.
+///
+/// When [CompilerOptions.chaseDependencies] is true, this default behavior
+/// changes, and any dependency of [sources] that is not listed in
+/// [CompilerOptions.inputSummaries] and [CompilerOptions.sdkSummary] is treated
+/// as an additional source file for the build unit.
 ///
 /// Any `part` declarations found in [sources] must refer to part files which
-/// are also listed in [sources], otherwise an error results.  (It is not
-/// permitted to refer to a part file declared in another build unit).
+/// are also listed in the build unit sources, otherwise an error results.  (It
+/// is not permitted to refer to a part file declared in another build unit).
 ///
-/// The return value is a [kernel.Program] object with no main method set.
+/// The return value is a [Program] object with no main method set.
 /// TODO(paulberry): would it be better to define a data type in kernel to
 /// represent a bundle of all the libraries in a given build unit?
 ///
 /// TODO(paulberry): does additional information need to be output to allow the
 /// caller to match up referenced elements to the summary files they were
 /// obtained from?
-Future<kernel.Program> kernelForBuildUnit(
-        List<Uri> sources, CompilerOptions options) =>
-    throw new UnimplementedError();
+Future<Program> kernelForBuildUnit(
+    List<Uri> sources, CompilerOptions options) async {
+  var repository = new Repository();
+  var loader = await _createLoader(options, repository: repository);
+  var context = loader.context;
+
+  // Process every library in the build unit.
+  for (var uri in sources) {
+    var source = context.sourceFactory.forUri2(uri);
+    //  We ignore part files, those are handled by their enclosing library.
+    if (context.computeKindOf(source) == SourceKind.PART) {
+      // TODO(sigmund): record it and ensure that this part is within a provided
+      // library.
+      continue;
+    }
+    loader.loadLibrary(uri);
+  }
+
+  // Check whether all dependencies were included in [sources].
+  // TODO(sigmund): we should look for dependencies using import, export, and
+  // part directives intead of relying on the dartk-loader.  In particular, if a
+  // library is imported but not used, the logic below will not detect it.
+  for (int i = 0; i < repository.libraries.length; ++i) {
+    // Note: we don't use a for-in loop because repository.libraries grows as
+    // the loader processes libraries.
+    var lib = repository.libraries[i];
+    var source = context.sourceFactory.forUri2(lib.importUri);
+    if (source is InSummarySource) continue;
+    if (options.chaseDependencies) {
+      loader.ensureLibraryIsLoaded(lib);
+    } else if (lib.isExternal) {
+      // Default behavior: the build should be hermetic and all dependencies
+      // should be listed.
+      options.onError(new _DartkError('hermetic build error: '
+          'no source or summary was given for ${lib.importUri}'));
+    }
+  }
+
+  Program program = new Program(repository.libraries);
+  _reportErrors(loader.errors, options.onError);
+  return program;
+}
+
+/// Create a [DartLoader] using the provided [options].
+///
+/// If [options] contain no configuration to resolve `.packages`, the [entry]
+/// file will be used to search for a `.packages` file.
+Future<DartLoader> _createLoader(CompilerOptions options,
+    {Repository repository, Uri entry}) async {
+  var kernelOptions = _convertOptions(options);
+  var packages = await createPackages(
+      _uriToPath(options.packagesFileUri, options),
+      discoveryPath: entry?.path);
+  var loader = new DartLoader(
+      repository ?? new Repository(), kernelOptions, packages);
+  var patchPaths = <String, List<String>>{};
+
+  // TODO(sigmund,paulberry): use ProcessedOptions so that we can resolve the
+  // URIs correctly even if sdkRoot is inferred and not specified explicitly.
+  String resolve(Uri patch) =>
+    options.fileSystem.context.fromUri(options.sdkRoot.resolveUri(patch));
+
+  options.targetPatches.forEach((uri, patches) {
+    patchPaths['$uri'] = patches.map(resolve).toList();
+  });
+  AnalysisOptionsImpl analysisOptions = loader.context.analysisOptions;
+  analysisOptions.patchPaths = patchPaths;
+  return loader;
+}
+
+DartOptions _convertOptions(CompilerOptions options) {
+  return new DartOptions(
+      strongMode: options.strongMode,
+      sdk: _uriToPath(options.sdkRoot, options),
+      // TODO(sigmund): make it possible to use summaries and still compile the
+      // sdk sources.
+      sdkSummary:
+          options.compileSdk ? null : _uriToPath(options.sdkSummary, options),
+      packagePath: _uriToPath(options.packagesFileUri, options),
+      customUriMappings: options.uriOverride,
+      declaredVariables: options.declaredVariables);
+}
+
+void _reportErrors(List errors, ErrorHandler onError) {
+  if (onError == null) return;
+  for (var error in errors) {
+    onError(new _DartkError(error));
+  }
+}
+
+String _uriToPath(Uri uri, CompilerOptions options) {
+  if (uri == null) return null;
+  if (uri.scheme != 'file') {
+    throw new StateError('Only file URIs are supported');
+  }
+  return options.fileSystem.context.fromUri(uri);
+}
+
+// TODO(sigmund): delete this class. Dartk should not format errors itself, we
+// should just pass them along.
+class _DartkError implements CompilationError {
+  String get correction => null;
+  SourceSpan get span => null;
+  final String message;
+  _DartkError(this.message);
+}
diff --git a/pub/front_end/lib/memory_file_system.dart b/pub/front_end/lib/memory_file_system.dart
index 267cbe3..e7382ad 100644
--- a/pub/front_end/lib/memory_file_system.dart
+++ b/pub/front_end/lib/memory_file_system.dart
@@ -20,26 +20,29 @@
   @override
   final p.Context context;
 
-  final Map<String, Uint8List> _files = {};
+  final Map<Uri, Uint8List> _files = {};
 
   /// The "current directory" in the in-memory virtual file system.
   ///
-  /// This is used to convert relative paths to absolute paths.
-  String currentDirectory;
+  /// This is used to convert relative URIs to absolute URIs.
+  ///
+  /// Always ends in a trailing '/'.
+  Uri currentDirectory;
 
-  MemoryFileSystem(this.context, this.currentDirectory);
-
-  @override
-  MemoryFileSystemEntity entityForPath(String path) =>
-      new MemoryFileSystemEntity._(
-          this, context.normalize(context.join(currentDirectory, path)));
+  MemoryFileSystem(this.context, Uri currentDirectory)
+      : currentDirectory = _addTrailingSlash(currentDirectory);
 
   @override
   MemoryFileSystemEntity entityForUri(Uri uri) {
-    if (uri.scheme != 'file') throw new ArgumentError('File URI expected');
-    // Note: we don't have to verify that the URI's path is absolute, because
-    // URIs with non-empty schemes always have absolute paths.
-    return entityForPath(context.fromUri(uri));
+    return new MemoryFileSystemEntity._(
+        this, currentDirectory.resolveUri(uri).normalizePath());
+  }
+
+  static Uri _addTrailingSlash(Uri uri) {
+    if (!uri.path.endsWith('/')) {
+      uri = uri.replace(path: uri.path + '/');
+    }
+    return uri;
   }
 }
 
@@ -49,22 +52,22 @@
   final MemoryFileSystem _fileSystem;
 
   @override
-  final String path;
+  final Uri uri;
 
-  MemoryFileSystemEntity._(this._fileSystem, this.path);
+  MemoryFileSystemEntity._(this._fileSystem, this.uri);
 
   @override
-  int get hashCode => path.hashCode;
+  int get hashCode => uri.hashCode;
 
   @override
   bool operator ==(Object other) =>
       other is MemoryFileSystemEntity &&
-      other.path == path &&
+      other.uri == uri &&
       identical(other._fileSystem, _fileSystem);
 
   @override
   Future<List<int>> readAsBytes() async {
-    List<int> contents = _fileSystem._files[path];
+    List<int> contents = _fileSystem._files[uri];
     if (contents != null) {
       return contents.toList();
     }
@@ -82,7 +85,7 @@
   /// If no file exists, one is created.  If a file exists already, it is
   /// overwritten.
   void writeAsBytesSync(List<int> bytes) {
-    _fileSystem._files[path] = new Uint8List.fromList(bytes);
+    _fileSystem._files[uri] = new Uint8List.fromList(bytes);
   }
 
   /// Writes the given string to this file system entity.
@@ -95,6 +98,6 @@
     // Note: the return type of UTF8.encode is List<int>, but in practice it
     // always returns Uint8List.  We rely on that for efficiency, so that we
     // don't have to make an extra copy.
-    _fileSystem._files[path] = UTF8.encode(s) as Uint8List;
+    _fileSystem._files[uri] = UTF8.encode(s) as Uint8List;
   }
 }
diff --git a/pub/front_end/lib/physical_file_system.dart b/pub/front_end/lib/physical_file_system.dart
index 0ed5d8b..f90abc9 100644
--- a/pub/front_end/lib/physical_file_system.dart
+++ b/pub/front_end/lib/physical_file_system.dart
@@ -24,15 +24,11 @@
   p.Context get context => p.context;
 
   @override
-  FileSystemEntity entityForPath(String path) =>
-      new _PhysicalFileSystemEntity(context.normalize(context.absolute(path)));
-
-  @override
   FileSystemEntity entityForUri(Uri uri) {
-    if (uri.scheme != 'file') throw new ArgumentError('File URI expected');
-    // Note: we don't have to verify that the URI's path is absolute, because
-    // URIs with non-empty schemes always have absolute paths.
-    return entityForPath(context.fromUri(uri));
+    if (uri.scheme != 'file' && uri.scheme != '') {
+      throw new ArgumentError('File URI expected');
+    }
+    return new _PhysicalFileSystemEntity(Uri.base.resolveUri(uri));
   }
 }
 
@@ -40,20 +36,20 @@
 /// [PhysicalFileSystem].
 class _PhysicalFileSystemEntity implements FileSystemEntity {
   @override
-  final String path;
+  final Uri uri;
 
-  _PhysicalFileSystemEntity(this.path);
+  _PhysicalFileSystemEntity(this.uri);
 
   @override
-  int get hashCode => path.hashCode;
+  int get hashCode => uri.hashCode;
 
   @override
   bool operator ==(Object other) =>
-      other is _PhysicalFileSystemEntity && other.path == path;
+      other is _PhysicalFileSystemEntity && other.uri == uri;
 
   @override
-  Future<List<int>> readAsBytes() => new io.File(path).readAsBytes();
+  Future<List<int>> readAsBytes() => new io.File.fromUri(uri).readAsBytes();
 
   @override
-  Future<String> readAsString() => new io.File(path).readAsString();
+  Future<String> readAsString() => new io.File.fromUri(uri).readAsString();
 }
diff --git a/pub/front_end/lib/src/async_dependency_walker.dart b/pub/front_end/lib/src/async_dependency_walker.dart
new file mode 100644
index 0000000..b0c6535
--- /dev/null
+++ b/pub/front_end/lib/src/async_dependency_walker.dart
@@ -0,0 +1,172 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+
+/**
+ * An instance of [AsyncDependencyWalker] contains the core algorithms for
+ * walking a dependency graph and evaluating nodes in a safe order.
+ *
+ * Computation of dependencies and evaluation of nodes may be asynchronous.
+ */
+abstract class AsyncDependencyWalker<NodeType extends Node<NodeType>> {
+  /**
+   * Called by [walk] to evaluate a single non-cyclical node, after
+   * all that node's dependencies have been evaluated.
+   */
+  Future<Null> evaluate(NodeType v);
+
+  /**
+   * Called by [walk] to evaluate a strongly connected component
+   * containing one or more nodes.  All dependencies of the strongly
+   * connected component have been evaluated.
+   */
+  Future<Null> evaluateScc(List<NodeType> scc);
+
+  /**
+   * Walk the dependency graph starting at [startingPoint], finding
+   * strongly connected components and evaluating them in a safe order
+   * by calling [evaluate] and [evaluateScc].
+   *
+   * This is an implementation of Tarjan's strongly connected
+   * components algorithm
+   * (https://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm).
+   *
+   * TODO(paulberry): Consider switching to an algorithm that allows
+   * dependencies to be computed in parallel, and nodes to be evaluated in
+   * parallel.
+   */
+  Future<Null> walk(NodeType startingPoint) async {
+    // TODO(paulberry): consider rewriting in a non-recursive way so
+    // that long dependency chains don't cause stack overflow.
+
+    // TODO(paulberry): in the event that an exception occurs during
+    // the walk, restore the state of the [Node] data structures so
+    // that further evaluation will be safe.
+
+    // The index which will be assigned to the next node that is
+    // freshly visited.
+    int index = 1;
+
+    // Stack of nodes which have been seen so far and whose strongly
+    // connected component is still being determined.  Nodes are only
+    // popped off the stack when they are evaluated, so sometimes the
+    // stack contains nodes that were visited after the current node.
+    List<NodeType> stack = <NodeType>[];
+
+    Future strongConnect(NodeType node) async {
+      bool hasTrivialCycle = false;
+
+      // Assign the current node an index and add it to the stack.  We
+      // haven't seen any of its dependencies yet, so set its lowLink
+      // to its index, indicating that so far it is the only node in
+      // its strongly connected component.
+      node._index = node._lowLink = index++;
+      stack.add(node);
+
+      // Consider the node's dependencies one at a time.
+      var dependencies =
+          node._dependencies ??= await node.computeDependencies();
+      for (NodeType dependency in dependencies) {
+        // If the dependency has already been evaluated, it can't be
+        // part of this node's strongly connected component, so we can
+        // skip it.
+        if (dependency._isEvaluated) {
+          continue;
+        }
+        if (identical(node, dependency)) {
+          // If a node includes itself as a dependency, there is no need to
+          // explore the dependency further.
+          hasTrivialCycle = true;
+        } else if (dependency._index == 0) {
+          // The dependency hasn't been seen yet, so recurse on it.
+          await strongConnect(dependency);
+          // If the dependency's lowLink refers to a node that was
+          // visited before the current node, that means that the
+          // current node, the dependency, and the node referred to by
+          // the dependency's lowLink are all part of the same
+          // strongly connected component, so we need to update the
+          // current node's lowLink accordingly.
+          if (dependency._lowLink < node._lowLink) {
+            node._lowLink = dependency._lowLink;
+          }
+        } else {
+          // The dependency has already been seen, so it is part of
+          // the current node's strongly connected component.  If it
+          // was visited earlier than the current node's lowLink, then
+          // it is a new addition to the current node's strongly
+          // connected component, so we need to update the current
+          // node's lowLink accordingly.
+          if (dependency._index < node._lowLink) {
+            node._lowLink = dependency._index;
+          }
+        }
+      }
+
+      // If the current node's lowLink is the same as its index, then
+      // we have finished visiting a strongly connected component, so
+      // pop the stack and evaluate it before moving on.
+      if (node._lowLink == node._index) {
+        // The strongly connected component has only one node.  If there is a
+        // cycle, it's a trivial one.
+        if (identical(stack.last, node)) {
+          stack.removeLast();
+          node._isEvaluated = true;
+          if (hasTrivialCycle) {
+            await evaluateScc(<NodeType>[node]);
+          } else {
+            await evaluate(node);
+          }
+        } else {
+          // There are multiple nodes in the strongly connected
+          // component.
+          List<NodeType> scc = <NodeType>[];
+          while (true) {
+            NodeType otherNode = stack.removeLast();
+            scc.add(otherNode);
+            otherNode._isEvaluated = true;
+            if (identical(otherNode, node)) {
+              break;
+            }
+          }
+          await evaluateScc(scc);
+        }
+      }
+    }
+
+    // Kick off the algorithm starting with the starting point.
+    await strongConnect(startingPoint);
+  }
+}
+
+/**
+ * Instances of [Node] represent nodes in a dependency graph.  The
+ * type parameter, [NodeType], is the derived type (this affords some
+ * extra type safety by making it difficult to accidentally construct
+ * bridges between unrelated dependency graphs).
+ */
+abstract class Node<NodeType> {
+  /**
+   * Index used by Tarjan's strongly connected components algorithm.
+   * Zero means the node has not been visited yet; a nonzero value
+   * counts the order in which the node was visited.
+   */
+  int _index = 0;
+
+  /**
+   * Low link used by Tarjan's strongly connected components
+   * algorithm.  This represents the smallest [_index] of all the nodes
+   * in the strongly connected component to which this node belongs.
+   */
+  int _lowLink = 0;
+
+  List<NodeType> _dependencies;
+
+  bool _isEvaluated = false;
+
+  /**
+   * Compute the dependencies of this node.
+   */
+  Future<List<NodeType>> computeDependencies();
+}
diff --git a/pub/front_end/lib/src/base/analysis_target.dart b/pub/front_end/lib/src/base/analysis_target.dart
new file mode 100644
index 0000000..ab50efd
--- /dev/null
+++ b/pub/front_end/lib/src/base/analysis_target.dart
@@ -0,0 +1,26 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:front_end/src/base/source.dart';
+
+/**
+ * An object with which an analysis result can be associated.
+ *
+ * Clients may implement this class when creating new kinds of targets.
+ * Instances of this type are used in hashed data structures, so subtypes are
+ * required to correctly implement [==] and [hashCode].
+ */
+abstract class AnalysisTarget {
+  /**
+   * If this target is associated with a library, return the source of the
+   * library's defining compilation unit; otherwise return `null`.
+   */
+  Source get librarySource;
+
+  /**
+   * Return the source associated with this target, or `null` if this target is
+   * not associated with a source.
+   */
+  Source get source;
+}
diff --git a/pub/front_end/lib/src/base/errors.dart b/pub/front_end/lib/src/base/errors.dart
new file mode 100644
index 0000000..d39953f
--- /dev/null
+++ b/pub/front_end/lib/src/base/errors.dart
@@ -0,0 +1,282 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/**
+ * An error code associated with an [AnalysisError].
+ *
+ * Generally, we want to provide messages that consist of three sentences. From
+ * the user's perspective these sentences should explain:
+ *
+ * 1. what is wrong,
+ * 2. why is it wrong, and
+ * 3. how do I fix it.
+ *
+ * However, we combine the first two in the [message] and the last in the
+ * [correction].
+ *
+ * When composing messages (including correction messages) keep the following
+ * guidelines in mind.
+ *
+ * 1. The message should be a complete sentence starting with an uppercase
+ * letter, and ending with a period.
+ *
+ * 2. Reserved words and embedded identifiers should be in single quotes, so
+ * prefer double quotes for the complete message. For example,
+ * ```
+ * "The class '{0}' can't use 'super'."
+ * ```
+ * Notice that the word 'class' in the preceding message is not quoted as it
+ * refers to the concept 'class', not the reserved word. On the other hand,
+ * 'super' refers to the reserved word. Do not quote 'null' and numeric literals.
+ *
+ * 3. Do not try to compose messages, as it can make translating them hard.
+ *
+ * 4. Try to keep the error messages short, but informative.
+ *
+ * 5. Use simple words and terminology, assume the reader of the message doesn't
+ * have an advanced degree in math, and that English is not the reader's native
+ * language. Do not assume any formal computer science training. For example, do
+ * not use Latin abbreviations (prefer "that is" over "i.e.", and "for example"
+ * over "e.g."). Also avoid phrases such as "if and only if" and "iff"; that
+ * level of precision is unnecessary.
+ *
+ * 6. Prefer contractions when they are in common use, for example, prefer
+ * "can't" over "cannot". Using "cannot", "must not", "shall not", etc. is
+ * off-putting to people new to programming.
+ *
+ * 7. Use common terminology, preferably from the Dart Language Specification.
+ * This increases the user's chance of finding a good explanation on the web.
+ *
+ * 8. Do not try to be cute or funny. It is extremely frustrating to work on a
+ * product that crashes with a "tongue-in-cheek" message, especially if you did
+ * not want to use this product to begin with.
+ *
+ * 9. Do not lie, that is, do not write error messages containing phrases like
+ * "can't happen".  If the user ever saw this message, it would be a lie. Prefer
+ * messages like: "Internal error: This function should not be called when 'x'
+ * is null.".
+ *
+ * 10. Prefer to not use the imperative tone. That is, the message should not
+ * sound accusing or like it is ordering the user around. The computer should
+ * describe the problem, not criticize the user for violating the specification.
+ */
+abstract class ErrorCode {
+  /**
+   * The name of the error code.
+   */
+  final String name;
+
+  /**
+   * The template used to create the message to be displayed for this error. The
+   * message should indicate what is wrong and why it is wrong.
+   */
+  final String message;
+
+  /**
+   * The template used to create the correction to be displayed for this error,
+   * or `null` if there is no correction information for this error. The
+   * correction should indicate how the user can fix the error.
+   */
+  final String correction;
+
+  /**
+   * Initialize a newly created error code to have the given [name]. The message
+   * associated with the error will be created from the given [message]
+   * template. The correction associated with the error will be created from the
+   * given [correction] template.
+   */
+  const ErrorCode(this.name, this.message, [this.correction]);
+
+  /**
+   * The severity of the error.
+   */
+  ErrorSeverity get errorSeverity;
+
+  /**
+   * The type of the error.
+   */
+  ErrorType get type;
+
+  /**
+   * The unique name of this error code.
+   */
+  String get uniqueName => "$runtimeType.$name";
+
+  @override
+  String toString() => uniqueName;
+}
+
+/**
+ * The severity of an [ErrorCode].
+ */
+class ErrorSeverity implements Comparable<ErrorSeverity> {
+  /**
+   * The severity representing a non-error. This is never used for any error
+   * code, but is useful for clients.
+   */
+  static const ErrorSeverity NONE = const ErrorSeverity('NONE', 0, " ", "none");
+
+  /**
+   * The severity representing an informational level analysis issue.
+   */
+  static const ErrorSeverity INFO = const ErrorSeverity('INFO', 1, "I", "info");
+
+  /**
+   * The severity representing a warning. Warnings can become errors if the `-Werror` command
+   * line flag is specified.
+   */
+  static const ErrorSeverity WARNING =
+      const ErrorSeverity('WARNING', 2, "W", "warning");
+
+  /**
+   * The severity representing an error.
+   */
+  static const ErrorSeverity ERROR =
+      const ErrorSeverity('ERROR', 3, "E", "error");
+
+  static const List<ErrorSeverity> values = const [NONE, INFO, WARNING, ERROR];
+
+  /**
+   * The name of this error code.
+   */
+  final String name;
+
+  /**
+   * The ordinal value of the error code.
+   */
+  final int ordinal;
+
+  /**
+   * The name of the severity used when producing machine output.
+   */
+  final String machineCode;
+
+  /**
+   * The name of the severity used when producing readable output.
+   */
+  final String displayName;
+
+  /**
+   * Initialize a newly created severity with the given names.
+   */
+  const ErrorSeverity(
+      this.name, this.ordinal, this.machineCode, this.displayName);
+
+  @override
+  int get hashCode => ordinal;
+
+  @override
+  int compareTo(ErrorSeverity other) => ordinal - other.ordinal;
+
+  /**
+   * Return the severity constant that represents the greatest severity.
+   */
+  ErrorSeverity max(ErrorSeverity severity) =>
+      this.ordinal >= severity.ordinal ? this : severity;
+
+  @override
+  String toString() => name;
+}
+
+/**
+ * The type of an [ErrorCode].
+ */
+class ErrorType implements Comparable<ErrorType> {
+  /**
+   * Task (todo) comments in user code.
+   */
+  static const ErrorType TODO = const ErrorType('TODO', 0, ErrorSeverity.INFO);
+
+  /**
+   * Extra analysis run over the code to follow best practices, which are not in
+   * the Dart Language Specification.
+   */
+  static const ErrorType HINT = const ErrorType('HINT', 1, ErrorSeverity.INFO);
+
+  /**
+   * Compile-time errors are errors that preclude execution. A compile time
+   * error must be reported by a Dart compiler before the erroneous code is
+   * executed.
+   */
+  static const ErrorType COMPILE_TIME_ERROR =
+      const ErrorType('COMPILE_TIME_ERROR', 2, ErrorSeverity.ERROR);
+
+  /**
+   * Checked mode compile-time errors are errors that preclude execution in
+   * checked mode.
+   */
+  static const ErrorType CHECKED_MODE_COMPILE_TIME_ERROR = const ErrorType(
+      'CHECKED_MODE_COMPILE_TIME_ERROR', 3, ErrorSeverity.ERROR);
+
+  /**
+   * Static warnings are those warnings reported by the static checker. They
+   * have no effect on execution. Static warnings must be provided by Dart
+   * compilers used during development.
+   */
+  static const ErrorType STATIC_WARNING =
+      const ErrorType('STATIC_WARNING', 4, ErrorSeverity.WARNING);
+
+  /**
+   * Many, but not all, static warnings relate to types, in which case they are
+   * known as static type warnings.
+   */
+  static const ErrorType STATIC_TYPE_WARNING =
+      const ErrorType('STATIC_TYPE_WARNING', 5, ErrorSeverity.WARNING);
+
+  /**
+   * Syntactic errors are errors produced as a result of input that does not
+   * conform to the grammar.
+   */
+  static const ErrorType SYNTACTIC_ERROR =
+      const ErrorType('SYNTACTIC_ERROR', 6, ErrorSeverity.ERROR);
+
+  /**
+   * Lint warnings describe style and best practice recommendations that can be
+   * used to formalize a project's style guidelines.
+   */
+  static const ErrorType LINT = const ErrorType('LINT', 7, ErrorSeverity.INFO);
+
+  static const List<ErrorType> values = const [
+    TODO,
+    HINT,
+    COMPILE_TIME_ERROR,
+    CHECKED_MODE_COMPILE_TIME_ERROR,
+    STATIC_WARNING,
+    STATIC_TYPE_WARNING,
+    SYNTACTIC_ERROR,
+    LINT
+  ];
+
+  /**
+   * The name of this error type.
+   */
+  final String name;
+
+  /**
+   * The ordinal value of the error type.
+   */
+  final int ordinal;
+
+  /**
+   * The severity of this type of error.
+   */
+  final ErrorSeverity severity;
+
+  /**
+   * Initialize a newly created error type to have the given [name] and
+   * [severity].
+   */
+  const ErrorType(this.name, this.ordinal, this.severity);
+
+  String get displayName => name.toLowerCase().replaceAll('_', ' ');
+
+  @override
+  int get hashCode => ordinal;
+
+  @override
+  int compareTo(ErrorType other) => ordinal - other.ordinal;
+
+  @override
+  String toString() => name;
+}
diff --git a/pub/front_end/lib/src/base/file_repository.dart b/pub/front_end/lib/src/base/file_repository.dart
new file mode 100644
index 0000000..d4d4f7c
--- /dev/null
+++ b/pub/front_end/lib/src/base/file_repository.dart
@@ -0,0 +1,100 @@
+// 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.
+
+/// Data structure storing an association between URI and file contents.
+///
+/// Each URI is also associated with a unique arbitrary path ending in ".dart".
+/// This allows interfacing with analyzer code that expects to manipulate paths
+/// rather than URIs.
+class FileRepository {
+  /// Regular expression matching the arbitrary file paths generated by
+  /// [_pathForIndex].
+  static final _pathRegexp = new RegExp(r'^/[0-9]+\.dart$');
+
+  /// The URIs currently stored in the repository.
+  final _uris = <Uri>[];
+
+  /// Map from a URI to its index in [_uris].
+  final _uriToIndexMap = <Uri, int>{};
+
+  /// The file contents associated with the URIs in [_uris].
+  final _contents = <String>[];
+
+  /// Clear any contents stored in the file repository.  The association between
+  /// URI and arbitrary path is preserved.
+  ///
+  /// Subsequent calls to [contentsForPath] will have undefined results until
+  /// new contents are stored using [store].
+  void clearContents() {
+    for (var i = 0; i < _contents.length; i++) {
+      _contents[i] = null;
+    }
+  }
+
+  /// Return the contents of the file whose arbitary path is [path].
+  ///
+  /// The path must have been returned by a previous call to [store] or
+  /// [pathForUri].
+  String contentsForPath(String path) {
+    var contents = _contents[_indexForPath(path)];
+    assert(contents != null);
+    return contents;
+  }
+
+  /// For testing purposes, return the contents of all files stored in the file
+  /// repository, as a map from path to contents string.
+  Map<String, String> getContentsForTesting() {
+    var result = <String, String>{};
+    for (var i = 0; i < _contents.length; i++) {
+      if (_contents[i] != null) result[_pathForIndex(i)] = _contents[i];
+    }
+    return result;
+  }
+
+  /// Return the arbitrary path associated with [uri].
+  ///
+  /// If [allocate] is `false` (the default), the uri must have previously been
+  /// allocated a corresponding path, e.g. via a call to [store].  If [allocate]
+  /// is `true`, then a new path will be allocated if necessary.
+  String pathForUri(Uri uri, {bool allocate: false}) {
+    return _pathForIndex(_indexForUri(uri, allocate));
+  }
+
+  /// Associate the given [uri] with file [contents].
+  ///
+  /// The arbitrary path associated with the file is returned.
+  String store(Uri uri, String contents) {
+    int index = _indexForUri(uri, true);
+    _contents[index] = contents;
+    return _pathForIndex(index);
+  }
+
+  /// Return the URI for the file whose arbitrary path is [path].
+  ///
+  /// The path must have been returned by a previous call to [store] or
+  /// [pathForUri].
+  Uri uriForPath(String path) => _uris[_indexForPath(path)];
+
+  /// Return the index into [_uris] and [_contents] matching the arbitrary path
+  /// [path].
+  int _indexForPath(String path) {
+    assert(_pathRegexp.hasMatch(path));
+    return int.parse(path.substring(1, path.length - 5));
+  }
+
+  int _indexForUri(Uri uri, bool allocate) {
+    int index = _uriToIndexMap[uri];
+    assert(allocate || index != null);
+    if (index == null) {
+      index = _uris.length;
+      _uris.add(uri);
+      _uriToIndexMap[uri] = index;
+      _contents.add(null);
+    }
+    return index;
+  }
+
+  /// Return the arbitrary path associated with the given index.
+  String _pathForIndex(int index) => '/$index.dart';
+}
diff --git a/pub/front_end/lib/src/base/jenkins_smi_hash.dart b/pub/front_end/lib/src/base/jenkins_smi_hash.dart
new file mode 100644
index 0000000..8901ba4
--- /dev/null
+++ b/pub/front_end/lib/src/base/jenkins_smi_hash.dart
@@ -0,0 +1,53 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// Jenkins hash function, optimized for small integers.
+///
+/// Static methods borrowed from sdk/lib/math/jenkins_smi_hash.dart.  Non-static
+/// methods are an enhancement for the "front_end" package.
+///
+/// Where performance is critical, use [hash2], [hash3], or [hash4], or the
+/// pattern `finish(combine(combine(...combine(0, a), b)..., z))`, where a..z
+/// are hash codes to be combined.
+///
+/// For ease of use, you may also use this pattern:
+/// `(new JenkinsSmiHash()..add(a)..add(b)....add(z)).hashCode`, where a..z are
+/// the sub-objects whose hashes should be combined.  This pattern performs the
+/// same operations as the performance critical variant, but allocates an extra
+/// object.
+class JenkinsSmiHash {
+  /// Accumulates the hash code [value] into the running hash [hash].
+  static int combine(int hash, int value) {
+    hash = 0x1fffffff & (hash + value);
+    hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10));
+    return hash ^ (hash >> 6);
+  }
+
+  /// Finalizes a running hash produced by [combine].
+  static int finish(int hash) {
+    hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3));
+    hash = hash ^ (hash >> 11);
+    return 0x1fffffff & (hash + ((0x00003fff & hash) << 15));
+  }
+
+  /// Combines together two hash codes.
+  static int hash2(a, b) => finish(combine(combine(0, a), b));
+
+  /// Combines together three hash codes.
+  static int hash3(a, b, c) => finish(combine(combine(combine(0, a), b), c));
+
+  /// Combines together four hash codes.
+  static int hash4(a, b, c, d) =>
+      finish(combine(combine(combine(combine(0, a), b), c), d));
+
+  int _hash = 0;
+
+  /// Accumulates the object [o] into the hash.
+  void add(Object o) {
+    _hash = combine(_hash, o.hashCode);
+  }
+
+  /// Finalizes the hash and return the resulting hashcode.
+  int get hashCode => finish(_hash);
+}
diff --git a/pub/front_end/lib/src/base/library_info.dart b/pub/front_end/lib/src/base/library_info.dart
new file mode 100644
index 0000000..a66b6d5
--- /dev/null
+++ b/pub/front_end/lib/src/base/library_info.dart
@@ -0,0 +1,159 @@
+// 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 bit flag used by [LibraryInfo] indicating that a library is used by
+/// dart2js.
+///
+/// This declaration duplicates the declaration in the SDK's "libraries.dart".
+const int DART2JS_PLATFORM = 1;
+
+/// A bit flag used by [LibraryInfo] indicating that a library is used by the
+/// VM.
+///
+/// This declaration duplicates the declaration in the SDK's "libraries.dart".
+const int VM_PLATFORM = 2;
+
+/// Parse a category string in the SDK's "libraries.dart".
+///
+/// This declaration duplicates the declaration in the SDK's "libraries.dart".
+Category parseCategory(String name) {
+  switch (name) {
+    case 'Client':
+      return Category.client;
+    case 'Server':
+      return Category.server;
+    case 'Embedded':
+      return Category.embedded;
+  }
+  return null;
+}
+
+/// The contexts that a library can be used from.
+///
+/// This declaration duplicates the declaration in the SDK's "libraries.dart".
+enum Category {
+  /// Indicates that a library can be used in a browser context.
+  client,
+
+  /// Indicates that a lbirary can be used in a command line context.
+  server,
+
+  /// Indicates that a library can be used from embedded devices.
+  embedded
+}
+
+/// Information about a "dart:" library gleaned from the SDK's "libraries.dart"
+/// file.
+///
+/// This declaration duplicates the declaration in "libraries.dart".
+class LibraryInfo {
+  /// Path to the library's *.dart file relative to the SDK's "lib" directory.
+  final String path;
+
+  /// The categories in which the library can be used, encoded as a
+  /// comma-separated String.
+  final String _categories;
+
+  /// Path to the dart2js library's *.dart file relative to the SDK's "lib"
+  /// directory, or null if dart2js uses the common library path defined above.
+  final String dart2jsPath;
+
+  /// Path to the dart2js library's patch file relative to the SDK's "lib"
+  /// directory, or null if no dart2js patch file associated with this library.
+  final String dart2jsPatchPath;
+
+  /// True if this library is documented and should be shown to the user.
+  final bool documented;
+
+  /// Bit flags indicating which platforms consume this library.  See
+  /// [DART2JS_LIBRARY] and [VM_LIBRARY].
+  final int platforms;
+
+  /// True if the library contains implementation details for another library.
+  /// The implication is that these libraries are less commonly used and that
+  /// tools like the analysis server should not show these libraries in a list
+  /// of all libraries unless the user specifically asks the tool to do so.
+  final bool implementation;
+
+  /// States the current maturity of this library.
+  final Maturity maturity;
+
+  const LibraryInfo(this.path,
+      {String categories: "",
+      this.dart2jsPath,
+      this.dart2jsPatchPath,
+      this.implementation: false,
+      this.documented: true,
+      this.maturity: Maturity.UNSPECIFIED,
+      this.platforms: DART2JS_PLATFORM | VM_PLATFORM})
+      : _categories = categories;
+
+  /// The categories in which the library can be used.
+  ///
+  /// If no categories are specified, the library is internal and cannot be
+  /// loaded by user code.
+  List<Category> get categories {
+    // `''.split(',')` returns [''], not [], so we handle that case separately.
+    if (_categories.isEmpty) return const <Category>[];
+    return _categories.split(',').map(parseCategory).toList();
+  }
+
+  /// The original "categories" String that was passed to the constructor.
+  ///
+  /// Can be used to construct a slightly modified copy of this LibraryInfo.
+  String get categoriesString {
+    return _categories;
+  }
+
+  bool get isDart2jsLibrary => (platforms & DART2JS_PLATFORM) != 0;
+
+  bool get isInternal => categories.isEmpty;
+
+  bool get isVmLibrary => (platforms & VM_PLATFORM) != 0;
+}
+
+/// Abstraction to capture the maturity of a library.
+class Maturity {
+  static const Maturity DEPRECATED = const Maturity(0, "Deprecated",
+      "This library will be remove before next major release.");
+  static const Maturity EXPERIMENTAL = const Maturity(
+      1,
+      "Experimental",
+      "This library is experimental and will likely change or be removed\n"
+      "in future versions.");
+  static const Maturity UNSTABLE = const Maturity(
+      2,
+      "Unstable",
+      "This library is in still changing and have not yet endured\n"
+      "sufficient real-world testing.\n"
+      "Backwards-compatibility is NOT guaranteed.");
+
+  static const Maturity WEB_STABLE = const Maturity(
+      3,
+      "Web Stable",
+      "This library is tracking the DOM evolution as defined by WC3.\n"
+      "Backwards-compatibility is NOT guaranteed.");
+
+  static const Maturity STABLE = const Maturity(
+      4,
+      "Stable",
+      "The library is stable. API backwards-compatibility is guaranteed.\n"
+      "However implementation details might change.");
+
+  static const Maturity LOCKED = const Maturity(5, "Locked",
+      "This library will not change except when serious bugs are encountered.");
+
+  static const Maturity UNSPECIFIED = const Maturity(-1, "Unspecified",
+      "The maturity for this library has not been specified.");
+
+  final int level;
+
+  final String name;
+
+  final String description;
+
+  const Maturity(this.level, this.name, this.description);
+
+  String toString() => "$name: $level\n$description\n";
+}
diff --git a/pub/front_end/lib/src/base/processed_options.dart b/pub/front_end/lib/src/base/processed_options.dart
new file mode 100644
index 0000000..60ef2ec
--- /dev/null
+++ b/pub/front_end/lib/src/base/processed_options.dart
@@ -0,0 +1,136 @@
+// 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:analyzer/src/summary/idl.dart';
+import 'package:front_end/compiler_options.dart';
+import 'package:front_end/file_system.dart';
+import 'package:front_end/src/base/uri_resolver.dart';
+import 'package:package_config/packages_file.dart' as package_config;
+
+/// Wrapper around [CompilerOptions] which exposes the options in a form useful
+/// to the front end implementation.
+///
+/// The intent is that the front end should immediately wrap any incoming
+/// [CompilerOptions] object in this class before doing further processing, and
+/// should thereafter access all options via the wrapper.  This ensures that
+/// options are interpreted in a consistent way and that data derived from
+/// options is not unnecessarily recomputed.
+class ProcessedOptions {
+  /// The raw [CompilerOptions] which this class wraps.
+  final CompilerOptions _raw;
+
+  /// The package map derived from the options, or `null` if the package map has
+  /// not been computed yet.
+  Map<String, Uri> _packages;
+
+  /// A URI resolver based on the options, or `null` if the URI resolver has not
+  /// been computed yet.
+  UriResolver _uriResolver;
+
+  /// The summary bundle for the SDK, or `null` if it has not been read yet.
+  PackageBundle _sdkSummary;
+
+  /// The location of the SDK, or `null` if the location hasn't been determined
+  /// yet.
+  Uri _sdkRoot;
+
+  /// Initializes a [ProcessedOptions] object wrapping the given [rawOptions].
+  ProcessedOptions(CompilerOptions rawOptions) : this._raw = rawOptions;
+
+  /// Determine whether to generate code for the SDK when compiling a
+  /// whole-program.
+  bool get compileSdk => _raw.compileSdk;
+
+  /// Get the [FileSystem] which should be used by the front end to access
+  /// files.
+  ///
+  /// If the client supplied roots using [CompilerOptions.multiRoots], the
+  /// returned [FileSystem] will automatically perform the appropriate mapping.
+  FileSystem get fileSystem {
+    // TODO(paulberry): support multiRoots.
+    assert(_raw.multiRoots.isEmpty);
+    return _raw.fileSystem;
+  }
+
+  /// Get the summary bundle for the SDK.
+  ///
+  /// This is an asynchronous getter since file system operations are required.
+  Future<PackageBundle> getSdkSummary() async {
+    if (_sdkSummary == null) {
+      Uri summaryLocation;
+      if (_raw.sdkSummary != null) {
+        // Options sdkSummary and sdkRoot are mutually exclusive.
+        assert(_raw.sdkRoot == null);
+        // No need to look for the SDK; we were told where the SDK summary is.
+        summaryLocation = _raw.sdkSummary;
+      } else {
+        // Need to look for the SDK summary inside the SDK.
+        var sdkRoot = await _getSdkRoot();
+        summaryLocation = sdkRoot.resolve(
+            'lib/_internal/' + (_raw.strongMode ? 'strong.sum' : 'spec.sum'));
+      }
+      var summaryBytes =
+          await fileSystem.entityForUri(summaryLocation).readAsBytes();
+      _sdkSummary = new PackageBundle.fromBuffer(summaryBytes);
+    }
+    return _sdkSummary;
+  }
+
+  /// Get the [UriResolver] which resolves "package:" and "dart:" URIs.
+  ///
+  /// This is an asynchronous getter since file system operations may be
+  /// required to locate/read the packages file as well as SDK metadata.
+  Future<UriResolver> getUriResolver() async {
+    if (_uriResolver == null) {
+      await _getPackages();
+      var sdkLibraries =
+          <String, Uri>{}; // TODO(paulberry): support SDK libraries
+      _uriResolver = new UriResolver(_packages, sdkLibraries);
+    }
+    return _uriResolver;
+  }
+
+  /// Get the package map which maps package names to URIs.
+  ///
+  /// This is an asynchronous getter since file system operations may be
+  /// required to locate/read the packages file.
+  Future<Map<String, Uri>> _getPackages() async {
+    if (_packages == null) {
+      if (_raw.packagesFileUri == null) {
+        throw new UnimplementedError(); // TODO(paulberry): search for .packages
+      } else if (_raw.packagesFileUri.path.isEmpty) {
+        _packages = {};
+      } else {
+        var contents =
+            await fileSystem.entityForUri(_raw.packagesFileUri).readAsBytes();
+        _packages = package_config.parse(contents, _raw.packagesFileUri);
+      }
+    }
+    return _packages;
+  }
+
+  /// Get the location of the SDK.
+  ///
+  /// This is an asynchronous getter since file system operations may be
+  /// required to locate the SDK.
+  Future<Uri> _getSdkRoot() async {
+    if (_sdkRoot == null) {
+      // If an SDK summary location was provided, the SDK itself should not be
+      // needed.
+      assert(_raw.sdkSummary == null);
+      if (_raw.sdkRoot == null) {
+        // TODO(paulberry): implement the algorithm for finding the SDK
+        // automagically.
+        throw new UnimplementedError();
+      }
+      _sdkRoot = _raw.sdkRoot;
+      if (!_sdkRoot.path.endsWith('/')) {
+        _sdkRoot = _sdkRoot.replace(path: _sdkRoot.path + '/');
+      }
+    }
+    return _sdkRoot;
+  }
+}
diff --git a/pub/front_end/lib/src/base/resolve_relative_uri.dart b/pub/front_end/lib/src/base/resolve_relative_uri.dart
new file mode 100644
index 0000000..cafcbf2
--- /dev/null
+++ b/pub/front_end/lib/src/base/resolve_relative_uri.dart
@@ -0,0 +1,27 @@
+// 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.
+
+/**
+ * Resolve the [containedUri] against [baseUri] using Dart rules.
+ *
+ * This function behaves similarly to [Uri.resolveUri], except that it properly
+ * handles situations like the following:
+ *
+ *     resolveRelativeUri(dart:core, bool.dart) -> dart:core/bool.dart
+ *     resolveRelativeUri(package:a/b.dart, ../c.dart) -> package:a/c.dart
+ */
+Uri resolveRelativeUri(Uri baseUri, Uri containedUri) {
+  if (containedUri.isAbsolute) {
+    return containedUri;
+  }
+  String scheme = baseUri.scheme;
+  // dart:core => dart:core/core.dart
+  if (scheme == 'dart') {
+    String part = baseUri.path;
+    if (part.indexOf('/') < 0) {
+      baseUri = Uri.parse('$scheme:$part/$part.dart');
+    }
+  }
+  return baseUri.resolveUri(containedUri);
+}
diff --git a/pub/front_end/lib/src/base/source.dart b/pub/front_end/lib/src/base/source.dart
new file mode 100644
index 0000000..a87f933
--- /dev/null
+++ b/pub/front_end/lib/src/base/source.dart
@@ -0,0 +1,175 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:front_end/src/base/analysis_target.dart';
+import 'package:front_end/src/base/timestamped_data.dart';
+import 'package:front_end/src/base/uri_kind.dart';
+import 'package:path/path.dart' as pathos;
+
+/// Base class providing implementations for the methods in [Source] that don't
+/// require filesystem access.
+abstract class BasicSource extends Source {
+  final Uri uri;
+
+  BasicSource(this.uri);
+
+  @override
+  String get encoding => uri.toString();
+
+  @override
+  String get fullName => encoding;
+
+  @override
+  int get hashCode => uri.hashCode;
+
+  @override
+  bool get isInSystemLibrary => uri.scheme == 'dart';
+
+  @override
+  String get shortName => pathos.basename(fullName);
+
+  @override
+  bool operator ==(Object object) => object is Source && object.uri == uri;
+}
+
+/**
+ * The interface `Source` defines the behavior of objects representing source code that can be
+ * analyzed by the analysis engine.
+ *
+ * Implementations of this interface need to be aware of some assumptions made by the analysis
+ * engine concerning sources:
+ * * Sources are not required to be unique. That is, there can be multiple instances representing
+ * the same source.
+ * * Sources are long lived. That is, the engine is allowed to hold on to a source for an extended
+ * period of time and that source must continue to report accurate and up-to-date information.
+ * Because of these assumptions, most implementations will not maintain any state but will delegate
+ * to an authoritative system of record in order to implement this API. For example, a source that
+ * represents files on disk would typically query the file system to determine the state of the
+ * file.
+ *
+ * If the instances that implement this API are the system of record, then they will typically be
+ * unique. In that case, sources that are created that represent non-existent files must also be
+ * retained so that if those files are created at a later date the long-lived sources representing
+ * those files will know that they now exist.
+ */
+abstract class Source implements AnalysisTarget {
+  /**
+   * An empty list of sources.
+   */
+  static const List<Source> EMPTY_LIST = const <Source>[];
+
+  /**
+   * Get the contents and timestamp of this source.
+   *
+   * Clients should consider using the method [AnalysisContext.getContents]
+   * because contexts can have local overrides of the content of a source that the source is not
+   * aware of.
+   *
+   * @return the contents and timestamp of the source
+   * @throws Exception if the contents of this source could not be accessed
+   */
+  TimestampedData<String> get contents;
+
+  /**
+   * Return an encoded representation of this source that can be used to create a source that is
+   * equal to this source.
+   *
+   * @return an encoded representation of this source
+   * See [SourceFactory.fromEncoding].
+   */
+  String get encoding;
+
+  /**
+   * Return the full (long) version of the name that can be displayed to the user to denote this
+   * source. For example, for a source representing a file this would typically be the absolute path
+   * of the file.
+   *
+   * @return a name that can be displayed to the user to denote this source
+   */
+  String get fullName;
+
+  /**
+   * Return a hash code for this source.
+   *
+   * @return a hash code for this source
+   * See [Object.hashCode].
+   */
+  @override
+  int get hashCode;
+
+  /**
+   * Return `true` if this source is in one of the system libraries.
+   *
+   * @return `true` if this is in a system library
+   */
+  bool get isInSystemLibrary;
+
+  @override
+  Source get librarySource => null;
+
+  /**
+   * Return the modification stamp for this source, or a negative value if the
+   * source does not exist. A modification stamp is a non-negative integer with
+   * the property that if the contents of the source have not been modified
+   * since the last time the modification stamp was accessed then the same value
+   * will be returned, but if the contents of the source have been modified one
+   * or more times (even if the net change is zero) the stamps will be different.
+   *
+   * Clients should consider using the method
+   * [AnalysisContext.getModificationStamp] because contexts can have local
+   * overrides of the content of a source that the source is not aware of.
+   */
+  int get modificationStamp;
+
+  /**
+   * Return a short version of the name that can be displayed to the user to denote this source. For
+   * example, for a source representing a file this would typically be the name of the file.
+   *
+   * @return a name that can be displayed to the user to denote this source
+   */
+  String get shortName;
+
+  @override
+  Source get source => this;
+
+  /**
+   * Return the URI from which this source was originally derived.
+   *
+   * @return the URI from which this source was originally derived
+   */
+  Uri get uri;
+
+  /**
+   * Return the kind of URI from which this source was originally derived. If this source was
+   * created from an absolute URI, then the returned kind will reflect the scheme of the absolute
+   * URI. If it was created from a relative URI, then the returned kind will be the same as the kind
+   * of the source against which the relative URI was resolved.
+   *
+   * @return the kind of URI from which this source was originally derived
+   */
+  UriKind get uriKind;
+
+  /**
+   * Return `true` if the given object is a source that represents the same source code as
+   * this source.
+   *
+   * @param object the object to be compared with this object
+   * @return `true` if the given object is a source that represents the same source code as
+   *         this source
+   * See [Object.==].
+   */
+  @override
+  bool operator ==(Object object);
+
+  /**
+   * Return `true` if this source exists.
+   *
+   * Clients should consider using the method [AnalysisContext.exists] because
+   * contexts can have local overrides of the content of a source that the source is not aware of
+   * and a source with local content is considered to exist even if there is no file on disk.
+   *
+   * @return `true` if this source exists
+   */
+  bool exists();
+}
diff --git a/pub/front_end/lib/src/scanner/syntactic_entity.dart b/pub/front_end/lib/src/base/syntactic_entity.dart
similarity index 100%
rename from pub/front_end/lib/src/scanner/syntactic_entity.dart
rename to pub/front_end/lib/src/base/syntactic_entity.dart
diff --git a/pub/front_end/lib/src/base/timestamped_data.dart b/pub/front_end/lib/src/base/timestamped_data.dart
new file mode 100644
index 0000000..4c76dc5
--- /dev/null
+++ b/pub/front_end/lib/src/base/timestamped_data.dart
@@ -0,0 +1,24 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/**
+ * Analysis data for which we have a modification time.
+ */
+class TimestampedData<E> {
+  /**
+   * The modification time of the source from which the data was created.
+   */
+  final int modificationTime;
+
+  /**
+   * The data that was created from the source.
+   */
+  final E data;
+
+  /**
+   * Initialize a newly created holder to associate the given [data] with the
+   * given [modificationTime].
+   */
+  TimestampedData(this.modificationTime, this.data);
+}
diff --git a/pub/front_end/lib/src/base/uri_kind.dart b/pub/front_end/lib/src/base/uri_kind.dart
new file mode 100644
index 0000000..0e6d007
--- /dev/null
+++ b/pub/front_end/lib/src/base/uri_kind.dart
@@ -0,0 +1,87 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/**
+ * The enumeration `UriKind` defines the different kinds of URI's that are known to the
+ * analysis engine. These are used to keep track of the kind of URI associated with a given source.
+ */
+class UriKind implements Comparable<UriKind> {
+  /**
+   * A 'dart:' URI.
+   */
+  static const UriKind DART_URI = const UriKind('DART_URI', 0, 0x64);
+
+  /**
+   * A 'file:' URI.
+   */
+  static const UriKind FILE_URI = const UriKind('FILE_URI', 1, 0x66);
+
+  /**
+   * A 'package:' URI.
+   */
+  static const UriKind PACKAGE_URI = const UriKind('PACKAGE_URI', 2, 0x70);
+
+  static const List<UriKind> values = const [DART_URI, FILE_URI, PACKAGE_URI];
+
+  /**
+   * The name of this URI kind.
+   */
+  final String name;
+
+  /**
+   * The ordinal value of the URI kind.
+   */
+  final int ordinal;
+
+  /**
+   * The single character encoding used to identify this kind of URI.
+   */
+  final int encoding;
+
+  /**
+   * Initialize a newly created URI kind to have the given encoding.
+   */
+  const UriKind(this.name, this.ordinal, this.encoding);
+
+  @override
+  int get hashCode => ordinal;
+
+  @override
+  int compareTo(UriKind other) => ordinal - other.ordinal;
+
+  @override
+  String toString() => name;
+
+  /**
+   * Return the URI kind represented by the given [encoding], or `null` if there
+   * is no kind with the given encoding.
+   */
+  static UriKind fromEncoding(int encoding) {
+    while (true) {
+      if (encoding == 0x64) {
+        return DART_URI;
+      } else if (encoding == 0x66) {
+        return FILE_URI;
+      } else if (encoding == 0x70) {
+        return PACKAGE_URI;
+      }
+      break;
+    }
+    return null;
+  }
+
+  /**
+   * Return the URI kind corresponding to the given scheme string.
+   */
+  static UriKind fromScheme(String scheme) {
+    if (scheme == 'package') {
+      return UriKind.PACKAGE_URI;
+    } else if (scheme == 'dart') {
+      return UriKind.DART_URI;
+    } else if (scheme == 'file') {
+      return UriKind.FILE_URI;
+    }
+    return UriKind.FILE_URI;
+  }
+}
diff --git a/pub/front_end/lib/src/base/uri_resolver.dart b/pub/front_end/lib/src/base/uri_resolver.dart
new file mode 100644
index 0000000..0c6a420
--- /dev/null
+++ b/pub/front_end/lib/src/base/uri_resolver.dart
@@ -0,0 +1,68 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// The class `UriResolver` implements the rules for resolving "dart:" and
+/// "package:" URIs.
+class UriResolver {
+  /// The URI scheme used for "package" URIs.
+  static const PACKAGE_SCHEME = 'package';
+
+  /// The URI scheme used for "dart" URIs.
+  static const DART_SCHEME = 'dart';
+
+  /// A map from package name to the file URI of the "lib" directory of the
+  /// corresponding package.  This is equivalent to the format returned by
+  /// the "package_config" package's parse() function.
+  final Map<String, Uri> packages;
+
+  /// A map from SDK library name (e.g. `core` for `dart:core`) to the file URI
+  /// of the defining compilation unit of the SDK library.
+  final Map<String, Uri> sdkLibraries;
+
+  UriResolver(this.packages, this.sdkLibraries);
+
+  /// Converts "package:" and "dart:" URIs to the locations of the corresponding
+  /// files.
+  ///
+  /// If the given URI is a "package:" or "dart:" URI, is well formed, and names
+  /// a package or dart library that is recognized, returns the URI it resolves
+  /// to.  If the given URI is a "package:" or "dart:" URI, and is ill-formed
+  /// or names a package or dart library that is not recognized, returns `null`.
+  ///
+  /// If the given URI has any scheme other than "package:" or "dart:", it is
+  /// returned unchanged.
+  ///
+  /// It is not necessary for the URI to be absolute (relative URIs will be
+  /// passed through unchanged).
+  ///
+  /// Note that no I/O is performed; the URI that is returned will be
+  /// independent of whether or not any particular file exists on the file
+  /// system.
+  Uri resolve(Uri uri) {
+    if (uri.scheme == DART_SCHEME || uri.scheme == PACKAGE_SCHEME) {
+      var path = uri.path;
+      var slashIndex = path.indexOf('/');
+      String prefix;
+      String rest;
+      if (slashIndex >= 0) {
+        prefix = path.substring(0, slashIndex);
+        rest = path.substring(slashIndex + 1);
+      } else {
+        prefix = path;
+        rest = '';
+      }
+      Uri libUri;
+      if (uri.scheme == PACKAGE_SCHEME) {
+        if (slashIndex < 0) return null;
+        libUri = packages[prefix];
+      } else if (uri.scheme == DART_SCHEME) {
+        libUri = sdkLibraries[prefix];
+      }
+      if (libUri == null) return null;
+      return libUri.resolve(rest);
+    } else {
+      return uri;
+    }
+  }
+}
diff --git a/pub/front_end/lib/src/dependency_grapher_impl.dart b/pub/front_end/lib/src/dependency_grapher_impl.dart
new file mode 100644
index 0000000..66aa443
--- /dev/null
+++ b/pub/front_end/lib/src/dependency_grapher_impl.dart
@@ -0,0 +1,151 @@
+// 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:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/error/listener.dart';
+import 'package:analyzer/src/dart/scanner/reader.dart';
+import 'package:analyzer/src/generated/parser.dart';
+import 'package:front_end/dependency_grapher.dart';
+import 'package:front_end/src/async_dependency_walker.dart';
+import 'package:front_end/src/base/processed_options.dart';
+import 'package:front_end/src/base/uri_resolver.dart';
+import 'package:front_end/src/scanner/scanner.dart';
+
+/// Generates a representation of the dependency graph of a program.
+///
+/// Given the Uri of one or more files, this function follows `import`,
+/// `export`, and `part` declarations to discover a graph of all files involved
+/// in the program.
+///
+/// If a [fileReader] is supplied, it is used to read file contents; otherwise
+/// they are read directly from `options.fileSystem`.
+///
+/// This is intended for internal use by the front end.  Clients should use
+/// package:front_end/dependency_grapher.dart.
+Future<Graph> graphForProgram(List<Uri> sources, ProcessedOptions options,
+    {FileReader fileReader}) async {
+  var uriResolver = await options.getUriResolver();
+  fileReader ??= (originalUri, resolvedUri) =>
+      options.fileSystem.entityForUri(resolvedUri).readAsString();
+  var walker = new _Walker(fileReader, uriResolver, options.compileSdk);
+  var startingPoint = new _StartingPoint(walker, sources);
+  await walker.walk(startingPoint);
+  return walker.graph;
+}
+
+/// Type of the callback function used by [graphForProgram] to read file
+/// contents.
+typedef Future<String> FileReader(Uri originalUri, Uri resolvedUri);
+
+class _Scanner extends Scanner {
+  _Scanner(String contents) : super(new CharSequenceReader(contents)) {
+    preserveComments = false;
+  }
+
+  @override
+  void reportError(errorCode, int offset, List<Object> arguments) {
+    // TODO(paulberry): report errors.
+  }
+}
+
+class _StartingPoint extends _WalkerNode {
+  final List<Uri> sources;
+
+  _StartingPoint(_Walker walker, this.sources) : super(walker, null);
+
+  @override
+  Future<List<_WalkerNode>> computeDependencies() async =>
+      sources.map(walker.nodeForUri).toList();
+}
+
+class _Walker extends AsyncDependencyWalker<_WalkerNode> {
+  final FileReader fileReader;
+  final UriResolver uriResolver;
+  final _nodesByUri = <Uri, _WalkerNode>{};
+  final graph = new Graph();
+  final bool compileSdk;
+
+  _Walker(this.fileReader, this.uriResolver, this.compileSdk);
+
+  @override
+  Future<Null> evaluate(_WalkerNode v) {
+    if (v is _StartingPoint) return new Future.value();
+    return evaluateScc([v]);
+  }
+
+  @override
+  Future<Null> evaluateScc(List<_WalkerNode> scc) {
+    var cycle = new LibraryCycleNode();
+    for (var walkerNode in scc) {
+      cycle.libraries[walkerNode.uri] = walkerNode.library;
+    }
+    graph.topologicallySortedCycles.add(cycle);
+    return new Future.value();
+  }
+
+  _WalkerNode nodeForUri(Uri referencedUri) {
+    var dependencyNode = _nodesByUri.putIfAbsent(
+        referencedUri, () => new _WalkerNode(this, referencedUri));
+    return dependencyNode;
+  }
+}
+
+class _WalkerNode extends Node<_WalkerNode> {
+  static final dartCoreUri = Uri.parse('dart:core');
+  final _Walker walker;
+  final Uri uri;
+  final LibraryNode library;
+
+  _WalkerNode(this.walker, Uri uri)
+      : uri = uri,
+        library = new LibraryNode(uri);
+
+  @override
+  Future<List<_WalkerNode>> computeDependencies() async {
+    var dependencies = <_WalkerNode>[];
+    // TODO(paulberry): add error recovery if the file can't be read.
+    var resolvedUri = walker.uriResolver.resolve(uri);
+    if (resolvedUri == null) {
+      // TODO(paulberry): If an error reporter was provided, report the error
+      // in the proper way and continue.
+      throw new StateError('Invalid URI: $uri');
+    }
+    var contents = await walker.fileReader(uri, resolvedUri);
+    var scanner = new _Scanner(contents);
+    var token = scanner.tokenize();
+    // TODO(paulberry): report errors.
+    var parser = new Parser(null, AnalysisErrorListener.NULL_LISTENER);
+    var unit = parser.parseDirectives(token);
+    bool coreUriFound = false;
+    void handleDependency(Uri referencedUri) {
+      _WalkerNode dependencyNode = walker.nodeForUri(referencedUri);
+      library.dependencies.add(dependencyNode.library);
+      if (referencedUri.scheme != 'dart' || walker.compileSdk) {
+        dependencies.add(dependencyNode);
+      }
+      if (referencedUri == dartCoreUri) {
+        coreUriFound = true;
+      }
+    }
+
+    for (var directive in unit.directives) {
+      if (directive is UriBasedDirective) {
+        // TODO(paulberry): when we support SDK libraries, we'll need more
+        // complex logic here to find SDK parts correctly.
+        var referencedUri = uri.resolve(directive.uri.stringValue);
+        if (directive is PartDirective) {
+          library.parts.add(referencedUri);
+        } else {
+          handleDependency(referencedUri);
+        }
+      }
+    }
+    if (!coreUriFound) {
+      handleDependency(dartCoreUri);
+    }
+    return dependencies;
+  }
+}
diff --git a/pub/front_end/lib/src/dependency_walker.dart b/pub/front_end/lib/src/dependency_walker.dart
new file mode 100644
index 0000000..7a27acb
--- /dev/null
+++ b/pub/front_end/lib/src/dependency_walker.dart
@@ -0,0 +1,168 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/**
+ * Instances of [Node] represent nodes in a dependency graph.  The
+ * type parameter, [NodeType], is the derived type (this affords some
+ * extra type safety by making it difficult to accidentally construct
+ * bridges between unrelated dependency graphs).
+ */
+abstract class Node<NodeType> {
+  /**
+   * Index used by Tarjan's strongly connected components algorithm.
+   * Zero means the node has not been visited yet; a nonzero value
+   * counts the order in which the node was visited.
+   */
+  int _index = 0;
+
+  /**
+   * Low link used by Tarjan's strongly connected components
+   * algorithm.  This represents the smallest [_index] of all the nodes
+   * in the strongly connected component to which this node belongs.
+   */
+  int _lowLink = 0;
+
+  List<NodeType> _dependencies;
+
+  /**
+   * Retrieve the dependencies of this node.
+   */
+  List<NodeType> get dependencies => _dependencies ??= computeDependencies();
+
+  /**
+   * Indicates whether this node has been evaluated yet.
+   */
+  bool get isEvaluated;
+
+  /**
+   * Compute the dependencies of this node.
+   */
+  List<NodeType> computeDependencies();
+}
+
+/**
+ * An instance of [DependencyWalker] contains the core algorithms for
+ * walking a dependency graph and evaluating nodes in a safe order.
+ */
+abstract class DependencyWalker<NodeType extends Node<NodeType>> {
+  /**
+   * Called by [walk] to evaluate a single non-cyclical node, after
+   * all that node's dependencies have been evaluated.
+   */
+  void evaluate(NodeType v);
+
+  /**
+   * Called by [walk] to evaluate a strongly connected component
+   * containing one or more nodes.  All dependencies of the strongly
+   * connected component have been evaluated.
+   */
+  void evaluateScc(List<NodeType> scc);
+
+  /**
+   * Walk the dependency graph starting at [startingPoint], finding
+   * strongly connected components and evaluating them in a safe order
+   * by calling [evaluate] and [evaluateScc].
+   *
+   * This is an implementation of Tarjan's strongly connected
+   * components algorithm
+   * (https://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm).
+   */
+  void walk(NodeType startingPoint) {
+    // TODO(paulberry): consider rewriting in a non-recursive way so
+    // that long dependency chains don't cause stack overflow.
+
+    // TODO(paulberry): in the event that an exception occurs during
+    // the walk, restore the state of the [Node] data structures so
+    // that further evaluation will be safe.
+
+    // The index which will be assigned to the next node that is
+    // freshly visited.
+    int index = 1;
+
+    // Stack of nodes which have been seen so far and whose strongly
+    // connected component is still being determined.  Nodes are only
+    // popped off the stack when they are evaluated, so sometimes the
+    // stack contains nodes that were visited after the current node.
+    List<NodeType> stack = <NodeType>[];
+
+    void strongConnect(NodeType node) {
+      bool hasTrivialCycle = false;
+
+      // Assign the current node an index and add it to the stack.  We
+      // haven't seen any of its dependencies yet, so set its lowLink
+      // to its index, indicating that so far it is the only node in
+      // its strongly connected component.
+      node._index = node._lowLink = index++;
+      stack.add(node);
+
+      // Consider the node's dependencies one at a time.
+      for (NodeType dependency in node.dependencies) {
+        // If the dependency has already been evaluated, it can't be
+        // part of this node's strongly connected component, so we can
+        // skip it.
+        if (dependency.isEvaluated) {
+          continue;
+        }
+        if (identical(node, dependency)) {
+          // If a node includes itself as a dependency, there is no need to
+          // explore the dependency further.
+          hasTrivialCycle = true;
+        } else if (dependency._index == 0) {
+          // The dependency hasn't been seen yet, so recurse on it.
+          strongConnect(dependency);
+          // If the dependency's lowLink refers to a node that was
+          // visited before the current node, that means that the
+          // current node, the dependency, and the node referred to by
+          // the dependency's lowLink are all part of the same
+          // strongly connected component, so we need to update the
+          // current node's lowLink accordingly.
+          if (dependency._lowLink < node._lowLink) {
+            node._lowLink = dependency._lowLink;
+          }
+        } else {
+          // The dependency has already been seen, so it is part of
+          // the current node's strongly connected component.  If it
+          // was visited earlier than the current node's lowLink, then
+          // it is a new addition to the current node's strongly
+          // connected component, so we need to update the current
+          // node's lowLink accordingly.
+          if (dependency._index < node._lowLink) {
+            node._lowLink = dependency._index;
+          }
+        }
+      }
+
+      // If the current node's lowLink is the same as its index, then
+      // we have finished visiting a strongly connected component, so
+      // pop the stack and evaluate it before moving on.
+      if (node._lowLink == node._index) {
+        // The strongly connected component has only one node.  If there is a
+        // cycle, it's a trivial one.
+        if (identical(stack.last, node)) {
+          stack.removeLast();
+          if (hasTrivialCycle) {
+            evaluateScc(<NodeType>[node]);
+          } else {
+            evaluate(node);
+          }
+        } else {
+          // There are multiple nodes in the strongly connected
+          // component.
+          List<NodeType> scc = <NodeType>[];
+          while (true) {
+            NodeType otherNode = stack.removeLast();
+            scc.add(otherNode);
+            if (identical(otherNode, node)) {
+              break;
+            }
+          }
+          evaluateScc(scc);
+        }
+      }
+    }
+
+    // Kick off the algorithm starting with the starting point.
+    strongConnect(startingPoint);
+  }
+}
diff --git a/pub/front_end/lib/src/incremental_kernel_generator_impl.dart b/pub/front_end/lib/src/incremental_kernel_generator_impl.dart
new file mode 100644
index 0000000..efd4ddd
--- /dev/null
+++ b/pub/front_end/lib/src/incremental_kernel_generator_impl.dart
@@ -0,0 +1,147 @@
+// 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:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/ast/standard_resolution_map.dart';
+import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/error/error.dart';
+import 'package:analyzer/src/generated/engine.dart';
+import 'package:analyzer/src/generated/source.dart';
+import 'package:front_end/incremental_kernel_generator.dart';
+import 'package:front_end/incremental_resolved_ast_generator.dart';
+import 'package:front_end/src/base/processed_options.dart';
+import 'package:front_end/src/base/source.dart';
+import 'package:front_end/src/incremental_resolved_ast_generator_impl.dart';
+import 'package:kernel/analyzer/loader.dart';
+import 'package:kernel/kernel.dart' hide Source;
+import 'package:kernel/repository.dart';
+
+dynamic unimplemented() {
+  // TODO(paulberry): get rid of this.
+  throw new UnimplementedError();
+}
+
+DartOptions _convertOptions(ProcessedOptions options) {
+  // TODO(paulberry): make sure options.compileSdk is handled correctly.
+  return new DartOptions(
+      strongMode: true, // TODO(paulberry): options.strongMode,
+      sdk: null, // TODO(paulberry): _uriToPath(options.sdkRoot, options),
+      sdkSummary:
+          null, // TODO(paulberry): options.compileSdk ? null : _uriToPath(options.sdkSummary, options),
+      packagePath:
+          null, // TODO(paulberry): _uriToPath(options.packagesFileUri, options),
+      declaredVariables: null // TODO(paulberry): options.declaredVariables
+      );
+}
+
+/// Implementation of [IncrementalKernelGenerator].
+///
+/// Theory of operation: an instance of [IncrementalResolvedAstGenerator] is
+/// used to obtain resolved ASTs, and these are fed into kernel code generation
+/// logic.
+///
+/// Note that the kernel doesn't expect to take resolved ASTs as a direct input;
+/// it expects to request resolved ASTs from an [AnalysisContext].  To deal with
+/// this, we create [_AnalysisContextProxy] which returns the resolved ASTs when
+/// requested.  TODO(paulberry): Make this unnecessary.
+class IncrementalKernelGeneratorImpl implements IncrementalKernelGenerator {
+  final IncrementalResolvedAstGenerator _resolvedAstGenerator;
+  final ProcessedOptions _options;
+
+  IncrementalKernelGeneratorImpl(Uri source, ProcessedOptions options)
+      : _resolvedAstGenerator =
+            new IncrementalResolvedAstGeneratorImpl(source, options),
+        _options = options;
+
+  @override
+  Future<DeltaProgram> computeDelta(
+      {Future<Null> watch(Uri uri, bool used)}) async {
+    var deltaLibraries = await _resolvedAstGenerator.computeDelta();
+    var kernelOptions = _convertOptions(_options);
+    var packages = null; // TODO(paulberry)
+    var kernels = <Uri, Program>{};
+    for (Uri uri in deltaLibraries.newState.keys) {
+      // The kernel generation code doesn't currently support building a kernel
+      // directly from resolved ASTs--it wants to query an analysis context.  So
+      // we provide it with a proxy analysis context that feeds it the resolved
+      // ASTs.
+      var strongMode = true; // TODO(paulberry): set this correctly
+      var analysisOptions = new _AnalysisOptionsProxy(strongMode);
+      var context =
+          new _AnalysisContextProxy(deltaLibraries.newState, analysisOptions);
+      var repository = new Repository();
+      var loader =
+          new DartLoader(repository, kernelOptions, packages, context: context);
+      loader.loadLibrary(uri);
+      kernels[uri] = new Program(repository.libraries);
+      // TODO(paulberry) rework watch invocation to eliminate race condition,
+      // include part source files, and prevent watch from being a bottleneck
+      if (watch != null) await watch(uri, true);
+    }
+    // TODO(paulberry) invoke watch with used=false for each unused source
+    return new DeltaProgram(kernels);
+  }
+
+  @override
+  void invalidate(String path) => _resolvedAstGenerator.invalidate(path);
+
+  @override
+  void invalidateAll() => _resolvedAstGenerator.invalidateAll();
+}
+
+class _AnalysisContextProxy implements AnalysisContext {
+  final Map<Uri, Map<Uri, CompilationUnit>> _resolvedLibraries;
+
+  @override
+  final _SourceFactoryProxy sourceFactory = new _SourceFactoryProxy();
+
+  @override
+  final AnalysisOptions analysisOptions;
+
+  _AnalysisContextProxy(this._resolvedLibraries, this.analysisOptions);
+
+  List<AnalysisError> computeErrors(Source source) {
+    // TODO(paulberry): do we need to return errors sometimes?
+    return [];
+  }
+
+  LibraryElement computeLibraryElement(Source source) {
+    assert(_resolvedLibraries.containsKey(source.uri));
+    return resolutionMap
+        .elementDeclaredByCompilationUnit(
+            _resolvedLibraries[source.uri][source.uri])
+        .library;
+  }
+
+  noSuchMethod(Invocation invocation) => unimplemented();
+
+  CompilationUnit resolveCompilationUnit(
+      Source unitSource, LibraryElement library) {
+    var unit = _resolvedLibraries[library.source.uri][unitSource.uri];
+    assert(unit != null);
+    return unit;
+  }
+}
+
+class _AnalysisOptionsProxy implements AnalysisOptions {
+  final bool strongMode;
+
+  _AnalysisOptionsProxy(this.strongMode);
+
+  noSuchMethod(Invocation invocation) => unimplemented();
+}
+
+class _SourceFactoryProxy implements SourceFactory {
+  Source forUri2(Uri absoluteUri) => new _SourceProxy(absoluteUri);
+
+  noSuchMethod(Invocation invocation) => unimplemented();
+}
+
+class _SourceProxy extends BasicSource {
+  _SourceProxy(Uri uri) : super(uri);
+
+  noSuchMethod(Invocation invocation) => unimplemented();
+}
diff --git a/pub/front_end/lib/src/incremental_resolved_ast_generator_impl.dart b/pub/front_end/lib/src/incremental_resolved_ast_generator_impl.dart
new file mode 100644
index 0000000..d0b093b
--- /dev/null
+++ b/pub/front_end/lib/src/incremental_resolved_ast_generator_impl.dart
@@ -0,0 +1,302 @@
+// 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:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/file_system/file_system.dart';
+import 'package:analyzer/src/context/context.dart';
+import 'package:analyzer/src/dart/analysis/byte_store.dart';
+import 'package:analyzer/src/dart/analysis/driver.dart' as driver;
+import 'package:analyzer/src/dart/analysis/file_state.dart';
+import 'package:analyzer/src/generated/engine.dart';
+import 'package:analyzer/src/generated/sdk.dart';
+import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer/src/summary/idl.dart';
+import 'package:analyzer/src/util/absolute_path.dart';
+import 'package:front_end/incremental_resolved_ast_generator.dart';
+import 'package:front_end/src/base/file_repository.dart';
+import 'package:front_end/src/base/processed_options.dart';
+import 'package:front_end/src/base/resolve_relative_uri.dart';
+import 'package:front_end/src/base/source.dart';
+import 'package:front_end/src/dependency_grapher_impl.dart';
+import 'package:path/src/context.dart';
+
+dynamic unimplemented() {
+  // TODO(paulberry): get rid of this.
+  throw new UnimplementedError();
+}
+
+/// Implementation of [IncrementalKernelGenerator].
+///
+/// Theory of operation: this class is a thin wrapper around
+/// [driver.AnalysisDriver].  When the client requests a new delta, we forward
+/// the request to the analysis driver.  When the client calls an invalidate
+/// method, we ensure that the proper files will be re-read next time a delta is
+/// requested.
+///
+/// Note that the analysis driver expects to be able to read file contents
+/// synchronously based on filesystem path rather than asynchronously based on
+/// URI, so the file contents are first read into memory using the asynchronous
+/// FileSystem API, and then these are fed into the analysis driver using a
+/// proxy implementation of [ResourceProvider].  TODO(paulberry): make this (and
+/// other proxies in this file) unnecessary.
+class IncrementalResolvedAstGeneratorImpl
+    implements IncrementalResolvedAstGenerator {
+  driver.AnalysisDriverScheduler _scheduler;
+  final _fileRepository = new FileRepository();
+  _ResourceProviderProxy _resourceProvider;
+  driver.AnalysisDriver _driver;
+  bool _isInitialized = false;
+  final ProcessedOptions _options;
+  final Uri _source;
+  bool _schedulerStarted = false;
+  final _fileState = <Uri, String>{};
+
+  IncrementalResolvedAstGeneratorImpl(this._source, this._options);
+
+  @override
+  Future<DeltaLibraries> computeDelta() async {
+    if (!_isInitialized) {
+      await init();
+    }
+    // The analysis driver doesn't currently support an asynchronous file API,
+    // so we have to find all the files first to read their contents.
+    // TODO(paulberry): this is an unnecessary source of duplicate work and
+    // should be eliminated ASAP.
+    var graph =
+        await graphForProgram([_source], _options, fileReader: _fileReader);
+    // TODO(paulberry): collect no-longer-referenced files from _fileState and
+    // _fileRepository.
+    var libraries = <Uri, Map<Uri, CompilationUnit>>{};
+    if (!_schedulerStarted) {
+      _scheduler.start();
+      _schedulerStarted = true;
+    }
+    for (var libraryCycle in graph.topologicallySortedCycles) {
+      for (var libraryUri in libraryCycle.libraries.keys) {
+        var libraryNode = libraryCycle.libraries[libraryUri];
+        for (var partUri in libraryNode.parts) {
+          // TODO(paulberry): resolve the part URI.
+          _fileReader(partUri, partUri);
+        }
+      }
+      for (var libraryUri in libraryCycle.libraries.keys) {
+        var libraryNode = libraryCycle.libraries[libraryUri];
+        var result =
+            await _driver.getResult(_fileRepository.pathForUri(libraryUri));
+        // TODO(paulberry): handle errors.
+        var units = {libraryUri: result.unit};
+        for (var partUri in libraryNode.parts) {
+          // Really we ought to have a driver API that lets us request a
+          // specific part of a given library.  Otherwise we will run into
+          // problems if a part is included in multiple libraries.
+          // TODO(paulberry): address this.
+          var partResult =
+              await _driver.getResult(_fileRepository.pathForUri(partUri));
+          // TODO(paulberry): handle errors.
+          units[partUri] = partResult.unit;
+        }
+        libraries[libraryUri] = units;
+      }
+    }
+    _driver.addFile(_fileRepository.pathForUri(_source));
+    // TODO(paulberry): stop the scheduler
+    return new DeltaLibraries(libraries);
+  }
+
+  Future<Null> init() async {
+    // TODO(paulberry): can we just use null?
+    var performanceLog = new driver.PerformanceLog(new _NullStringSink());
+    _scheduler = new driver.AnalysisDriverScheduler(performanceLog);
+    _resourceProvider = new _ResourceProviderProxy(_fileRepository);
+    // TODO(paulberry): MemoryByteStore leaks memory (it never discards data).
+    // Do something better here.
+    var byteStore = new MemoryByteStore();
+    // TODO(paulberry): can we just use null?
+    var fileContentOverlay = new FileContentOverlay();
+    var sdkContext = new AnalysisContextImpl();
+    var sdkBundle = await _options.getSdkSummary();
+    var dartSdk = new _DartSdkProxy(sdkBundle, sdkContext, _fileRepository);
+    sdkContext.sourceFactory =
+        new SourceFactory([new DartUriResolver(dartSdk)]);
+
+    var sourceFactory = new _SourceFactoryProxy(dartSdk, _fileRepository);
+    var analysisOptions = new AnalysisOptionsImpl();
+    _driver = new driver.AnalysisDriver(
+        _scheduler,
+        performanceLog,
+        _resourceProvider,
+        byteStore,
+        fileContentOverlay,
+        'front_end',
+        sourceFactory,
+        analysisOptions,
+        sdkBundle: sdkBundle);
+    _isInitialized = true;
+  }
+
+  @override
+  void invalidate(String path) {
+    throw new UnimplementedError();
+  }
+
+  @override
+  void invalidateAll() {
+    _fileState.clear();
+    _fileRepository.clearContents();
+    // TODO(paulberry): verify that this has an effect (requires a multi-file
+    // test).
+    if (_isInitialized) {
+      _driver.knownFiles.forEach(_driver.changeFile);
+    }
+  }
+
+  Future<String> _fileReader(Uri originalUri, Uri resolvedUri) async {
+    String contents = _fileState[resolvedUri] ??=
+        await _options.fileSystem.entityForUri(resolvedUri).readAsString();
+    _fileRepository.store(originalUri, contents);
+    return contents;
+  }
+}
+
+class _DartSdkProxy implements DartSdk {
+  final PackageBundle summary;
+
+  final AnalysisContext context;
+
+  final FileRepository _fileRepository;
+
+  _DartSdkProxy(this.summary, this.context, this._fileRepository);
+
+  @override
+  PackageBundle getLinkedBundle() => summary;
+
+  @override
+  Source mapDartUri(String uriString) {
+    var uri = Uri.parse(uriString);
+    return new _SourceProxy(
+        uri, _fileRepository.pathForUri(uri, allocate: true));
+  }
+
+  noSuchMethod(Invocation invocation) => unimplemented();
+}
+
+class _FileProxy implements File {
+  final _SourceProxy _source;
+
+  final _ResourceProviderProxy _resourceProvider;
+
+  _FileProxy(this._source, this._resourceProvider);
+
+  @override
+  String get path => _source.fullName;
+
+  @override
+  String get shortName => path;
+
+  @override
+  Source createSource([Uri uri]) {
+    assert(uri == null);
+    return _source;
+  }
+
+  noSuchMethod(Invocation invocation) => unimplemented();
+
+  @override
+  String readAsStringSync() {
+    return _resourceProvider._fileRepository.contentsForPath(path);
+  }
+}
+
+/// A string sink that ignores everything written to it.
+class _NullStringSink implements StringSink {
+  void write(Object obj) {}
+  void writeAll(Iterable objects, [String separator = ""]) {}
+  void writeCharCode(int charCode) {}
+  void writeln([Object obj = ""]) {}
+}
+
+class _ResourceProviderProxy implements ResourceProvider {
+  final FileRepository _fileRepository;
+
+  _ResourceProviderProxy(this._fileRepository);
+
+  @override
+  AbsolutePathContext get absolutePathContext => throw new UnimplementedError();
+
+  @override
+  Context get pathContext => throw new UnimplementedError();
+
+  @override
+  File getFile(String path) {
+    return new _FileProxy(
+        new _SourceProxy(_fileRepository.uriForPath(path), path), this);
+  }
+
+  @override
+  Folder getFolder(String path) => throw new UnimplementedError();
+
+  @override
+  Future<List<int>> getModificationTimes(List<Source> sources) =>
+      throw new UnimplementedError();
+
+  @override
+  Resource getResource(String path) => throw new UnimplementedError();
+
+  @override
+  Folder getStateLocation(String pluginId) => throw new UnimplementedError();
+}
+
+class _SourceFactoryProxy implements SourceFactory {
+  @override
+  final DartSdk dartSdk;
+
+  final FileRepository _fileRepository;
+
+  @override
+  AnalysisContext context;
+
+  _SourceFactoryProxy(this.dartSdk, this._fileRepository);
+
+  @override
+  SourceFactory clone() => new _SourceFactoryProxy(dartSdk, _fileRepository);
+
+  @override
+  Source forUri(String absoluteUri) {
+    Uri uri = Uri.parse(absoluteUri);
+    return forUri2(uri);
+  }
+
+  @override
+  Source forUri2(Uri absoluteUri) {
+    return new _SourceProxy(
+        absoluteUri, _fileRepository.pathForUri(absoluteUri, allocate: true));
+  }
+
+  noSuchMethod(Invocation invocation) => unimplemented();
+
+  Source resolveUri(Source containingSource, String containedUri) {
+    // TODO(paulberry): re-use code from dependency_grapher_impl, and support
+    // SDK URI resolution logic.
+    String absoluteUri =
+        resolveRelativeUri(containingSource?.uri, Uri.parse(containedUri))
+            .toString();
+    return forUri(absoluteUri);
+  }
+
+  @override
+  Uri restoreUri(Source source) => source.uri;
+}
+
+class _SourceProxy extends BasicSource {
+  @override
+  final String fullName;
+
+  _SourceProxy(Uri uri, this.fullName) : super(uri);
+
+  int get modificationStamp => 0;
+
+  noSuchMethod(Invocation invocation) => unimplemented();
+}
diff --git a/pub/front_end/lib/src/libraries_reader.dart b/pub/front_end/lib/src/libraries_reader.dart
new file mode 100644
index 0000000..ded5d9f
--- /dev/null
+++ b/pub/front_end/lib/src/libraries_reader.dart
@@ -0,0 +1,201 @@
+import 'package:analyzer/src/summary/idl.dart';
+import 'package:front_end/src/base/library_info.dart';
+
+/// Decodes the contents of the SDK's "libraries.dart" file.
+///
+/// Caller should pass in the unlinked summary of the libraries.dart file.  This
+/// function will materialize the "libraries" constant based on information in
+/// the summary.
+///
+/// Note that this code is not intended to be fully general; it makes some
+/// assumptions about the structure of the "libraries.dart" file (such as what
+/// declarations are expected to be present in it, and the types of those
+/// declarations).
+Map<String, LibraryInfo> readLibraries(UnlinkedUnit librariesUnit) {
+  var constContext = new _ConstContext(librariesUnit.references);
+  for (var variable in librariesUnit.variables) {
+    if (!variable.isConst) continue;
+    constContext.topLevelConstants[variable.name] =
+        new _ConstVariable(variable.initializer.bodyExpr, constContext);
+  }
+  for (var cls in librariesUnit.classes) {
+    if (cls.name == 'Maturity') {
+      for (var field in cls.fields) {
+        if (!field.isConst) continue;
+        constContext.maturityConstants[field.name] =
+            new _ConstVariable(field.initializer.bodyExpr, constContext);
+      }
+    }
+  }
+  return constContext.topLevelConstants['libraries'].value;
+}
+
+/// Function type used to invoke a constructor based on dynamic information.
+///
+/// Caller supplies two callbacks ([positional] and [named]) which can be used
+/// to query the arguments passed to the constructor.  These callbacks will
+/// return the requested argument if it was provided; otherwise they will return
+/// the supplied default value.
+typedef dynamic _Constructor(dynamic positional(int i, [dynamic defaultValue]),
+    dynamic named(String name, [dynamic defaultValue]));
+
+/// Contextual information used to evaluate constants in the "libraries.dart"
+/// file.
+class _ConstContext {
+  /// Top level constants in the "libraries.dart" file.
+  final topLevelConstants = <String, _ConstVariable>{};
+
+  /// Static constants in "libraries.dart"'s "Maturity" class.
+  final maturityConstants = <String, _ConstVariable>{};
+
+  /// References from the unlinked summary of the "libraries.dart" file.
+  final List<UnlinkedReference> references;
+
+  _ConstContext(this.references);
+}
+
+/// Information necessary to evaluate a single constant from the
+/// "libraries.dart" file.
+class _ConstVariable {
+  /// The constant expression from the unlinked summary.
+  final UnlinkedExpr expr;
+
+  /// Contextual information necessary to evaluate the constant.
+  final _ConstContext context;
+
+  /// The evaluated value, or `null` if it hasn't been evaluated yet.
+  dynamic _value;
+
+  _ConstVariable(this.expr, this.context);
+
+  /// Evaluate the constant (if necessary) and return it.
+  dynamic get value => _value ??= _materialize();
+
+  /// Find the constructor referred to by [entityRef] and return a function
+  /// which may be used to invoke it.
+  _Constructor _findConstructor(EntityRef entityRef) {
+    // This method is not fully general; we only support the constructor
+    // invocations that we expect to find in LibraryInfo.
+    assert(entityRef.implicitFunctionTypeIndices.isEmpty);
+    assert(entityRef.paramReference == 0);
+    assert(entityRef.syntheticParams.isEmpty);
+    assert(entityRef.syntheticReturnType == null);
+    assert(entityRef.typeArguments.isEmpty);
+    var reference = context.references[entityRef.reference];
+    assert(reference.prefixReference == 0);
+    switch (reference.name) {
+      case 'LibraryInfo':
+        return (dynamic positional(int i, [dynamic defaultValue]),
+                dynamic named(String name, [dynamic defaultValue])) =>
+            new LibraryInfo(positional(0),
+                categories: named('categories', ''),
+                dart2jsPath: named('dart2jsPath'),
+                dart2jsPatchPath: named('dart2jsPatchPath'),
+                implementation: named('implementation', false),
+                documented: named('documented', true),
+                maturity: named('maturity', Maturity.UNSPECIFIED),
+                platforms: named('platforms', DART2JS_PLATFORM | VM_PLATFORM));
+      case 'Maturity':
+        return (dynamic positional(int i, [dynamic defaultValue]),
+                dynamic named(String name, [dynamic defaultValue])) =>
+            new Maturity(positional(0), positional(1), positional(2));
+      default:
+        throw new UnimplementedError(
+            'Unexpected constructor reference: ${reference.name}');
+    }
+  }
+
+  /// Compute the value referred to by [entityRef].
+  dynamic _findReference(EntityRef entityRef) {
+    // This method is not fully general; we only support the references that we
+    // expect to find in LibraryInfo.
+    assert(entityRef.implicitFunctionTypeIndices.isEmpty);
+    assert(entityRef.paramReference == 0);
+    assert(entityRef.syntheticParams.isEmpty);
+    assert(entityRef.syntheticReturnType == null);
+    assert(entityRef.typeArguments.isEmpty);
+    var reference = context.references[entityRef.reference];
+    if (reference.prefixReference == 0) {
+      return context.topLevelConstants[reference.name].value;
+    } else {
+      assert(reference.prefixReference != 0);
+      var prefixReference = context.references[reference.prefixReference];
+      assert(prefixReference.name == 'Maturity');
+      assert(prefixReference.prefixReference == 0);
+      return context.maturityConstants[reference.name].value;
+    }
+  }
+
+  /// Compute the value of the constant.
+  dynamic _materialize() {
+    var stack = [];
+    var stringIndex = 0;
+    var intIndex = 0;
+    var referenceIndex = 0;
+    List popItems(int count) {
+      var items = stack.sublist(stack.length - count, stack.length);
+      stack.length -= count;
+      return items;
+    }
+
+    for (var operation in expr.operations) {
+      switch (operation) {
+        case UnlinkedExprOperation.pushString:
+          stack.add(expr.strings[stringIndex++]);
+          break;
+        case UnlinkedExprOperation.invokeConstructor:
+          var namedArgumentList = popItems(expr.ints[intIndex++]);
+          var namedArguments = <String, dynamic>{};
+          for (var namedArgument in namedArgumentList) {
+            namedArguments[expr.strings[stringIndex++]] = namedArgument;
+          }
+          var positionalArguments = popItems(expr.ints[intIndex++]);
+          stack.add(_findConstructor(expr.references[referenceIndex++])(
+              (i, [defaultValue]) => i < positionalArguments.length
+                  ? positionalArguments[i]
+                  : defaultValue,
+              (name, [defaultValue]) => namedArguments.containsKey(name)
+                  ? namedArguments[name]
+                  : defaultValue));
+          break;
+        case UnlinkedExprOperation.makeUntypedMap:
+          var map = {};
+          var numKeyValuePairs = expr.ints[intIndex++];
+          var keyValueList = popItems(numKeyValuePairs * 2);
+          for (var i = 0; i < numKeyValuePairs; i++) {
+            map[keyValueList[2 * i]] = keyValueList[2 * i + 1];
+          }
+          stack.add(map);
+          break;
+        case UnlinkedExprOperation.pushReference:
+          stack.add(_findReference(expr.references[referenceIndex++]));
+          break;
+        case UnlinkedExprOperation.pushInt:
+          stack.add(expr.ints[intIndex++]);
+          break;
+        case UnlinkedExprOperation.pushFalse:
+          stack.add(false);
+          break;
+        case UnlinkedExprOperation.pushTrue:
+          stack.add(true);
+          break;
+        case UnlinkedExprOperation.bitOr:
+          var y = stack.removeLast();
+          var x = stack.removeLast();
+          stack.add(x | y);
+          break;
+        default:
+          throw new UnimplementedError(
+              'Unexpected expression in libraries.dart: $operation');
+      }
+    }
+    assert(stringIndex == expr.strings.length);
+    assert(intIndex == expr.ints.length);
+    assert(referenceIndex == expr.references.length);
+    assert(stack.length == 1);
+    if (stack[0] == null) {
+      throw new StateError('Unexpected null constant in libraries.dart');
+    }
+    return stack[0];
+  }
+}
diff --git a/pub/front_end/lib/src/scanner/errors.dart b/pub/front_end/lib/src/scanner/errors.dart
index 4688ccd..bcf0c56 100644
--- a/pub/front_end/lib/src/scanner/errors.dart
+++ b/pub/front_end/lib/src/scanner/errors.dart
@@ -2,307 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-import 'package:analyzer/error/error.dart'
-    show errorCodeValues, errorCodeByUniqueName;
-
-/**
- * An error code associated with an [AnalysisError].
- *
- * Generally, we want to provide messages that consist of three sentences. From
- * the user's perspective these sentences should explain:
- *
- * 1. what is wrong,
- * 2. why is it wrong, and
- * 3. how do I fix it.
- *
- * However, we combine the first two in the [message] and the last in the
- * [correction].
- *
- * When composing messages (including correction messages) keep the following
- * guidelines in mind.
- *
- * 1. The message should be a complete sentence starting with an uppercase
- * letter, and ending with a period.
- *
- * 2. Reserved words and embedded identifiers should be in single quotes, so
- * prefer double quotes for the complete message. For example,
- * ```
- * "The class '{0}' can't use 'super'."
- * ```
- * Notice that the word 'class' in the preceding message is not quoted as it
- * refers to the concept 'class', not the reserved word. On the other hand,
- * 'super' refers to the reserved word. Do not quote 'null' and numeric literals.
- *
- * 3. Do not try to compose messages, as it can make translating them hard.
- *
- * 4. Try to keep the error messages short, but informative.
- *
- * 5. Use simple words and terminology, assume the reader of the message doesn't
- * have an advanced degree in math, and that English is not the reader's native
- * language. Do not assume any formal computer science training. For example, do
- * not use Latin abbreviations (prefer "that is" over "i.e.", and "for example"
- * over "e.g."). Also avoid phrases such as "if and only if" and "iff"; that
- * level of precision is unnecessary.
- *
- * 6. Prefer contractions when they are in common use, for example, prefer
- * "can't" over "cannot". Using "cannot", "must not", "shall not", etc. is
- * off-putting to people new to programming.
- *
- * 7. Use common terminology, preferably from the Dart Language Specification.
- * This increases the user's chance of finding a good explanation on the web.
- *
- * 8. Do not try to be cute or funny. It is extremely frustrating to work on a
- * product that crashes with a "tongue-in-cheek" message, especially if you did
- * not want to use this product to begin with.
- *
- * 9. Do not lie, that is, do not write error messages containing phrases like
- * "can't happen".  If the user ever saw this message, it would be a lie. Prefer
- * messages like: "Internal error: This function should not be called when 'x'
- * is null.".
- *
- * 10. Prefer to not use the imperative tone. That is, the message should not
- * sound accusing or like it is ordering the user around. The computer should
- * describe the problem, not criticize the user for violating the specification.
- */
-abstract class ErrorCode {
-  /**
-   * Engine error code values.
-   */
-  @deprecated
-  static const List<ErrorCode> values = errorCodeValues;
-
-  /**
-   * An empty list of error codes.
-   */
-  @deprecated
-  static const List<ErrorCode> EMPTY_LIST = const <ErrorCode>[];
-
-  /**
-   * The name of the error code.
-   */
-  final String name;
-
-  /**
-   * The template used to create the message to be displayed for this error. The
-   * message should indicate what is wrong and why it is wrong.
-   */
-  final String message;
-
-  /**
-   * The template used to create the correction to be displayed for this error,
-   * or `null` if there is no correction information for this error. The
-   * correction should indicate how the user can fix the error.
-   */
-  final String correction;
-
-  /**
-   * Initialize a newly created error code to have the given [name]. The message
-   * associated with the error will be created from the given [message]
-   * template. The correction associated with the error will be created from the
-   * given [correction] template.
-   */
-  const ErrorCode(this.name, this.message, [this.correction]);
-
-  /**
-   * The severity of the error.
-   */
-  ErrorSeverity get errorSeverity;
-
-  /**
-   * The type of the error.
-   */
-  ErrorType get type;
-
-  /**
-   * The unique name of this error code.
-   */
-  String get uniqueName => "$runtimeType.$name";
-
-  @override
-  String toString() => uniqueName;
-
-  /**
-   * Return the [ErrorCode] with the given [uniqueName], or `null` if not
-   * found.
-   */
-  @deprecated
-  static ErrorCode byUniqueName(String uniqueName) =>
-      errorCodeByUniqueName(uniqueName);
-}
-
-/**
- * The severity of an [ErrorCode].
- */
-class ErrorSeverity implements Comparable<ErrorSeverity> {
-  /**
-   * The severity representing a non-error. This is never used for any error
-   * code, but is useful for clients.
-   */
-  static const ErrorSeverity NONE = const ErrorSeverity('NONE', 0, " ", "none");
-
-  /**
-   * The severity representing an informational level analysis issue.
-   */
-  static const ErrorSeverity INFO = const ErrorSeverity('INFO', 1, "I", "info");
-
-  /**
-   * The severity representing a warning. Warnings can become errors if the `-Werror` command
-   * line flag is specified.
-   */
-  static const ErrorSeverity WARNING =
-      const ErrorSeverity('WARNING', 2, "W", "warning");
-
-  /**
-   * The severity representing an error.
-   */
-  static const ErrorSeverity ERROR =
-      const ErrorSeverity('ERROR', 3, "E", "error");
-
-  static const List<ErrorSeverity> values = const [NONE, INFO, WARNING, ERROR];
-
-  /**
-   * The name of this error code.
-   */
-  final String name;
-
-  /**
-   * The ordinal value of the error code.
-   */
-  final int ordinal;
-
-  /**
-   * The name of the severity used when producing machine output.
-   */
-  final String machineCode;
-
-  /**
-   * The name of the severity used when producing readable output.
-   */
-  final String displayName;
-
-  /**
-   * Initialize a newly created severity with the given names.
-   */
-  const ErrorSeverity(
-      this.name, this.ordinal, this.machineCode, this.displayName);
-
-  @override
-  int get hashCode => ordinal;
-
-  @override
-  int compareTo(ErrorSeverity other) => ordinal - other.ordinal;
-
-  /**
-   * Return the severity constant that represents the greatest severity.
-   */
-  ErrorSeverity max(ErrorSeverity severity) =>
-      this.ordinal >= severity.ordinal ? this : severity;
-
-  @override
-  String toString() => name;
-}
-
-/**
- * The type of an [ErrorCode].
- */
-class ErrorType implements Comparable<ErrorType> {
-  /**
-   * Task (todo) comments in user code.
-   */
-  static const ErrorType TODO = const ErrorType('TODO', 0, ErrorSeverity.INFO);
-
-  /**
-   * Extra analysis run over the code to follow best practices, which are not in
-   * the Dart Language Specification.
-   */
-  static const ErrorType HINT = const ErrorType('HINT', 1, ErrorSeverity.INFO);
-
-  /**
-   * Compile-time errors are errors that preclude execution. A compile time
-   * error must be reported by a Dart compiler before the erroneous code is
-   * executed.
-   */
-  static const ErrorType COMPILE_TIME_ERROR =
-      const ErrorType('COMPILE_TIME_ERROR', 2, ErrorSeverity.ERROR);
-
-  /**
-   * Checked mode compile-time errors are errors that preclude execution in
-   * checked mode.
-   */
-  static const ErrorType CHECKED_MODE_COMPILE_TIME_ERROR = const ErrorType(
-      'CHECKED_MODE_COMPILE_TIME_ERROR', 3, ErrorSeverity.ERROR);
-
-  /**
-   * Static warnings are those warnings reported by the static checker. They
-   * have no effect on execution. Static warnings must be provided by Dart
-   * compilers used during development.
-   */
-  static const ErrorType STATIC_WARNING =
-      const ErrorType('STATIC_WARNING', 4, ErrorSeverity.WARNING);
-
-  /**
-   * Many, but not all, static warnings relate to types, in which case they are
-   * known as static type warnings.
-   */
-  static const ErrorType STATIC_TYPE_WARNING =
-      const ErrorType('STATIC_TYPE_WARNING', 5, ErrorSeverity.WARNING);
-
-  /**
-   * Syntactic errors are errors produced as a result of input that does not
-   * conform to the grammar.
-   */
-  static const ErrorType SYNTACTIC_ERROR =
-      const ErrorType('SYNTACTIC_ERROR', 6, ErrorSeverity.ERROR);
-
-  /**
-   * Lint warnings describe style and best practice recommendations that can be
-   * used to formalize a project's style guidelines.
-   */
-  static const ErrorType LINT = const ErrorType('LINT', 7, ErrorSeverity.INFO);
-
-  static const List<ErrorType> values = const [
-    TODO,
-    HINT,
-    COMPILE_TIME_ERROR,
-    CHECKED_MODE_COMPILE_TIME_ERROR,
-    STATIC_WARNING,
-    STATIC_TYPE_WARNING,
-    SYNTACTIC_ERROR,
-    LINT
-  ];
-
-  /**
-   * The name of this error type.
-   */
-  final String name;
-
-  /**
-   * The ordinal value of the error type.
-   */
-  final int ordinal;
-
-  /**
-   * The severity of this type of error.
-   */
-  final ErrorSeverity severity;
-
-  /**
-   * Initialize a newly created error type to have the given [name] and
-   * [severity].
-   */
-  const ErrorType(this.name, this.ordinal, this.severity);
-
-  String get displayName => name.toLowerCase().replaceAll('_', ' ');
-
-  @override
-  int get hashCode => ordinal;
-
-  @override
-  int compareTo(ErrorType other) => ordinal - other.ordinal;
-
-  @override
-  String toString() => name;
-}
+import 'package:front_end/src/base/errors.dart';
 
 /**
  * The error codes used for errors detected by the scanner.
diff --git a/pub/front_end/lib/src/scanner/reader.dart b/pub/front_end/lib/src/scanner/reader.dart
index ee9d6c0..b079139 100644
--- a/pub/front_end/lib/src/scanner/reader.dart
+++ b/pub/front_end/lib/src/scanner/reader.dart
@@ -42,3 +42,92 @@
    */
   int peek();
 }
+
+/**
+ * A [CharacterReader] that reads characters from a character sequence.
+ */
+class CharSequenceReader implements CharacterReader {
+  /**
+   * The sequence from which characters will be read.
+   */
+  final String _sequence;
+
+  /**
+   * The number of characters in the string.
+   */
+  int _stringLength;
+
+  /**
+   * The index, relative to the string, of the next character to be read.
+   */
+  int _charOffset;
+
+  /**
+   * Initialize a newly created reader to read the characters in the given
+   * [_sequence].
+   */
+  CharSequenceReader(this._sequence) {
+    this._stringLength = _sequence.length;
+    this._charOffset = 0;
+  }
+
+  @override
+  int get offset => _charOffset - 1;
+
+  @override
+  void set offset(int offset) {
+    _charOffset = offset + 1;
+  }
+
+  @override
+  int advance() {
+    if (_charOffset >= _stringLength) {
+      return -1;
+    }
+    return _sequence.codeUnitAt(_charOffset++);
+  }
+
+  @override
+  String getString(int start, int endDelta) =>
+      _sequence.substring(start, _charOffset + endDelta);
+
+  @override
+  int peek() {
+    if (_charOffset >= _stringLength) {
+      return -1;
+    }
+    return _sequence.codeUnitAt(_charOffset);
+  }
+}
+
+/**
+ * A [CharacterReader] that reads characters from a character sequence, but adds
+ * a delta when reporting the current character offset so that the character
+ * sequence can be a subsequence from a larger sequence.
+ */
+class SubSequenceReader extends CharSequenceReader {
+  /**
+   * The offset from the beginning of the file to the beginning of the source
+   * being scanned.
+   */
+  final int _offsetDelta;
+
+  /**
+   * Initialize a newly created reader to read the characters in the given
+   * [sequence]. The [_offsetDelta] is the offset from the beginning of the file
+   * to the beginning of the source being scanned
+   */
+  SubSequenceReader(String sequence, this._offsetDelta) : super(sequence);
+
+  @override
+  int get offset => _offsetDelta + super.offset;
+
+  @override
+  void set offset(int offset) {
+    super.offset = offset - _offsetDelta;
+  }
+
+  @override
+  String getString(int start, int endDelta) =>
+      super.getString(start - _offsetDelta, endDelta);
+}
diff --git a/pub/front_end/lib/src/scanner/token.dart b/pub/front_end/lib/src/scanner/token.dart
index 10d4924..abd0194 100644
--- a/pub/front_end/lib/src/scanner/token.dart
+++ b/pub/front_end/lib/src/scanner/token.dart
@@ -6,11 +6,10 @@
  * Defines the tokens that are produced by the scanner, used by the parser, and
  * referenced from the [AST structure](ast.dart).
  */
-
 import 'dart:collection';
 
+import 'package:front_end/src/base/syntactic_entity.dart';
 import 'package:front_end/src/scanner/string_utilities.dart';
-import 'package:front_end/src/scanner/syntactic_entity.dart';
 
 /**
  * The opening half of a grouping pair of tokens. This is used for curly
@@ -167,6 +166,9 @@
 
   static const Keyword CONTINUE = const Keyword._('CONTINUE', "continue");
 
+  static const Keyword COVARIANT =
+      const Keyword._('COVARIANT', "covariant", true);
+
   static const Keyword DEFAULT = const Keyword._('DEFAULT', "default");
 
   static const Keyword DEFERRED = const Keyword._('DEFERRED', "deferred", true);
@@ -258,6 +260,7 @@
     CLASS,
     CONST,
     CONTINUE,
+    COVARIANT,
     DEFAULT,
     DEFERRED,
     DO,
diff --git a/pub/front_end/pubspec.yaml b/pub/front_end/pubspec.yaml
index 8b75e23..5f15860 100644
--- a/pub/front_end/pubspec.yaml
+++ b/pub/front_end/pubspec.yaml
@@ -1,18 +1,18 @@
 name: front_end
-version: 0.1.0-alpha.0
+version: 0.1.0-alpha.1
 author: Dart Team <misc@dartlang.org>
 description: Front end for compilation of Dart code.
 homepage: https://github.com/dart-lang/sdk/tree/master/pkg/front_end
 environment:
   sdk: '>=1.12.0 <2.0.0'
 dependencies:
-  analyzer: '^0.29.0'
+  analyzer: 0.30.0-alpha.1
   path: '^1.3.9'
   source_span: '^1.2.3'
 dev_dependencies:
   # TODO(sigmund): update to a version constraint once we roll the latest kernel
   # to the repo.
-  kernel: {path: ../../third_party/pkg/kernel}
+  kernel: {path: ../../pkg/kernel}
   package_config: '^1.0.0'
   test: ^0.12.0
   test_reflective_loader: ^0.1.0
diff --git a/pub/front_end/tool/example.dart b/pub/front_end/tool/example.dart
new file mode 100644
index 0000000..d81f437
--- /dev/null
+++ b/pub/front_end/tool/example.dart
@@ -0,0 +1,29 @@
+import 'dart:async';
+
+import 'package:front_end/kernel_generator.dart';
+import 'package:front_end/compiler_options.dart';
+import 'package:kernel/binary/ast_to_binary.dart';
+import 'package:kernel/kernel.dart' show Program;
+
+Future dumpToSink(Program program, StreamSink<List<int>> sink) {
+  new BinaryPrinter(sink).writeProgramFile(program);
+  return sink.close();
+}
+
+Future kernelToSink(Uri entry, StreamSink<List<int>> sink) async {
+  var program = await kernelForProgram(
+      entry,
+      new CompilerOptions()
+        ..sdkRoot = new Uri.file('sdk')
+        ..packagesFileUri = new Uri.file('.packages')
+        ..onError = (e) => print(e.message));
+
+  await dumpToSink(program, sink);
+}
+
+main(args) async {
+  kernelToSink(
+      Uri.base.resolve(args[0]),
+      // TODO(sigmund,hausner): define memory type where to dump binary data.
+      new StreamController<List<int>>.broadcast().sink);
+}
diff --git a/pub/front_end/tool/perf.dart b/pub/front_end/tool/perf.dart
index ec306ca..7c4e4cd 100644
--- a/pub/front_end/tool/perf.dart
+++ b/pub/front_end/tool/perf.dart
@@ -6,171 +6,91 @@
 library front_end.tool.perf;
 
 import 'dart:async';
-import 'dart:io' show exit, stderr;
+import 'dart:io' show exit;
 
 import 'package:analyzer/dart/ast/ast.dart';
-import 'package:analyzer/dart/ast/token.dart';
 import 'package:analyzer/error/listener.dart';
 import 'package:analyzer/file_system/file_system.dart' show ResourceUriResolver;
 import 'package:analyzer/file_system/physical_file_system.dart'
     show PhysicalResourceProvider;
 import 'package:analyzer/source/package_map_resolver.dart';
 import 'package:analyzer/src/context/builder.dart';
-import 'package:analyzer/src/dart/scanner/reader.dart';
-import 'package:analyzer/src/dart/scanner/scanner.dart';
 import 'package:analyzer/src/dart/sdk/sdk.dart' show FolderBasedDartSdk;
 import 'package:analyzer/src/generated/parser.dart';
 import 'package:analyzer/src/generated/source.dart';
 import 'package:analyzer/src/generated/source_io.dart';
-import 'package:kernel/analyzer/loader.dart';
-import 'package:kernel/kernel.dart';
+import 'package:analyzer/src/summary/format.dart';
+import 'package:analyzer/src/summary/idl.dart';
+import 'package:analyzer/src/summary/link.dart';
+import 'package:analyzer/src/summary/summarize_ast.dart';
+import 'package:front_end/compiler_options.dart';
+import 'package:front_end/kernel_generator.dart';
+import 'package:front_end/src/scanner/reader.dart';
+import 'package:front_end/src/scanner/scanner.dart';
+import 'package:front_end/src/scanner/token.dart';
+import 'package:kernel/kernel.dart' hide Source;
 import 'package:package_config/discovery.dart';
 
-/// Cumulative total number of chars scanned.
-int scanTotalChars = 0;
-
-/// Cumulative time spent scanning.
-Stopwatch scanTimer = new Stopwatch();
-
-/// Factory to load and resolve app, packages, and sdk sources.
-SourceFactory sources;
-
 main(List<String> args) async {
   // TODO(sigmund): provide sdk folder as well.
   if (args.length < 2) {
     print('usage: perf.dart <bench-id> <entry.dart>');
     exit(1);
   }
-  var totalTimer = new Stopwatch()..start();
 
   var bench = args[0];
   var entryUri = Uri.base.resolve(args[1]);
 
   await setup(entryUri);
 
+  Set<Source> files = scanReachableFiles(entryUri);
   var handlers = {
-    'scan': () async {
-      Set<Source> files = scanReachableFiles(entryUri);
-      // TODO(sigmund): replace the warmup with instrumented snapshots.
-      for (int i = 0; i < 10; i++) scanFiles(files);
-    },
-    'parse': () async {
-      Set<Source> files = scanReachableFiles(entryUri);
-      // TODO(sigmund): replace the warmup with instrumented snapshots.
-      for (int i = 0; i < 10; i++) parseFiles(files);
-    },
+    'scan': () async => scanFiles(files),
+    'parse': () async => parseFiles(files),
     'kernel_gen_e2e': () async {
-      // TODO(sigmund): remove. This is used to compute the input size, we
-      // should extract input size from frontend instead.
-      scanReachableFiles(entryUri);
-      // TODO(sigmund): replace this warmup. Note that for very large programs,
-      // the GC pressure on the VM seems to make this worse with time (maybe we
-      // are leaking memory?). That's why we run it twice and not 10 times.
-      for (int i = 0; i < 2; i++) await generateKernel(entryUri);
+      await generateKernel(entryUri, useSdkSummary: false);
     },
+    'kernel_gen_e2e_sum': () async {
+      await generateKernel(entryUri, useSdkSummary: true, compileSdk: false);
+    },
+    'unlinked_summarize': () async => summarize(files),
+    'unlinked_summarize_from_sources': () async => summarize(files),
+    'prelinked_summarize': () async => summarize(files, prelink: true),
+    'linked_summarize': () async => summarize(files, link: true),
   };
 
   var handler = handlers[bench];
   if (handler == null) {
-    // TODO(sigmund): implement the remaining benchmarks.
     print('unsupported bench-id: $bench. Please specify one of the following: '
         '${handlers.keys.join(", ")}');
     exit(1);
   }
-  await handler();
 
-  totalTimer.stop();
-  report("total", totalTimer.elapsedMicroseconds);
-}
-
-/// Sets up analyzer to be able to load and resolve app, packages, and sdk
-/// sources.
-Future setup(Uri entryUri) async {
-  var provider = PhysicalResourceProvider.INSTANCE;
-  var packageMap = new ContextBuilder(provider, null, null)
-      .convertPackagesToMap(await findPackages(entryUri));
-  sources = new SourceFactory([
-    new ResourceUriResolver(provider),
-    new PackageMapUriResolver(provider, packageMap),
-    new DartUriResolver(
-        new FolderBasedDartSdk(provider, provider.getFolder("sdk"))),
-  ]);
-}
-
-/// Load and scans all files we need to process: files reachable from the
-/// entrypoint and all core libraries automatically included by the VM.
-Set<Source> scanReachableFiles(Uri entryUri) {
-  var files = new Set<Source>();
-  var loadTimer = new Stopwatch()..start();
-  collectSources(sources.forUri2(entryUri), files);
-
-  var libs = [
-    "dart:async",
-    "dart:collection",
-    "dart:convert",
-    "dart:core",
-    "dart:developer",
-    "dart:_internal",
-    "dart:isolate",
-    "dart:math",
-    "dart:mirrors",
-    "dart:typed_data",
-    "dart:io"
-  ];
-
-  for (var lib in libs) {
-    collectSources(sources.forUri(lib), files);
+  // TODO(sigmund): replace the warmup with instrumented snapshots.
+  int iterations = bench.contains('kernel_gen') ? 2 : 10;
+  for (int i = 0; i < iterations; i++) {
+    var totalTimer = new Stopwatch()..start();
+    print('== iteration $i');
+    await handler();
+    totalTimer.stop();
+    report('total', totalTimer.elapsedMicroseconds);
   }
-
-  loadTimer.stop();
-
-  print('input size: ${scanTotalChars} chars');
-  var loadTime = loadTimer.elapsedMicroseconds - scanTimer.elapsedMicroseconds;
-  report("load", loadTime);
-  report("scan", scanTimer.elapsedMicroseconds);
-  return files;
 }
 
-/// Scans every file in [files] and reports the time spent doing so.
-void scanFiles(Set<Source> files) {
-  // The code below will record again how many chars are scanned and how long it
-  // takes to scan them, even though we already did so in [scanReachableFiles].
-  // Recording and reporting this twice is unnecessary, but we do so for now to
-  // validate that the results are consistent.
-  scanTimer = new Stopwatch();
-  var old = scanTotalChars;
-  scanTotalChars = 0;
-  for (var source in files) {
-    tokenize(source);
-  }
+/// Cumulative time spent parsing.
+Stopwatch parseTimer = new Stopwatch();
 
-  // Report size and scanning time again. See discussion above.
-  if (old != scanTotalChars) print('input size changed? ${old} chars');
-  report("scan", scanTimer.elapsedMicroseconds);
-}
+/// Cumulative time spent building unlinked summaries.
+Stopwatch unlinkedSummarizeTimer = new Stopwatch();
 
-/// Parses every file in [files] and reports the time spent doing so.
-void parseFiles(Set<Source> files) {
-  // The code below will record again how many chars are scanned and how long it
-  // takes to scan them, even though we already did so in [scanReachableFiles].
-  // Recording and reporting this twice is unnecessary, but we do so for now to
-  // validate that the results are consistent.
-  scanTimer = new Stopwatch();
-  var old = scanTotalChars;
-  scanTotalChars = 0;
-  var parseTimer = new Stopwatch()..start();
-  for (var source in files) {
-    parseFull(source);
-  }
-  parseTimer.stop();
+/// Cumulative time spent scanning.
+Stopwatch scanTimer = new Stopwatch();
 
-  // Report size and scanning time again. See discussion above.
-  if (old != scanTotalChars) print('input size changed? ${old} chars');
-  report("scan", scanTimer.elapsedMicroseconds);
+/// Size of all sources.
+int inputSize = 0;
 
-  var pTime = parseTimer.elapsedMicroseconds - scanTimer.elapsedMicroseconds;
-  report("parse", pTime);
-}
+/// Factory to load and resolve app, packages, and sdk sources.
+SourceFactory sources;
 
 /// Add to [files] all sources reachable from [start].
 void collectSources(Source start, Set<Source> files) {
@@ -184,6 +104,87 @@
   }
 }
 
+Future<Program> generateKernel(Uri entryUri,
+    {bool useSdkSummary: false, bool compileSdk: true}) async {
+  // TODO(sigmund): this is here only to compute the input size,
+  // we should extract the input size from the frontend instead.
+  scanReachableFiles(entryUri);
+
+  var dartkTimer = new Stopwatch()..start();
+  // TODO(sigmund): add a constructor with named args to compiler options.
+  var options = new CompilerOptions()
+    ..strongMode = false
+    ..compileSdk = compileSdk
+    ..packagesFileUri = new Uri.file('.packages')
+    ..onError = ((e) => print('${e.message}'));
+  if (useSdkSummary) {
+    // TODO(sigmund): adjust path based on the benchmark runner architecture.
+    // Possibly let the runner make the file available at an architecture
+    // independent location.
+    options.sdkSummary =
+        new Uri.file('out/ReleaseX64/dart-sdk/lib/_internal/spec.sum');
+  } else {
+    options.sdkRoot = new Uri.file('sdk');
+  }
+  Program program = await kernelForProgram(entryUri, options);
+  dartkTimer.stop();
+  var suffix = useSdkSummary ? '_sum' : '';
+  report('kernel_gen_e2e${suffix}', dartkTimer.elapsedMicroseconds);
+  return program;
+}
+
+/// Generates unlinkmed summaries for all files in [files], and returns them in
+/// an [_UnlinkedSummaries] container.
+_UnlinkedSummaries generateUnlinkedSummaries(Set<Source> files) {
+  var unlinkedSummaries = new _UnlinkedSummaries();
+  for (var source in files) {
+    unlinkedSummaries.summariesByUri[source.uri.toString()] =
+        unlinkedSummarize(source);
+  }
+  return unlinkedSummaries;
+}
+
+/// Generates unlinked summaries for every file in [files] and, if requested via
+/// [prelink] or [link], generates the pre-linked and linked summaries as well.
+///
+/// This function also prints a report of the time spent on each action.
+void summarize(Set<Source> files, {bool prelink: false, bool link: false}) {
+  scanTimer = new Stopwatch();
+  parseTimer = new Stopwatch();
+  unlinkedSummarizeTimer = new Stopwatch();
+  var unlinkedSummaries = generateUnlinkedSummaries(files);
+  report('scan', scanTimer.elapsedMicroseconds);
+  report('parse', parseTimer.elapsedMicroseconds);
+  report('unlinked_summarize', unlinkedSummarizeTimer.elapsedMicroseconds);
+  report(
+      'unlinked_summarize_from_sources',
+      unlinkedSummarizeTimer.elapsedMicroseconds +
+          parseTimer.elapsedMicroseconds +
+          scanTimer.elapsedMicroseconds);
+
+  if (prelink || link) {
+    var prelinkTimer = new Stopwatch()..start();
+    var prelinkedLibraries = prelinkSummaries(files, unlinkedSummaries);
+    prelinkTimer.stop();
+    report('prelinked_summarize', prelinkTimer.elapsedMicroseconds);
+
+    if (link) {
+      var linkTimer = new Stopwatch()..start();
+      LinkedLibrary getDependency(String uri) {
+        // getDependency should never be called because all dependencies are
+        // present in [prelinkedLibraries].
+        print('Warning: getDependency called for: $uri');
+        return null;
+      }
+
+      relink(prelinkedLibraries, getDependency, unlinkedSummaries.getUnit,
+          true /*strong*/);
+      linkTimer.stop();
+      report('linked_summarize', linkTimer.elapsedMicroseconds);
+    }
+  }
+}
+
 /// Uses the diet-parser to parse only directives in [source].
 CompilationUnit parseDirectives(Source source) {
   var token = tokenize(source);
@@ -191,55 +192,158 @@
   return parser.parseDirectives(token);
 }
 
+/// Parses every file in [files] and reports the time spent doing so.
+void parseFiles(Set<Source> files) {
+  scanTimer = new Stopwatch();
+  parseTimer = new Stopwatch();
+  for (var source in files) {
+    parseFull(source);
+  }
+
+  report('scan', scanTimer.elapsedMicroseconds);
+  report('parse', parseTimer.elapsedMicroseconds);
+}
+
 /// Parse the full body of [source] and return it's compilation unit.
 CompilationUnit parseFull(Source source) {
   var token = tokenize(source);
+  parseTimer.start();
   var parser = new Parser(source, AnalysisErrorListener.NULL_LISTENER);
-  return parser.parseCompilationUnit(token);
+  var unit = parser.parseCompilationUnit(token);
+  parseTimer.stop();
+  return unit;
+}
+
+/// Prelinks all the summaries for [files], using [unlinkedSummaries] to obtain
+/// their unlinked summaries.
+///
+/// The return value is suitable for passing to the summary linker.
+Map<String, LinkedLibraryBuilder> prelinkSummaries(
+    Set<Source> files, _UnlinkedSummaries unlinkedSummaries) {
+  Set<String> libraryUris = files.map((source) => '${source.uri}').toSet();
+
+  String getDeclaredVariable(String s) => null;
+  var prelinkedLibraries =
+      setupForLink(libraryUris, unlinkedSummaries.getUnit, getDeclaredVariable);
+  return prelinkedLibraries;
+}
+
+/// Report that metric [name] took [time] micro-seconds to process
+/// [inputSize] characters.
+void report(String name, int time) {
+  var sb = new StringBuffer();
+  var padding = ' ' * (20 - name.length);
+  sb.write('$name:$padding $time us, ${time ~/ 1000} ms');
+  var invSpeed = (time * 1000 / inputSize).toStringAsFixed(2);
+  sb.write(', $invSpeed ns/char');
+  print('$sb');
+}
+
+/// Scans every file in [files] and reports the time spent doing so.
+void scanFiles(Set<Source> files) {
+  // `tokenize` records how many chars are scanned and how long it takes to scan
+  // them. As this function is called repeatedly when running as a benchmark, we
+  // make sure to clear the data and compute it again every time.
+  scanTimer = new Stopwatch();
+  for (var source in files) {
+    tokenize(source);
+  }
+
+  report('scan', scanTimer.elapsedMicroseconds);
+}
+
+/// Load and scans all files we need to process: files reachable from the
+/// entrypoint and all core libraries automatically included by the VM.
+Set<Source> scanReachableFiles(Uri entryUri) {
+  var files = new Set<Source>();
+  var loadTimer = new Stopwatch()..start();
+  scanTimer = new Stopwatch();
+  collectSources(sources.forUri2(entryUri), files);
+
+  var libs = [
+    'dart:async',
+    'dart:collection',
+    'dart:convert',
+    'dart:core',
+    'dart:developer',
+    'dart:_internal',
+    'dart:isolate',
+    'dart:math',
+    'dart:mirrors',
+    'dart:typed_data',
+    'dart:io'
+  ];
+
+  for (var lib in libs) {
+    collectSources(sources.forUri(lib), files);
+  }
+
+  loadTimer.stop();
+
+  inputSize = 0;
+  for (var s in files) inputSize += s.contents.data.length;
+  print('input size: ${inputSize} chars');
+  var loadTime = loadTimer.elapsedMicroseconds - scanTimer.elapsedMicroseconds;
+  report('load', loadTime);
+  report('scan', scanTimer.elapsedMicroseconds);
+  return files;
+}
+
+/// Sets up analyzer to be able to load and resolve app, packages, and sdk
+/// sources.
+Future setup(Uri entryUri) async {
+  var provider = PhysicalResourceProvider.INSTANCE;
+  var packageMap = new ContextBuilder(provider, null, null)
+      .convertPackagesToMap(await findPackages(entryUri));
+  sources = new SourceFactory([
+    new ResourceUriResolver(provider),
+    new PackageMapUriResolver(provider, packageMap),
+    new DartUriResolver(
+        new FolderBasedDartSdk(provider, provider.getFolder('sdk'))),
+  ]);
 }
 
 /// Scan [source] and return the first token produced by the scanner.
 Token tokenize(Source source) {
   scanTimer.start();
-  var contents = source.contents.data;
-  scanTotalChars += contents.length;
   // TODO(sigmund): is there a way to scan from a random-access-file without
   // first converting to String?
-  var scanner = new Scanner(source, new CharSequenceReader(contents),
-      AnalysisErrorListener.NULL_LISTENER)..preserveComments = false;
+  var scanner = new _Scanner(source.contents.data);
   var token = scanner.tokenize();
   scanTimer.stop();
   return token;
 }
 
-/// Report that metric [name] took [time] micro-seconds to process
-/// [scanTotalChars] characters.
-void report(String name, int time) {
-  var sb = new StringBuffer();
-  sb.write('$name: $time us, ${time ~/ 1000} ms');
-  sb.write(', ${scanTotalChars * 1000 ~/ time} chars/ms');
-  print('$sb');
+UnlinkedUnitBuilder unlinkedSummarize(Source source) {
+  var unit = parseFull(source);
+  unlinkedSummarizeTimer.start();
+  var unlinkedUnit = serializeAstUnlinked(unit);
+  unlinkedSummarizeTimer.stop();
+  return unlinkedUnit;
 }
 
-// TODO(sigmund): replace this once kernel is produced by the frontend directly.
-Future<Program> generateKernel(Uri entryUri) async {
-  var dartkTimer = new Stopwatch()..start();
-  var options = new DartOptions(strongMode: false, sdk: 'sdk');
-  var packages =
-      await createPackages(options.packagePath, discoveryPath: entryUri.path);
-  var repository = new Repository();
-  DartLoader loader = new DartLoader(repository, options, packages);
+/// Simple container for a mapping from URI string to an unlinked summary.
+class _UnlinkedSummaries {
+  final summariesByUri = <String, UnlinkedUnit>{};
 
-  Program program = loader.loadProgram(entryUri.path);
-  List errors = loader.errors;
-  if (errors.isNotEmpty) {
-    const int errorLimit = 100;
-    stderr.writeln(errors.take(errorLimit).join('\n'));
-    if (errors.length > errorLimit) {
-      stderr.writeln('[error] ${errors.length - errorLimit} errors not shown');
+  /// Get the unlinked summary for the given URI, and report a warning if it
+  /// can't be found.
+  UnlinkedUnit getUnit(String uri) {
+    var result = summariesByUri[uri];
+    if (result == null) {
+      print('Warning: no summary found for: $uri');
     }
+    return result;
   }
-  dartkTimer.stop();
-  report("kernel_gen_e2e", dartkTimer.elapsedMicroseconds);
-  return program;
+}
+
+class _Scanner extends Scanner {
+  _Scanner(String contents) : super(new CharSequenceReader(contents)) {
+    preserveComments = false;
+  }
+
+  @override
+  void reportError(errorCode, int offset, List<Object> arguments) {
+    // ignore errors.
+  }
 }
diff --git a/pub/front_end/tool/perf_test.dart b/pub/front_end/tool/perf_test.dart
index 5abc06f..66093ed 100644
--- a/pub/front_end/tool/perf_test.dart
+++ b/pub/front_end/tool/perf_test.dart
@@ -8,4 +8,4 @@
 
 import 'perf.dart' as m;
 
-main() => print('done ${m.scanTotalChars}');
+main() => print('done ${m.inputSize}');
diff --git a/pub/isolate/BUILD.gn b/pub/isolate/BUILD.gn
index f1eb5f8..d9fcfc4 100644
--- a/pub/isolate/BUILD.gn
+++ b/pub/isolate/BUILD.gn
@@ -1,4 +1,4 @@
-# This file is generated by importer.py for isolate-0.2.3
+# This file is generated by importer.py for isolate-1.0.0
 
 import("//build/dart/dart_package.gni")
 
diff --git a/pub/isolate/CHANGELOG.md b/pub/isolate/CHANGELOG.md
index cadcf76..f69a8aa 100644
--- a/pub/isolate/CHANGELOG.md
+++ b/pub/isolate/CHANGELOG.md
@@ -1,22 +1,26 @@
-###0.2.3
+## 1.0.0
+
+* Change to using `package:test` for testing.
+
+## 0.2.3
 
 * Fixed strong mode analysis errors.
 * Migrated tests to package:test.
 
-###0.2.2
+## 0.2.2
 
 * Made `Isolate.kill` parameter `priority` a named parameter.
 
-###0.2.1
+## 0.2.1
 
 * Fixed spelling in a number of doc comments and the README.
 
-###0.2.0
+## 0.2.0
 
 * Renamed library `isolaterunner.dart` to `isolate_runner.dart`.
 * Renamed library `loadbalancer.dart' to `load_balancer.dart`.
 
-###0.1.0
+## 0.1.0
 
 * Initial version
 * Adds IsolateRunner as a helper around Isolate.
diff --git a/pub/isolate/pubspec.yaml b/pub/isolate/pubspec.yaml
index f68a76e..ae9da40 100644
--- a/pub/isolate/pubspec.yaml
+++ b/pub/isolate/pubspec.yaml
@@ -1,5 +1,5 @@
 name: isolate
-version: 0.2.3
+version: 1.0.0
 author: Dart Team <misc@dartlang.org>
 description: Utility functions and classes related to the 'dart:isolate' library.
 homepage: https://github.com/dart-lang/isolate
diff --git a/pub/usage/.analysis_options b/pub/usage/.analysis_options
index c702eea..a10d4c5 100644
--- a/pub/usage/.analysis_options
+++ b/pub/usage/.analysis_options
@@ -1,7 +1,2 @@
 analyzer:
   strong-mode: true
-  language:
-    enableConditionalDirectives: true
-  exclude:
-    - example/flutter_example/**
-    - lib/src/usage_impl_flutter.dart
diff --git a/pub/usage/.gitignore b/pub/usage/.gitignore
index f8192d2..52f0c5b 100644
--- a/pub/usage/.gitignore
+++ b/pub/usage/.gitignore
@@ -1,8 +1,3 @@
-build/
-doc/api/
 .packages
-packages
-.buildlog
-pubspec.lock
-.settings/
 .pub/
+pubspec.lock
diff --git a/pub/usage/.project b/pub/usage/.project
deleted file mode 100644
index 5e76d1e..0000000
--- a/pub/usage/.project
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<projectDescription>
-	<name>usage</name>
-	<comment></comment>
-	<projects>
-	</projects>
-	<buildSpec>
-		<buildCommand>
-			<name>com.google.dart.tools.core.dartBuilder</name>
-			<arguments>
-			</arguments>
-		</buildCommand>
-	</buildSpec>
-	<natures>
-		<nature>com.google.dart.tools.core.dartNature</nature>
-	</natures>
-	<filteredResources>
-		<filter>
-			<id>1418770673943</id>
-			<name></name>
-			<type>30</type>
-			<matcher>
-				<id>com.google.dart.tools.core.packagesFolderMatcher</id>
-			</matcher>
-		</filter>
-	</filteredResources>
-</projectDescription>
diff --git a/pub/usage/.travis.yml b/pub/usage/.travis.yml
index 35def79..9e27d1f 100644
--- a/pub/usage/.travis.yml
+++ b/pub/usage/.travis.yml
@@ -1,11 +1,3 @@
 language: dart
-dart:
-  - dev
 sudo: false
-
-# before_install:
-#   - "export CHROME_ARGS=--no-sandbox"
-#   - "export DISPLAY=:99.0"
-#   - "sh -e /etc/init.d/xvfb start"
-
 script: ./tool/travis.sh
diff --git a/pub/usage/.vscode/launch.json b/pub/usage/.vscode/launch.json
new file mode 100644
index 0000000..3e69379
--- /dev/null
+++ b/pub/usage/.vscode/launch.json
@@ -0,0 +1,15 @@
+{
+  "version": "0.2.0",
+  "configurations": [
+
+    {
+      "name": "Dart command line",
+      "type": "dart-cli",
+      "request": "launch",
+      "cwd": "${workspaceRoot}",
+      "debugSettings": "${command.debugSettings}",
+      "program": "${workspaceRoot}/example/ga.dart",
+      "args": []
+    }
+  ]
+}
\ No newline at end of file
diff --git a/pub/usage/BUILD.gn b/pub/usage/BUILD.gn
index f5ef48d..fb2aaa5 100644
--- a/pub/usage/BUILD.gn
+++ b/pub/usage/BUILD.gn
@@ -1,4 +1,4 @@
-# This file is generated by importer.py for usage-2.2.2
+# This file is generated by importer.py for usage-3.0.0
 
 import("//build/dart/dart_package.gni")
 
diff --git a/pub/usage/changelog.md b/pub/usage/changelog.md
index 0d5a5d7..16729df 100644
--- a/pub/usage/changelog.md
+++ b/pub/usage/changelog.md
@@ -1,5 +1,13 @@
 # Changelog
 
+## 3.0.0
+- removed the use of configurable imports
+- removed the Flutter specific entry-point; Flutter apps can now use the
+  regular `dart:io` entrypoint (AnalyticsIO)
+- moved the uuid library from `lib/src/` to `lib/uuid/`
+- fixed an issue with reporting the user language for the dart:io provider
+- changed to send additional lines for reported exceptions
+
 ## 2.2.2
 - adjust the Flutter usage client to Flutter API changes
 
diff --git a/pub/usage/example/example.dart b/pub/usage/example/example.dart
index 27fb5fc..06578c3 100644
--- a/pub/usage/example/example.dart
+++ b/pub/usage/example/example.dart
@@ -5,10 +5,9 @@
 /// A simple web app to hand-test the usage library.
 library usage_example;
 
-import 'dart:async';
 import 'dart:html';
 
-import 'package:usage/usage.dart';
+import 'package:usage/usage_html.dart';
 
 Analytics _analytics;
 String _lastUa;
@@ -22,28 +21,28 @@
 
 String _ua() => (querySelector('#ua') as InputElement).value.trim();
 
-Future<Analytics> getAnalytics() async {
+Analytics getAnalytics() {
   if (_analytics == null || _lastUa != _ua()) {
     _lastUa = _ua();
-    _analytics = await Analytics.create(_lastUa, 'Test app', '1.0');
+    _analytics = new AnalyticsHtml(_lastUa, 'Test app', '1.0');
     _analytics.sendScreenView(window.location.pathname);
   }
 
   return _analytics;
 }
 
-Future _handleFoo() async {
-  Analytics analytics = await getAnalytics();
+void _handleFoo() {
+  Analytics analytics = getAnalytics();
   analytics.sendEvent('main', 'foo');
 }
 
-Future _handleBar() async {
-  Analytics analytics = await getAnalytics();
+void _handleBar() {
+  Analytics analytics = getAnalytics();
   analytics.sendEvent('main', 'bar');
 }
 
-Future _changePage() async {
-  Analytics analytics = await getAnalytics();
+void _changePage() {
+  Analytics analytics = getAnalytics();
   window.history.pushState(null, 'new page', '${++_count}.html');
   analytics.sendScreenView(window.location.pathname);
 }
diff --git a/pub/usage/example/flutter_example/.gitignore b/pub/usage/example/flutter_example/.gitignore
deleted file mode 100644
index 14c7d4c..0000000
--- a/pub/usage/example/flutter_example/.gitignore
+++ /dev/null
@@ -1,9 +0,0 @@
-.DS_Store
-.atom/
-.idea
-.packages
-.pub/
-build/
-ios/.generated/
-packages
-pubspec.lock
diff --git a/pub/usage/example/flutter_example/README.md b/pub/usage/example/flutter_example/README.md
deleted file mode 100644
index 7608a60..0000000
--- a/pub/usage/example/flutter_example/README.md
+++ /dev/null
@@ -1,9 +0,0 @@
-# Example of usage package with Flutter
-
-To run the Flutter example, ensure that the pubspec.yaml points to your Flutter
-path. Then run:
-
-```
-pub get
-flutter run
-```
diff --git a/pub/usage/example/flutter_example/android/AndroidManifest.xml b/pub/usage/example/flutter_example/android/AndroidManifest.xml
deleted file mode 100644
index 2e28bb3..0000000
--- a/pub/usage/example/flutter_example/android/AndroidManifest.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.yourcompany.flutterExample"
-    android:versionCode="1"
-    android:versionName="0.0.1">
-
-    <uses-sdk android:minSdkVersion="16" android:targetSdkVersion="21" />
-    <uses-permission android:name="android.permission.INTERNET"/>
-
-    <application android:name="org.domokit.sky.shell.SkyApplication" android:label="flutter_example" android:icon="@mipmap/ic_launcher">
-        <activity android:name="org.domokit.sky.shell.SkyActivity"
-                  android:launchMode="singleTask"
-                  android:theme="@android:style/Theme.Black.NoTitleBar"
-                  android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection"
-                  android:hardwareAccelerated="true"
-                  android:windowSoftInputMode="adjustResize">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN"/>
-                <category android:name="android.intent.category.LAUNCHER"/>
-            </intent-filter>
-        </activity>
-    </application>
-</manifest>
diff --git a/pub/usage/example/flutter_example/flutter.yaml b/pub/usage/example/flutter_example/flutter.yaml
deleted file mode 100644
index 2f6cd44..0000000
--- a/pub/usage/example/flutter_example/flutter.yaml
+++ /dev/null
@@ -1,2 +0,0 @@
-name: flutter_example
-uses-material-design: true
diff --git a/pub/usage/example/flutter_example/lib/main.dart b/pub/usage/example/flutter_example/lib/main.dart
deleted file mode 100644
index ff2d78d..0000000
--- a/pub/usage/example/flutter_example/lib/main.dart
+++ /dev/null
@@ -1,73 +0,0 @@
-// Copyright 2016, the Flutter project authors.  Please see the AUTHORS file
-// for 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:flutter/material.dart';
-import 'package:usage/usage.dart';
-
-Future main() async {
-  runApp(new Container());
-  Analytics ga = await Analytics.create('UA-67589403-4', 'ga_test', '1.0');
-  runApp(new MaterialApp(
-    title: 'Usage Example',
-    theme: new ThemeData.dark(),
-    routes: <String, WidgetBuilder>{
-      '/': (BuildContext context) => new FlutterDemo(ga)
-    }
-  ));
-}
-
-class FlutterDemo extends StatefulWidget {
-  FlutterDemo(this.ga);
-  Analytics ga;
-  @override
-  State createState() => new _FlutterDemoState();
-}
-
-class _FlutterDemoState extends State<FlutterDemo> {
-  int _times = 0;
-
-  void _handleButtonPressed() {
-    config.ga.sendEvent('button', 'pressed');
-    setState(() {
-      _times++;
-    });
-  }
-
-  void _handleOptIn(bool value) {
-    setState(() {
-      config.ga.enabled = value;
-    });
-  }
-
-  @override
-  Widget build(BuildContext context) {
-    return new Scaffold(
-      appBar: new AppBar(
-        title: new Text('Usage Example')
-      ),
-      body: new Column(
-        children: <Widget>[
-          new Center(
-            child: new Text("Button pressed $_times times.")
-          ),
-          new ListItem(
-            onTap: () => _handleOptIn(!config.ga.enabled),
-            leading: new Checkbox(
-              value: config.ga.enabled,
-              onChanged: _handleOptIn
-            ),
-            title: new Text("Opt in to analytics")
-          )
-        ],
-        mainAxisAlignment: MainAxisAlignment.spaceAround
-      ),
-      floatingActionButton: new FloatingActionButton(
-        child: new Icon(icon: Icons.add),
-        onPressed: _handleButtonPressed
-      )
-    );
-  }
-}
diff --git a/pub/usage/example/flutter_example/pubspec.yaml b/pub/usage/example/flutter_example/pubspec.yaml
deleted file mode 100644
index e95d585..0000000
--- a/pub/usage/example/flutter_example/pubspec.yaml
+++ /dev/null
@@ -1,7 +0,0 @@
-name: flutter_example
-description: Create a new Flutter project.
-dependencies:
-  usage:
-    path: ../..
-  flutter:
-    path: ../../../flutter/packages/flutter
diff --git a/pub/usage/example/ga.dart b/pub/usage/example/ga.dart
index e905ea6..bf0807e 100644
--- a/pub/usage/example/ga.dart
+++ b/pub/usage/example/ga.dart
@@ -5,11 +5,9 @@
 /// A simple command-line app to hand-test the usage library.
 library usage_ga;
 
-import 'dart:async';
+import 'package:usage/usage_io.dart';
 
-import 'package:usage/usage.dart';
-
-Future main(List args) async {
+main(List args) async {
   final String DEFAULT_UA = 'UA-55029513-1';
 
   if (args.isEmpty) {
@@ -21,17 +19,13 @@
 
   String ua = args.isEmpty ? DEFAULT_UA : args.first;
 
-  Analytics ga = await Analytics.create(ua, 'ga_test', '1.0');
+  Analytics ga = new AnalyticsIO(ua, 'ga_test', '3.0');
 
-  ga.sendScreenView('home').then((_) {
-    return ga.sendScreenView('files');
-  }).then((_) {
-    return ga.sendException('foo exception, line 123:56');
-  }).then((_) {
-    return ga.sendTiming('writeDuration', 123);
-  }).then((_) {
-    return ga.sendEvent('create', 'consoleapp', label: 'Console App');
-  }).then((_) {
-    print('pinged ${ua}');
-  });
+  await ga.sendScreenView('home');
+  await ga.sendScreenView('files');
+  await ga
+      .sendException('foo error:\n${sanitizeStacktrace(StackTrace.current)}');
+  await ga.sendTiming('writeDuration', 123);
+  await ga.sendEvent('create', 'consoleapp', label: 'Console App');
+  print('pinged ${ua}');
 }
diff --git a/pub/usage/lib/src/usage_impl.dart b/pub/usage/lib/src/usage_impl.dart
index 290c5fb..105fe36 100644
--- a/pub/usage/lib/src/usage_impl.dart
+++ b/pub/usage/lib/src/usage_impl.dart
@@ -6,9 +6,7 @@
 import 'dart:math' as math;
 
 import '../usage.dart';
-import 'uuid.dart';
-
-final int _MAX_EXCEPTION_LENGTH = 100;
+import '../uuid/uuid.dart';
 
 String postEncode(Map<String, dynamic> map) {
   // &foo=bar
@@ -19,11 +17,11 @@
 }
 
 /**
- * A throttling algorithim. This models the throttling after a bucket with
+ * A throttling algorithm. This models the throttling after a bucket with
  * water dripping into it at the rate of 1 drop per second. If the bucket has
  * water when an operation is requested, 1 drop of water is removed and the
- * operation is performed. If not the operation is skipped. This algorithim
- * lets operations be peformed in bursts without throttling, but holds the
+ * operation is performed. If not the operation is skipped. This algorithm
+ * lets operations be performed in bursts without throttling, but holds the
  * overall average rate of operations to 1 per second.
  */
 class ThrottlingBucket {
@@ -59,7 +57,8 @@
 }
 
 class AnalyticsImpl implements Analytics {
-  static const String _defaultAnalyticsUrl = 'https://www.google-analytics.com/collect';
+  static const String _defaultAnalyticsUrl =
+      'https://www.google-analytics.com/collect';
 
   /**
    * Tracking ID / Property ID.
@@ -78,16 +77,13 @@
 
   String _url;
 
-  StreamController<Map<String, dynamic>> _sendController = new StreamController.broadcast(sync: true);
+  StreamController<Map<String, dynamic>> _sendController =
+      new StreamController.broadcast(sync: true);
 
-  AnalyticsImpl(
-    this.trackingId,
-    this.properties,
-    this.postHandler, {
-    String applicationName,
-    String applicationVersion,
-    String analyticsUrl
-  }) {
+  AnalyticsImpl(this.trackingId, this.properties, this.postHandler,
+      {String applicationName,
+      String applicationVersion,
+      String analyticsUrl}) {
     assert(trackingId != null);
 
     if (applicationName != null) setSessionValue('an', applicationName);
@@ -115,7 +111,9 @@
    */
   bool get enabled {
     bool optIn = analyticsOpt == AnalyticsOpt.optIn;
-    return optIn ? properties['enabled'] == true : properties['enabled'] != false;
+    return optIn
+        ? properties['enabled'] == true
+        : properties['enabled'] != false;
   }
 
   /**
@@ -142,19 +140,25 @@
     return _sendPayload('social', args);
   }
 
-  Future sendTiming(String variableName, int time, {String category, String label}) {
+  Future sendTiming(String variableName, int time,
+      {String category, String label}) {
     Map<String, dynamic> args = {'utv': variableName, 'utt': time};
     if (label != null) args['utl'] = label;
     if (category != null) args['utc'] = category;
     return _sendPayload('timing', args);
   }
 
-  AnalyticsTimer startTimer(String variableName, {String category, String label}) {
-    return new AnalyticsTimer(this,
-        variableName, category: category, label: label);
+  AnalyticsTimer startTimer(String variableName,
+      {String category, String label}) {
+    return new AnalyticsTimer(this, variableName,
+        category: category, label: label);
   }
 
   Future sendException(String description, {bool fatal}) {
+    // We trim exceptions to a max length; google analytics will apply it's own
+    // truncation, likely around 150 chars or so.
+    const int maxExceptionLength = 1000;
+
     // In order to ensure that the client of this API is not sending any PII
     // data, we strip out any stack trace that may reference a path on the
     // user's drive (file:/...).
@@ -162,8 +166,10 @@
       description = description.substring(0, description.indexOf('file:/'));
     }
 
-    if (description != null && description.length > _MAX_EXCEPTION_LENGTH) {
-      description = description.substring(0, _MAX_EXCEPTION_LENGTH);
+    description = description.replaceAll('\n', '; ');
+
+    if (description.length > maxExceptionLength) {
+      description = description.substring(0, maxExceptionLength);
     }
 
     Map<String, dynamic> args = {'exd': description};
@@ -253,7 +259,7 @@
  * of these injected into it. There are default implementations for `dart:io`
  * and `dart:html` clients.
  *
- * The [name] paramater is used to uniquely store these properties on disk /
+ * The [name] parameter is used to uniquely store these properties on disk /
  * persistent storage.
  */
 abstract class PersistentProperties {
@@ -261,8 +267,8 @@
 
   PersistentProperties(this.name);
 
-  dynamic operator[](String key);
-  void operator[]=(String key, dynamic value);
+  dynamic operator [](String key);
+  void operator []=(String key, dynamic value);
 }
 
 /**
diff --git a/pub/usage/lib/src/usage_impl_default.dart b/pub/usage/lib/src/usage_impl_default.dart
deleted file mode 100644
index 78b3f46..0000000
--- a/pub/usage/lib/src/usage_impl_default.dart
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'dart:async';
-
-import '../usage.dart';
-
-Future<Analytics> createAnalytics(
-  String trackingId,
-  String applicationName,
-  String applicationVersion, {
-  String analyticsUrl
-}) {
-  throw new UnimplementedError();
-}
diff --git a/pub/usage/lib/src/usage_impl_flutter.dart b/pub/usage/lib/src/usage_impl_flutter.dart
deleted file mode 100644
index 58f90a3..0000000
--- a/pub/usage/lib/src/usage_impl_flutter.dart
+++ /dev/null
@@ -1,91 +0,0 @@
-// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'dart:async';
-import 'dart:convert' show JSON;
-import 'dart:io';
-
-import 'package:flutter/http.dart' as http;
-import 'package:flutter/services.dart';
-import 'package:path/path.dart' as path;
-
-import '../usage.dart';
-import 'usage_impl.dart';
-
-Future<Analytics> createAnalytics(
-  String trackingId,
-  String applicationName,
-  String applicationVersion, {
-  String analyticsUrl
-}) async {
-    Directory dataDirectory = await PathProvider.getTemporaryDirectory();
-
-    String fileName = '.${applicationName.replaceAll(' ', '_')}';
-    File file = new File(path.join(dataDirectory.path, fileName));
-    await file.create();
-    String contents = await file.readAsString();
-    if (contents.isEmpty) contents = '{}';
-    Map map = JSON.decode(contents);
-
-    return new AnalyticsImpl(
-      trackingId,
-      new FlutterPersistentProperties(applicationName, file, map),
-      new FlutterPostHandler(),
-      applicationName: applicationName,
-      applicationVersion: applicationVersion,
-      analyticsUrl: analyticsUrl
-    );
-}
-
-String _createUserAgent() {
-  // Mozilla/5.0 (iPhone; U; CPU iPhone OS 5_1_1 like Mac OS X; en)
-  // Dart/1.8.0-edge.41170 (macos; macos; macos; null)
-  String os = Platform.operatingSystem;
-  String locale = Platform.environment['LANG'];
-  return "Dart/${_dartVersion()} (${os}; ${os}; ${os}; ${locale})";
-}
-
-String _dartVersion() {
-  String ver = Platform.version;
-  int index = ver.indexOf(' ');
-  if (index != -1) ver = ver.substring(0, index);
-  return ver;
-}
-
-class FlutterPostHandler extends PostHandler {
-  final String _userAgent;
-  final HttpClient mockClient;
-
-  FlutterPostHandler({HttpClient this.mockClient}) : _userAgent = _createUserAgent();
-
-  Future sendPost(String url, Map<String, dynamic> parameters) {
-    // Add custom parameters for OS and the Dart version.
-    parameters['cd1'] = Platform.operatingSystem;
-    parameters['cd2'] = 'dart ${_dartVersion()}';
-
-    String data = postEncode(parameters);
-
-    Map<String, String> headers = <String, String>{ 'User-Agent': _userAgent };
-
-    return http.post(url, body: data, headers: headers);
-  }
-}
-
-class FlutterPersistentProperties extends PersistentProperties {
-  File _file;
-  Map _map;
-  FlutterPersistentProperties(String name, this._file, this._map) : super(name);
-
-  dynamic operator[](String key) => _map[key];
-
-  void operator[]=(String key, dynamic value) {
-    if (value == null) {
-      _map.remove(key);
-    } else {
-      _map[key] = value;
-    }
-
-    _file.writeAsString(JSON.encode(_map) + '\n');
-  }
-}
diff --git a/pub/usage/lib/src/usage_impl_html.dart b/pub/usage/lib/src/usage_impl_html.dart
index 6a5922c..7752fe5 100644
--- a/pub/usage/lib/src/usage_impl_html.dart
+++ b/pub/usage/lib/src/usage_impl_html.dart
@@ -6,34 +6,21 @@
 import 'dart:convert' show JSON;
 import 'dart:html';
 
-import '../usage.dart';
 import 'usage_impl.dart';
 
-Future<Analytics> createAnalytics(
-  String trackingId,
-  String applicationName,
-  String applicationVersion, {
-  String analyticsUrl
-}) {
-  return new Future.value(new AnalyticsHtml(
-    trackingId,
-    applicationName,
-    applicationVersion,
-    analyticsUrl: analyticsUrl
-  ));
-}
-
+/// An interface to a Google Analytics session, suitable for use in web apps.
+///
+/// [analyticsUrl] is an optional replacement for the default Google Analytics
+/// URL (`https://www.google-analytics.com/collect`).
 class AnalyticsHtml extends AnalyticsImpl {
-  AnalyticsHtml(String trackingId, String applicationName, String applicationVersion, {
-    String analyticsUrl
-  }) : super(
-      trackingId,
-      new HtmlPersistentProperties(applicationName),
-      new HtmlPostHandler(),
-      applicationName: applicationName,
-      applicationVersion: applicationVersion,
-      analyticsUrl: analyticsUrl
-  ) {
+  AnalyticsHtml(
+      String trackingId, String applicationName, String applicationVersion,
+      {String analyticsUrl})
+      : super(trackingId, new HtmlPersistentProperties(applicationName),
+            new HtmlPostHandler(),
+            applicationName: applicationName,
+            applicationVersion: applicationVersion,
+            analyticsUrl: analyticsUrl) {
     int screenWidth = window.screen.width;
     int screenHeight = window.screen.height;
 
@@ -58,7 +45,7 @@
     var request = mockRequestor == null ? HttpRequest.request : mockRequestor;
     return request(url, method: 'POST', sendData: data).catchError((e) {
       // Catch errors that can happen during a request, but that we can't do
-      // anything about, e.g. a missing internet conenction.
+      // anything about, e.g. a missing internet connection.
     });
   }
 }
@@ -72,9 +59,9 @@
     _map = JSON.decode(str);
   }
 
-  dynamic operator[](String key) => _map[key];
+  dynamic operator [](String key) => _map[key];
 
-  void operator[]=(String key, dynamic value) {
+  void operator []=(String key, dynamic value) {
     if (value == null) {
       _map.remove(key);
     } else {
diff --git a/pub/usage/lib/src/usage_impl_io.dart b/pub/usage/lib/src/usage_impl_io.dart
index fff224a..fe5cc44 100644
--- a/pub/usage/lib/src/usage_impl_io.dart
+++ b/pub/usage/lib/src/usage_impl_io.dart
@@ -8,49 +8,55 @@
 
 import 'package:path/path.dart' as path;
 
-import '../usage.dart';
 import 'usage_impl.dart';
 
-Future<Analytics> createAnalytics(
-  String trackingId,
-  String applicationName,
-  String applicationVersion, {
-  String analyticsUrl
-}) {
-  return new Future.value(new AnalyticsIO(
-    trackingId,
-    applicationName,
-    applicationVersion,
-    analyticsUrl: analyticsUrl
-  ));
-}
-
+/// An interface to a Google Analytics session, suitable for use in command-line
+/// applications.
+///
+/// `trackingId`, `applicationName`, and `applicationVersion` values should be supplied.
+/// `analyticsUrl` is optional, and lets user's substitute their own analytics URL for
+/// the default.
+///
+/// `documentDirectory` is where the analytics settings are stored. It
+/// defaults to the user home directory. For regular `dart:io` apps this doesn't need to
+/// be supplied. For Flutter applications, you should pass in a value like
+/// `PathProvider.getApplicationDocumentsDirectory()`.
 class AnalyticsIO extends AnalyticsImpl {
-  AnalyticsIO(String trackingId, String applicationName, String applicationVersion, {
-    String analyticsUrl
-  }) : super(
-    trackingId,
-    new IOPersistentProperties(applicationName),
-    new IOPostHandler(),
-    applicationName: applicationName,
-    applicationVersion: applicationVersion,
-    analyticsUrl: analyticsUrl
-  );
+  AnalyticsIO(
+      String trackingId, String applicationName, String applicationVersion,
+      {String analyticsUrl, Directory documentDirectory})
+      : super(
+            trackingId,
+            new IOPersistentProperties(applicationName,
+                documentDirPath: documentDirectory?.path),
+            new IOPostHandler(),
+            applicationName: applicationName,
+            applicationVersion: applicationVersion,
+            analyticsUrl: analyticsUrl) {
+    final String locale = getPlatformLocale();
+    if (locale != null) {
+      setSessionValue('ul', locale);
+    }
+  }
 }
 
 String _createUserAgent() {
-  if (Platform.isMacOS) {
-    return 'Mozilla/5.0 (Macintosh; Intel Mac OS X)';
+  final String locale = getPlatformLocale() ?? '';
+
+  if (Platform.isAndroid) {
+    return 'Mozilla/5.0 (Android; Mobile; ${locale})';
+  } else if (Platform.isIOS) {
+    return 'Mozilla/5.0 (iPhone; U; CPU iPhone OS like Mac OS X; ${locale})';
   } else if (Platform.isMacOS) {
-    return 'Mozilla/5.0 (Windows; Windows)';
+    return 'Mozilla/5.0 (Macintosh; Intel Mac OS X; Macintosh; ${locale})';
+  } else if (Platform.isWindows) {
+    return 'Mozilla/5.0 (Windows; Windows; Windows; ${locale})';
   } else if (Platform.isLinux) {
-    return 'Mozilla/5.0 (Linux; Linux)';
+    return 'Mozilla/5.0 (Linux; Linux; Linux; ${locale})';
   } else {
-    // Mozilla/5.0 (iPhone; U; CPU iPhone OS 5_1_1 like Mac OS X; en)
-    // Dart/1.8.0-edge.41170 (macos; macos; macos; null)
+    // Dart/1.8.0 (macos; macos; macos; en_US)
     String os = Platform.operatingSystem;
-    String locale = Platform.environment['LANG'];
-    return "Dart/${_dartVersion()} (${os}; ${os}; ${os}; ${locale})";
+    return "Dart/${getDartVersion()} (${os}; ${os}; ${os}; ${locale})";
   }
 }
 
@@ -60,7 +66,7 @@
   return value == null ? '.' : value;
 }
 
-String _dartVersion() {
+String getDartVersion() {
   String ver = Platform.version;
   int index = ver.indexOf(' ');
   if (index != -1) ver = ver.substring(0, index);
@@ -74,10 +80,6 @@
   IOPostHandler({HttpClient this.mockClient}) : _userAgent = _createUserAgent();
 
   Future sendPost(String url, Map<String, dynamic> parameters) async {
-    // Add custom parameters for OS and the Dart version.
-    parameters['cd1'] = Platform.operatingSystem;
-    parameters['cd2'] = 'dart ${_dartVersion()}';
-
     String data = postEncode(parameters);
 
     HttpClient client = mockClient != null ? mockClient : new HttpClient();
@@ -87,9 +89,9 @@
       req.write(data);
       HttpClientResponse response = await req.close();
       response.drain();
-    } catch(exception) {
+    } catch (exception) {
       // Catch errors that can happen during a request, but that we can't do
-      // anything about, e.g. a missing internet conenction.
+      // anything about, e.g. a missing internet connection.
     }
   }
 }
@@ -98,9 +100,10 @@
   File _file;
   Map _map;
 
-  IOPersistentProperties(String name) : super(name) {
+  IOPersistentProperties(String name, {String documentDirPath}) : super(name) {
     String fileName = '.${name.replaceAll(' ', '_')}';
-    _file = new File(path.join(_userHomeDir(), fileName));
+    documentDirPath ??= _userHomeDir();
+    _file = new File(path.join(documentDirPath, fileName));
 
     try {
       if (!_file.existsSync()) _file.createSync();
@@ -112,9 +115,9 @@
     }
   }
 
-  dynamic operator[](String key) => _map[key];
+  dynamic operator [](String key) => _map[key];
 
-  void operator[]=(String key, dynamic value) {
+  void operator []=(String key, dynamic value) {
     if (value == null && !_map.containsKey(key)) return;
     if (_map[key] == value) return;
 
@@ -126,6 +129,24 @@
 
     try {
       _file.writeAsStringSync(JSON.encode(_map) + '\n');
-    } catch (_) { }
+    } catch (_) {}
   }
 }
+
+/// Return the string for the platform's locale; return's `null` if the locale
+/// can't be determined.
+String getPlatformLocale() {
+  String locale = Platform.environment['LANG'];
+  if (locale == null) return null;
+
+  if (locale != null) {
+    // Convert `en_US.UTF-8` to `en_US`.
+    int index = locale.indexOf('.');
+    if (index != null) locale = locale.substring(0, index);
+
+    // Convert `en_US` to `en-us`.
+    locale = locale.replaceAll('_', '-').toLowerCase();
+  }
+
+  return locale;
+}
diff --git a/pub/usage/lib/src/uuid.dart b/pub/usage/lib/src/uuid.dart
deleted file mode 100644
index 66e99ac..0000000
--- a/pub/usage/lib/src/uuid.dart
+++ /dev/null
@@ -1,48 +0,0 @@
-// 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.
-
-/**
- * A UUID generator library.
- */
-library usage.uuid;
-
-import 'dart:math' show Random;
-
-/**
- * A UUID generator. This will generate unique IDs in the format:
- *
- *     f47ac10b-58cc-4372-a567-0e02b2c3d479
- *
- * The generated uuids are 128 bit numbers encoded in a specific string format.
- *
- * For more information, see
- * http://en.wikipedia.org/wiki/Universally_unique_identifier.
- */
-class Uuid {
-  Random _random = new Random();
-
-  /**
-   * Generate a version 4 (random) uuid. This is a uuid scheme that only uses
-   * random numbers as the source of the generated uuid.
-   */
-  String generateV4() {
-    // Generate xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx / 8-4-4-4-12.
-    int special = 8 + _random.nextInt(4);
-
-    return
-        '${_bitsDigits(16, 4)}${_bitsDigits(16, 4)}-'
-        '${_bitsDigits(16, 4)}-'
-        '4${_bitsDigits(12, 3)}-'
-        '${_printDigits(special,  1)}${_bitsDigits(12, 3)}-'
-        '${_bitsDigits(16, 4)}${_bitsDigits(16, 4)}${_bitsDigits(16, 4)}';
-  }
-
-  String _bitsDigits(int bitCount, int digitCount) =>
-      _printDigits(_generateBits(bitCount), digitCount);
-
-  int _generateBits(int bitCount) => _random.nextInt(1 << bitCount);
-
-  String _printDigits(int value, int count) =>
-      value.toRadixString(16).padLeft(count, '0');
-}
diff --git a/pub/usage/lib/usage.dart b/pub/usage/lib/usage.dart
index 53f1812..13f98d6 100644
--- a/pub/usage/lib/usage.dart
+++ b/pub/usage/lib/usage.dart
@@ -3,15 +3,17 @@
 // BSD-style license that can be found in the LICENSE file.
 
 /**
- * `usage` is a wrapper around Google Analytics for both command-line, web, and
- * Flutter apps.
+ * `usage` is a wrapper around Google Analytics for both command-line apps
+ * and web apps.
  *
- * In order to use this library, call the [Analytics.create] static method.
- * You'll get either the command-line, web, or Flutter implementation based on
- * the current platform.
+ * In order to use this library as a web app, import the `analytics_html.dart`
+ * library and instantiate the [AnalyticsHtml] class.
  *
- * When creating a new Analytics instance, you need to provide a Google
- * Analytics tracking ID, the application name, and the application version.
+ * In order to use this library as a command-line app, import the
+ * `analytics_io.dart` library and instantiate the [AnalyticsIO] class.
+ *
+ * For both classes, you need to provide a Google Analytics tracking ID, the
+ * application name, and the application version.
  *
  * Your application should provide an opt-in option for the user. If they
  * opt-in, set the [optIn] field to `true`. This setting will persist across
@@ -24,40 +26,22 @@
 
 import 'dart:async';
 
-import 'src/usage_impl_default.dart'
-   if (dart.library.js) 'src/usage_impl_html.dart'
-   if (dart.library.ui) 'src/usage_impl_flutter.dart'
-   if (dart.library.io) 'src/usage_impl_io.dart'
-   as impl;
-
 // Matches file:/, non-ws, /, non-ws, .dart
 final RegExp _pathRegex = new RegExp(r'file:/\S+/(\S+\.dart)');
 
+// Match multiple tabs or spaces.
+final RegExp _tabOrSpaceRegex = new RegExp(r'[\t ]+');
+
 /**
- * An interface to a Google Analytics session. You'll get the correct one for
- * your platform by calling the [Analytics.create] static method.
- * [AnalyticsMock] can be used for testing or for some variants of an opt-in
- * workflow.
+ * An interface to a Google Analytics session. [AnalyticsHtml] and [AnalyticsIO]
+ * are concrete implementations of this interface. [AnalyticsMock] can be used
+ * for testing or for some variants of an opt-in workflow.
  *
- * The analytics information is sent on a best-effort basis. Failures to send
- * the GA information will not result in errors from the asynchronous `send`
- * methods.
+ * The analytics information is sent on a best-effort basis. So, failures to
+ * send the GA information will not result in errors from the asynchronous
+ * `send` methods.
  */
 abstract class Analytics {
-  static Future<Analytics> create(
-    String trackingId,
-    String applicationName,
-    String applicationVersion, {
-    String analyticsUrl
-  }) {
-    return impl.createAnalytics(
-      trackingId,
-      applicationName,
-      applicationVersion,
-      analyticsUrl: analyticsUrl
-    );
-  }
-
   /**
    * Tracking ID / Property ID.
    */
@@ -109,8 +93,8 @@
    * milliseconds). [category] specifies the category of the timing. [label]
    * specifies the label of the timing.
    */
-  Future sendTiming(String variableName, int time, {String category,
-      String label});
+  Future sendTiming(String variableName, int time,
+      {String category, String label});
 
   /**
    * Start a timer. The time won't be calculated, and the analytics information
@@ -141,7 +125,7 @@
 
   /**
    * Fires events when the usage library sends any data over the network. This
-   * will not fire if analytics has been disabled or if the throttling algorithim
+   * will not fire if analytics has been disabled or if the throttling algorithm
    * has been engaged.
    *
    * This method is public to allow library clients to more easily test their
@@ -210,8 +194,8 @@
     if (_endMillis != null) return new Future.value();
 
     _endMillis = new DateTime.now().millisecondsSinceEpoch;
-    return analytics.sendTiming(
-        variableName, currentElapsedMillis, category: category, label: label);
+    return analytics.sendTiming(variableName, currentElapsedMillis,
+        category: category, label: label);
   }
 }
 
@@ -223,11 +207,11 @@
   String get trackingId => 'UA-0';
   final bool logCalls;
 
-
   /**
    * Events are never added to this controller for the mock implementation.
    */
-  StreamController<Map<String, dynamic>> _sendController = new StreamController.broadcast();
+  StreamController<Map<String, dynamic>> _sendController =
+      new StreamController.broadcast();
 
   /**
    * Create a new [AnalyticsMock]. If [logCalls] is true, all calls will be
@@ -245,20 +229,31 @@
       _log('screenView', {'viewName': viewName});
 
   Future sendEvent(String category, String action, {String label, int value}) {
-    return _log('event', {'category': category, 'action': action,
-      'label': label, 'value': value});
+    return _log('event', {
+      'category': category,
+      'action': action,
+      'label': label,
+      'value': value
+    });
   }
 
   Future sendSocial(String network, String action, String target) =>
       _log('social', {'network': network, 'action': action, 'target': target});
 
-  Future sendTiming(String variableName, int time, {String category, String label}) {
-    return _log('timing', {'variableName': variableName, 'time': time,
-      'category': category, 'label': label});
+  Future sendTiming(String variableName, int time,
+      {String category, String label}) {
+    return _log('timing', {
+      'variableName': variableName,
+      'time': time,
+      'category': category,
+      'label': label
+    });
   }
 
-  AnalyticsTimer startTimer(String variableName, {String category, String label}) {
-    return new AnalyticsTimer(this, variableName, category: category, label: label);
+  AnalyticsTimer startTimer(String variableName,
+      {String category, String label}) {
+    return new AnalyticsTimer(this, variableName,
+        category: category, label: label);
   }
 
   Future sendException(String description, {bool fatal}) =>
@@ -266,7 +261,7 @@
 
   dynamic getSessionValue(String param) => null;
 
-  void setSessionValue(String param, dynamic value) { }
+  void setSessionValue(String param, dynamic value) {}
 
   Stream<Map<String, dynamic>> get onSend => _sendController.stream;
 
@@ -299,16 +294,13 @@
 
   for (Match match in iter) {
     String replacement = match.group(1);
-    str = str.substring(0, match.start)
-        + replacement + str.substring(match.end);
+    str =
+        str.substring(0, match.start) + replacement + str.substring(match.end);
   }
 
   if (shorten) {
     // Shorten the stacktrace up a bit.
-    str = str
-        .replaceAll('(package:', '(')
-        .replaceAll('(dart:', '(')
-        .replaceAll(new RegExp(r'\s+'), ' ');
+    str = str.replaceAll(_tabOrSpaceRegex, ' ');
   }
 
   return str;
diff --git a/pub/usage/lib/usage_html.dart b/pub/usage/lib/usage_html.dart
new file mode 100644
index 0000000..569c1eb
--- /dev/null
+++ b/pub/usage/lib/usage_html.dart
@@ -0,0 +1,13 @@
+// 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.
+
+/// In order to use this library import the `usage_html.dart` file and
+/// instantiate the [AnalyticsHtml] class.
+///
+/// You'll need to provide a Google Analytics tracking ID, the application name,
+/// and the application version.
+library usage_html;
+
+export 'src/usage_impl_html.dart' show AnalyticsHtml;
+export 'usage.dart';
diff --git a/pub/usage/lib/usage_io.dart b/pub/usage/lib/usage_io.dart
new file mode 100644
index 0000000..5e35e94
--- /dev/null
+++ b/pub/usage/lib/usage_io.dart
@@ -0,0 +1,13 @@
+// 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.
+
+/// In order to use this library import the `usage_io.dart` file and
+/// instantiate the [AnalyticsIO] class.
+///
+/// You'll need to provide a Google Analytics tracking ID, the application name,
+/// and the application version.
+library usage_io;
+
+export 'src/usage_impl_io.dart' show AnalyticsIO;
+export 'usage.dart';
diff --git a/pub/usage/lib/uuid/uuid.dart b/pub/usage/lib/uuid/uuid.dart
new file mode 100644
index 0000000..eaafeb2
--- /dev/null
+++ b/pub/usage/lib/uuid/uuid.dart
@@ -0,0 +1,42 @@
+// 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.
+
+/// A UUID generator library.
+library uuid;
+
+import 'dart:math' show Random;
+
+/// A UUID generator.
+///
+/// This will generate unique IDs in the format:
+///
+///     f47ac10b-58cc-4372-a567-0e02b2c3d479
+///
+/// The generated uuids are 128 bit numbers encoded in a specific string format.
+/// For more information, see
+/// [en.wikipedia.org/wiki/Universally_unique_identifier](http://en.wikipedia.org/wiki/Universally_unique_identifier).
+class Uuid {
+  final Random _random = new Random();
+
+  /// Generate a version 4 (random) uuid. This is a uuid scheme that only uses
+  /// random numbers as the source of the generated uuid.
+  String generateV4() {
+    // Generate xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx / 8-4-4-4-12.
+    int special = 8 + _random.nextInt(4);
+
+    return '${_bitsDigits(16, 4)}${_bitsDigits(16, 4)}-'
+        '${_bitsDigits(16, 4)}-'
+        '4${_bitsDigits(12, 3)}-'
+        '${_printDigits(special,  1)}${_bitsDigits(12, 3)}-'
+        '${_bitsDigits(16, 4)}${_bitsDigits(16, 4)}${_bitsDigits(16, 4)}';
+  }
+
+  String _bitsDigits(int bitCount, int digitCount) =>
+      _printDigits(_generateBits(bitCount), digitCount);
+
+  int _generateBits(int bitCount) => _random.nextInt(1 << bitCount);
+
+  String _printDigits(int value, int count) =>
+      value.toRadixString(16).padLeft(count, '0');
+}
diff --git a/pub/usage/pubspec.yaml b/pub/usage/pubspec.yaml
index 74705d9..34dd640 100644
--- a/pub/usage/pubspec.yaml
+++ b/pub/usage/pubspec.yaml
@@ -3,13 +3,13 @@
 # BSD-style license that can be found in the LICENSE file.
 
 name: usage
-version: 2.2.2
+version: 3.0.0
 description: A Google Analytics wrapper for both command-line, web, and Flutter apps.
 homepage: https://github.com/dart-lang/usage
 author: Dart Team <misc@dartlang.org>
 
 environment:
-  sdk: '>=1.15.0 <2.0.0'
+  sdk: '>=1.19.0 <2.0.0'
 
 dev_dependencies:
   browser: ^0.10.0
diff --git a/pub/usage/readme.md b/pub/usage/readme.md
index 8aa0b95..458c581 100644
--- a/pub/usage/readme.md
+++ b/pub/usage/readme.md
@@ -3,20 +3,42 @@
 `usage` is a wrapper around Google Analytics for both command-line, web, and
 Flutter apps.
 
+[![pub package](https://img.shields.io/pub/v/usage.svg)](https://pub.dartlang.org/packages/usage)
 [![Build Status](https://travis-ci.org/dart-lang/usage.svg)](https://travis-ci.org/dart-lang/usage)
 [![Coverage Status](https://img.shields.io/coveralls/dart-lang/usage.svg)](https://coveralls.io/r/dart-lang/usage?branch=master)
 
-## Using this library
+## For web apps
 
-In order to use this library, call the `Analytics.create` static method.
-You'll get either the command-line, web, or Flutter implementation based on
-the current platform.
+To use this library as a web app, import the `usage_html.dart` library and
+instantiate the `AnalyticsHtml` class.
 
 When you are creating a new property at [google analytics](https://www.google.com/analytics/)
-make sure to select not the website option, but the **mobile app** option.
+make sure to select the **mobile app** option, not the website option.
+
+## For Flutter apps
+
+Flutter applications can use the `AnalyticsIO` version of this library. They will need
+to specify the documents directory in the constructor in order to tell the library where
+to save the analytics preferences:
+
+```dart
+import 'package:flutter/services.dart';
+import 'package:usage/usage_io.dart';
+
+void main() {
+  final String UA = ...;
+
+  Analytics ga = new AnalyticsIO(UA, 'ga_test', '3.0',
+    documentsDirectory: PathProvider.getApplicationDocumentsDirectory());
+  ...
+}
+```
 
 ## For command-line apps
 
+To use this library as a command-line app, import the `usage_io.dart` library
+and instantiate the `AnalyticsIO` class.
+
 Note, for CLI apps, the usage library will send analytics pings asynchronously.
 This is useful it that it doesn't block the app generally. It does have one
 side-effect, in that outstanding asynchronous requests will block termination
@@ -38,10 +60,10 @@
 
 ## Using the API
 
-Import the package:
+Import the package (in this example we use the `dart:io` version):
 
 ```dart
-import 'package:usage/usage.dart';
+import 'package:usage/usage_io.dart';
 ```
 
 And call some analytics code:
@@ -49,7 +71,8 @@
 ```dart
 final String UA = ...;
 
-Analytics ga = await Analytics.create(UA, 'ga_test', '1.0');
+Analytics ga = new AnalyticsIO(UA, 'ga_test', '3.0');
+ga.optIn = true;
 
 ga.sendScreenView('home');
 ga.sendException('foo exception');
diff --git a/pub/usage/tool/grind.dart b/pub/usage/tool/grind.dart
index 72f4393..f93261b 100644
--- a/pub/usage/tool/grind.dart
+++ b/pub/usage/tool/grind.dart
@@ -15,13 +15,15 @@
 @Task()
 void init() => _buildExampleDir.createSync(recursive: true);
 
-@Task() @Depends(init)
+@Task()
+@Depends(init)
 void build() {
   // Compile `test/web_test.dart` to the `build/test` dir; measure its size.
   File srcFile = new File('example/example.dart');
-  Dart2js.compile(
-    srcFile, outDir: _buildExampleDir, minify: true, extraArgs: ['--conditional-directives']
-  );
+  Dart2js.compile(srcFile,
+      outDir: _buildExampleDir,
+      minify: true,
+      extraArgs: ['--conditional-directives']);
   File outFile = joinFile(_buildExampleDir, ['example.dart.js']);
 
   log('${outFile.path} compiled to ${_printSize(outFile)}');
diff --git a/pub/usage/tool/travis.sh b/pub/usage/tool/travis.sh
index e6f3aca..a3f3082 100755
--- a/pub/usage/tool/travis.sh
+++ b/pub/usage/tool/travis.sh
@@ -15,11 +15,7 @@
   test/all.dart
 
 # Run the tests.
-dart --conditional_directives -c test/all.dart
-
-# Run the UI/web tests as well.
-#pub build test
-#pub run grinder:test build/test/web.html
+dart -c test/all.dart
 
 # Measure the size of the compiled JS, for the dart:html version of the library.
 dart tool/grind.dart build
diff --git a/pub/vector_math/BUILD.gn b/pub/vector_math/BUILD.gn
index 6cadce2..3136ecc 100644
--- a/pub/vector_math/BUILD.gn
+++ b/pub/vector_math/BUILD.gn
@@ -1,4 +1,4 @@
-# This file is generated by importer.py for vector_math-2.0.3
+# This file is generated by importer.py for vector_math-2.0.4
 
 import("//build/dart/dart_package.gni")
 
diff --git a/pub/vector_math/changelog.md b/pub/vector_math/changelog.md
index 88a48ed..5122c85 100644
--- a/pub/vector_math/changelog.md
+++ b/pub/vector_math/changelog.md
@@ -1,5 +1,13 @@
 # Changelog - vector_math
 
+## v 2.0.4 - February 2017
+
+- Added Matrix4.isIdentity()
+- Added Matrix4.isZero()
+- Added Matrix3.isIdentity()
+- Added Matrix3.isZero()
+- Added Vector2.angleTo and Vector2.angleToSigned
+
 ## v 2.0.3 - May 2016
 
 - Synchronize Float64 version
diff --git a/pub/vector_math/lib/src/vector_math/colors.dart b/pub/vector_math/lib/src/vector_math/colors.dart
index 2925a38..6b5a533 100644
--- a/pub/vector_math/lib/src/vector_math/colors.dart
+++ b/pub/vector_math/lib/src/vector_math/colors.dart
@@ -72,17 +72,35 @@
   }
 
   /// Convert a [input] color to a hex string without a leading '#'. To include
-  /// the alpha channel, set [alpha] to true, it is false by default.
-  static String toHexString(Vector4 input, {bool alpha: false}) {
-    var color = (input.r * 255).floor() << 16 |
-        (input.g * 255).floor() << 8 |
-        (input.b * 255).floor();
+  /// the alpha channel, set [alpha] to true, it is false by default. If [short]
+  /// is true, the resulting hex string might also be a short version, like #ff0
+  /// (default false).
+  static String toHexString(Vector4 input,
+      {bool alpha: false, bool short: false}) {
+    final r = (input.r * 0xFF).floor() & 0xFF;
+    final g = (input.g * 0xFF).floor() & 0xFF;
+    final b = (input.b * 0xFF).floor() & 0xFF;
+    final a = (input.a * 0xFF).floor() & 0xFF;
 
-    if (alpha) {
-      color |= (input.a * 255).floor() << 24;
+    final isShort = short &&
+        ((r >> 4) == (r & 0xF)) &&
+        ((g >> 4) == (g & 0xF)) &&
+        ((b >> 4) == (b & 0xF)) &&
+        (!alpha || (a >> 4) == (a & 0xF));
+
+    if (isShort) {
+      final rgb = (r & 0xF).toRadixString(16) +
+          (g & 0xF).toRadixString(16) +
+          (b & 0xF).toRadixString(16);
+
+      return alpha ? (a & 0xF).toRadixString(16) + rgb : rgb;
+    } else {
+      final rgb = r.toRadixString(16).padLeft(2, '0') +
+          g.toRadixString(16).padLeft(2, '0') +
+          b.toRadixString(16).padLeft(2, '0');
+
+      return alpha ? a.toRadixString(16).padLeft(2, '0') + rgb : rgb;
     }
-
-    return color.toRadixString(16);
   }
 
   /// Blend the [foreground] color over [background] color and store the color
diff --git a/pub/vector_math/lib/src/vector_math/matrix3.dart b/pub/vector_math/lib/src/vector_math/matrix3.dart
index 0dae0a3..6f65541 100644
--- a/pub/vector_math/lib/src/vector_math/matrix3.dart
+++ b/pub/vector_math/lib/src/vector_math/matrix3.dart
@@ -899,4 +899,30 @@
     double z = _m3storage[8];
     return new Vector3(x, y, z);
   }
+
+  /// Is [this] the identity matrix?
+  bool isIdentity() {
+    return _m3storage[0] == 1.0 // col 1
+        && _m3storage[1] == 0.0
+        && _m3storage[2] == 0.0
+        && _m3storage[3] == 0.0 // col 2
+        && _m3storage[4] == 1.0
+        && _m3storage[5] == 0.0
+        && _m3storage[6] == 0.0 // col 3
+        && _m3storage[7] == 0.0
+        && _m3storage[8] == 1.0;
+  }
+
+  /// Is [this] the zero matrix?
+  bool isZero() {
+    return _m3storage[0] == 0.0 // col 1
+        && _m3storage[1] == 0.0
+        && _m3storage[2] == 0.0
+        && _m3storage[3] == 0.0 // col 2
+        && _m3storage[4] == 0.0
+        && _m3storage[5] == 0.0
+        && _m3storage[6] == 0.0 // col 3
+        && _m3storage[7] == 0.0
+        && _m3storage[8] == 0.0;
+  }
 }
diff --git a/pub/vector_math/lib/src/vector_math/matrix4.dart b/pub/vector_math/lib/src/vector_math/matrix4.dart
index 7fb688f..0e3e4b4 100644
--- a/pub/vector_math/lib/src/vector_math/matrix4.dart
+++ b/pub/vector_math/lib/src/vector_math/matrix4.dart
@@ -1980,4 +1980,44 @@
     double z = _m4storage[10];
     return new Vector3(x, y, z);
   }
+
+  /// Is [this] the identity matrix?
+  bool isIdentity() {
+    return _m4storage[0] == 1.0 // col 1
+        && _m4storage[1] == 0.0
+        && _m4storage[2] == 0.0
+        && _m4storage[3] == 0.0
+        && _m4storage[4] == 0.0 // col 2
+        && _m4storage[5] == 1.0
+        && _m4storage[6] == 0.0
+        && _m4storage[7] == 0.0
+        && _m4storage[8] == 0.0 // col 3
+        && _m4storage[9] == 0.0
+        && _m4storage[10] == 1.0
+        && _m4storage[11] == 0.0
+        && _m4storage[12] == 0.0 // col 4
+        && _m4storage[13] == 0.0
+        && _m4storage[14] == 0.0
+        && _m4storage[15] == 1.0;
+  }
+
+  /// Is [this] the zero matrix?
+  bool isZero() {
+    return _m4storage[0] == 0.0 // col 1
+        && _m4storage[1] == 0.0
+        && _m4storage[2] == 0.0
+        && _m4storage[3] == 0.0
+        && _m4storage[4] == 0.0 // col 2
+        && _m4storage[5] == 0.0
+        && _m4storage[6] == 0.0
+        && _m4storage[7] == 0.0
+        && _m4storage[8] == 0.0 // col 3
+        && _m4storage[9] == 0.0
+        && _m4storage[10] == 0.0
+        && _m4storage[11] == 0.0
+        && _m4storage[12] == 0.0 // col 4
+        && _m4storage[13] == 0.0
+        && _m4storage[14] == 0.0
+        && _m4storage[15] == 0.0;
+  }
 }
diff --git a/pub/vector_math/lib/src/vector_math/opengl.dart b/pub/vector_math/lib/src/vector_math/opengl.dart
index b913761..d46588d 100644
--- a/pub/vector_math/lib/src/vector_math/opengl.dart
+++ b/pub/vector_math/lib/src/vector_math/opengl.dart
@@ -113,10 +113,16 @@
 /// (always positive).
 void setPerspectiveMatrix(Matrix4 perspectiveMatrix, double fovYRadians,
     double aspectRatio, double zNear, double zFar) {
-  double height = Math.tan(fovYRadians * 0.5) * zNear;
-  double width = height * aspectRatio;
-  setFrustumMatrix(
-      perspectiveMatrix, -width, width, -height, height, zNear, zFar);
+  final double height = Math.tan(fovYRadians * 0.5);
+  final double width = height * aspectRatio;
+  final double near_minus_far = zNear - zFar;
+
+  final Matrix4 view = perspectiveMatrix..setZero();
+  view.setEntry(0, 0, 1.0 / width);
+  view.setEntry(1, 1, 1.0 / height);
+  view.setEntry(2, 2, (zFar + zNear) / near_minus_far);
+  view.setEntry(3, 2, -1.0);
+  view.setEntry(2, 3, (2.0 * zNear * zFar) / near_minus_far);
 }
 
 /// Constructs a new OpenGL perspective projection matrix.
@@ -136,6 +142,41 @@
   return r;
 }
 
+/// Constructs an OpenGL infinite projection matrix in [infiniteMatrix].
+/// [fovYRadians] specifies the field of view angle, in radians, in the y
+/// direction.
+/// [aspectRatio] specifies the aspect ratio that determines the field of view
+/// in the x direction. The aspect ratio of x (width) to y (height).
+/// [zNear] specifies the distance from the viewer to the near plane
+/// (always positive).
+void setInfiniteMatrix(Matrix4 infiniteMatrix, double fovYRadians,
+    double aspectRatio, double zNear) {
+  final double height = Math.tan(fovYRadians * 0.5);
+  final double width = height * aspectRatio;
+
+  final Matrix4 view = infiniteMatrix..setZero();
+  view.setEntry(0, 0, 1.0 / width);
+  view.setEntry(1, 1, 1.0 / height);
+  view.setEntry(2, 2, -1.0);
+  view.setEntry(3, 2, -1.0);
+  view.setEntry(2, 3, -2.0 * zNear);
+}
+
+/// Constructs a new OpenGL infinite projection matrix.
+///
+/// [fovYRadians] specifies the field of view angle, in radians, in the y
+/// direction.
+/// [aspectRatio] specifies the aspect ratio that determines the field of view
+/// in the x direction. The aspect ratio of x (width) to y (height).
+/// [zNear] specifies the distance from the viewer to the near plane
+/// (always positive).
+Matrix4 makeInfiniteMatrix(
+    double fovYRadians, double aspectRatio, double zNear) {
+  Matrix4 r = new Matrix4.zero();
+  setInfiniteMatrix(r, fovYRadians, aspectRatio, zNear);
+  return r;
+}
+
 /// Constructs an OpenGL perspective projection matrix in [perspectiveMatrix].
 ///
 /// [left], [right] specify the coordinates for the left and right vertical
diff --git a/pub/vector_math/lib/src/vector_math/third_party/noise.dart b/pub/vector_math/lib/src/vector_math/third_party/noise.dart
index 517586c..0e695ba 100644
--- a/pub/vector_math/lib/src/vector_math/third_party/noise.dart
+++ b/pub/vector_math/lib/src/vector_math/third_party/noise.dart
@@ -28,53 +28,53 @@
 
 class SimplexNoise {
   static final _grad3 = <List<double>>[
-    [1, 1, 0],
-    [-1, 1, 0],
-    [1, -1, 0],
-    [-1, -1, 0],
-    [1, 0, 1],
-    [-1, 0, 1],
-    [1, 0, -1],
-    [-1, 0, -1],
-    [0, 1, 1],
-    [0, -1, 1],
-    [0, 1, -1],
-    [0, -1, -1]
+    [1.0, 1.0, 0.0],
+    [-1.0, 1.0, 0.0],
+    [1.0, -1.0, 0.0],
+    [-1.0, -1.0, 0.0],
+    [1.0, 0.0, 1.0],
+    [-1.0, 0.0, 1.0],
+    [1.0, 0.0, -1.0],
+    [-1.0, 0.0, -1.0],
+    [0.0, 1.0, 1.0],
+    [0.0, -1.0, 1.0],
+    [0.0, 1.0, -1.0],
+    [0.0, -1.0, -1.0]
   ];
 
   static final _grad4 = <List<double>>[
-    [0, 1, 1, 1],
-    [0, 1, 1, -1],
-    [0, 1, -1, 1],
-    [0, 1, -1, -1],
-    [0, -1, 1, 1],
-    [0, -1, 1, -1],
-    [0, -1, -1, 1],
-    [0, -1, -1, -1],
-    [1, 0, 1, 1],
-    [1, 0, 1, -1],
-    [1, 0, -1, 1],
-    [1, 0, -1, -1],
-    [-1, 0, 1, 1],
-    [-1, 0, 1, -1],
-    [-1, 0, -1, 1],
-    [-1, 0, -1, -1],
-    [1, 1, 0, 1],
-    [1, 1, 0, -1],
-    [1, -1, 0, 1],
-    [1, -1, 0, -1],
-    [-1, 1, 0, 1],
-    [-1, 1, 0, -1],
-    [-1, -1, 0, 1],
-    [-1, -1, 0, -1],
-    [1, 1, 1, 0],
-    [1, 1, -1, 0],
-    [1, -1, 1, 0],
-    [1, -1, -1, 0],
-    [-1, 1, 1, 0],
-    [-1, 1, -1, 0],
-    [-1, -1, 1, 0],
-    [-1, -1, -1, 0]
+    [0.0, 1.0, 1.0, 1.0],
+    [0.0, 1.0, 1.0, -1.0],
+    [0.0, 1.0, -1.0, 1.0],
+    [0.0, 1.0, -1.0, -1.0],
+    [0.0, -1.0, 1.0, 1.0],
+    [0.0, -1.0, 1.0, -1.0],
+    [0.0, -1.0, -1.0, 1.0],
+    [0.0, -1.0, -1.0, -1.0],
+    [1.0, 0.0, 1.0, 1.0],
+    [1.0, 0.0, 1.0, -1.0],
+    [1.0, 0.0, -1.0, 1.0],
+    [1.0, 0.0, -1.0, -1.0],
+    [-1.0, 0.0, 1.0, 1.0],
+    [-1.0, 0.0, 1.0, -1.0],
+    [-1.0, 0.0, -1.0, 1.0],
+    [-1.0, 0.0, -1.0, -1.0],
+    [1.0, 1.0, 0.0, 1.0],
+    [1.0, 1.0, 0.0, -1.0],
+    [1.0, -1.0, 0.0, 1.0],
+    [1.0, -1.0, 0.0, -1.0],
+    [-1.0, 1.0, 0.0, 1.0],
+    [-1.0, 1.0, 0.0, -1.0],
+    [-1.0, -1.0, 0.0, 1.0],
+    [-1.0, -1.0, 0.0, -1.0],
+    [1.0, 1.0, 1.0, 0.0],
+    [1.0, 1.0, -1.0, 0.0],
+    [1.0, -1.0, 1.0, 0.0],
+    [1.0, -1.0, -1.0, 0.0],
+    [-1.0, 1.0, 1.0, 0.0],
+    [-1.0, 1.0, -1.0, 0.0],
+    [-1.0, -1.0, 1.0, 0.0],
+    [-1.0, -1.0, -1.0, 0.0]
   ];
 
   // To remove the need for index wrapping, double the permutation table length
@@ -101,7 +101,7 @@
     if (r == null) {
       r = new Math.Random();
     }
-    List p =
+    List<int> p =
         new List<int>.generate(256, (i) => r.nextInt(256), growable: false);
     _perm = new List<int>.generate(p.length * 2, (i) => p[i % p.length],
         growable: false);
diff --git a/pub/vector_math/lib/src/vector_math/vector2.dart b/pub/vector_math/lib/src/vector_math/vector2.dart
index ef5dcba..d98ecec 100644
--- a/pub/vector_math/lib/src/vector_math/vector2.dart
+++ b/pub/vector_math/lib/src/vector_math/vector2.dart
@@ -54,6 +54,13 @@
   Vector2.fromBuffer(ByteBuffer buffer, int offset)
       : _v2storage = new Float32List.view(buffer, offset, 2);
 
+  /// Generate random vector in the range (0, 0) to (1, 1). You can
+  /// optionally pass your own random number generator.
+  factory Vector2.random([Math.Random rng]) {
+    rng = rng == null ? new Math.Random() : rng;
+    return new Vector2(rng.nextDouble(), rng.nextDouble());
+  }
+
   /// Set the values of the vector.
   void setValues(double x_, double y_) {
     _v2storage[0] = x_;
@@ -154,7 +161,7 @@
   }
 
   /// Normalize [this]. Returns length of vector before normalization.
-  /// /// DEPRCATED: Use [normalize].
+  /// DEPRECATED: Use [normalize].
   @deprecated
   double normalizeLength() => normalize();
 
@@ -180,6 +187,33 @@
     return dx * dx + dy * dy;
   }
 
+  /// Returns the angle between [this] vector and [other] in radians.
+  double angleTo(Vector2 other) {
+    final otherStorage = other._v2storage;
+    if (_v2storage[0] == otherStorage[0] &&
+        _v2storage[1] == otherStorage[1]) {
+      return 0.0;
+    }
+
+    final d = dot(other);
+
+    return Math.acos(d.clamp(-1.0, 1.0));
+  }
+
+  /// Returns the signed angle between [this] and [other] in radians.
+  double angleToSigned(Vector2 other) {
+    final otherStorage = other._v2storage;
+    if (_v2storage[0] == otherStorage[0] &&
+        _v2storage[1] == otherStorage[1]) {
+      return 0.0;
+    }
+
+    final s = cross(other);
+    final c = dot(other);
+
+    return Math.atan2(s, c);
+  }
+
   /// Inner product.
   double dot(Vector2 other) {
     final otherStorage = other._v2storage;
diff --git a/pub/vector_math/lib/src/vector_math/vector3.dart b/pub/vector_math/lib/src/vector_math/vector3.dart
index 6598290..3f5177d 100644
--- a/pub/vector_math/lib/src/vector_math/vector3.dart
+++ b/pub/vector_math/lib/src/vector_math/vector3.dart
@@ -58,6 +58,13 @@
   Vector3.fromBuffer(ByteBuffer buffer, int offset)
       : _v3storage = new Float32List.view(buffer, offset, 3);
 
+  /// Generate random vector in the range (0, 0, 0) to (1, 1, 1). You can
+  /// optionally pass your own random number generator.
+  factory Vector3.random([Math.Random rng]) {
+    rng = rng == null ? new Math.Random() : rng;
+    return new Vector3(rng.nextDouble(), rng.nextDouble(), rng.nextDouble());
+  }
+
   /// Set the values of the vector.
   void setValues(double x_, double y_, double z_) {
     _v3storage[0] = x_;
diff --git a/pub/vector_math/lib/src/vector_math/vector4.dart b/pub/vector_math/lib/src/vector_math/vector4.dart
index a63f4dd..72a2496 100644
--- a/pub/vector_math/lib/src/vector_math/vector4.dart
+++ b/pub/vector_math/lib/src/vector_math/vector4.dart
@@ -64,6 +64,14 @@
   Vector4.fromBuffer(ByteBuffer buffer, int offset)
       : _v4storage = new Float32List.view(buffer, offset, 4);
 
+  /// Generate random vector in the range (0, 0, 0, 0) to (1, 1, 1, 1). You can
+  /// optionally pass your own random number generator.
+  factory Vector4.random([Math.Random rng]) {
+    rng = rng == null ? new Math.Random() : rng;
+    return new Vector4(
+      rng.nextDouble(), rng.nextDouble(), rng.nextDouble(), rng.nextDouble());
+  }
+
   /// Set the values of the vector.
   void setValues(double x_, double y_, double z_, double w_) {
     _v4storage[3] = w_;
diff --git a/pub/vector_math/lib/src/vector_math_64/colors.dart b/pub/vector_math/lib/src/vector_math_64/colors.dart
index 9fa8d7a..d9917f6 100644
--- a/pub/vector_math/lib/src/vector_math_64/colors.dart
+++ b/pub/vector_math/lib/src/vector_math_64/colors.dart
@@ -72,17 +72,35 @@
   }
 
   /// Convert a [input] color to a hex string without a leading '#'. To include
-  /// the alpha channel, set [alpha] to true, it is false by default.
-  static String toHexString(Vector4 input, {bool alpha: false}) {
-    var color = (input.r * 255).floor() << 16 |
-        (input.g * 255).floor() << 8 |
-        (input.b * 255).floor();
+  /// the alpha channel, set [alpha] to true, it is false by default. If [short]
+  /// is true, the resulting hex string might also be a short version, like #ff0
+  /// (default false).
+  static String toHexString(Vector4 input,
+      {bool alpha: false, bool short: false}) {
+    final r = (input.r * 0xFF).floor() & 0xFF;
+    final g = (input.g * 0xFF).floor() & 0xFF;
+    final b = (input.b * 0xFF).floor() & 0xFF;
+    final a = (input.a * 0xFF).floor() & 0xFF;
 
-    if (alpha) {
-      color |= (input.a * 255).floor() << 24;
+    final isShort = short &&
+        ((r >> 4) == (r & 0xF)) &&
+        ((g >> 4) == (g & 0xF)) &&
+        ((b >> 4) == (b & 0xF)) &&
+        (!alpha || (a >> 4) == (a & 0xF));
+
+    if (isShort) {
+      final rgb = (r & 0xF).toRadixString(16) +
+          (g & 0xF).toRadixString(16) +
+          (b & 0xF).toRadixString(16);
+
+      return alpha ? (a & 0xF).toRadixString(16) + rgb : rgb;
+    } else {
+      final rgb = r.toRadixString(16).padLeft(2, '0') +
+          g.toRadixString(16).padLeft(2, '0') +
+          b.toRadixString(16).padLeft(2, '0');
+
+      return alpha ? a.toRadixString(16).padLeft(2, '0') + rgb : rgb;
     }
-
-    return color.toRadixString(16);
   }
 
   /// Blend the [foreground] color over [background] color and store the color
diff --git a/pub/vector_math/lib/src/vector_math_64/matrix3.dart b/pub/vector_math/lib/src/vector_math_64/matrix3.dart
index c2890bd..2499d9a 100644
--- a/pub/vector_math/lib/src/vector_math_64/matrix3.dart
+++ b/pub/vector_math/lib/src/vector_math_64/matrix3.dart
@@ -899,4 +899,30 @@
     double z = _m3storage[8];
     return new Vector3(x, y, z);
   }
+
+  /// Is [this] the identity matrix?
+  bool isIdentity() {
+    return _m3storage[0] == 1.0 // col 1
+        && _m3storage[1] == 0.0
+        && _m3storage[2] == 0.0
+        && _m3storage[3] == 0.0 // col 2
+        && _m3storage[4] == 1.0
+        && _m3storage[5] == 0.0
+        && _m3storage[6] == 0.0 // col 3
+        && _m3storage[7] == 0.0
+        && _m3storage[8] == 1.0;
+  }
+
+  /// Is [this] the zero matrix?
+  bool isZero() {
+    return _m3storage[0] == 0.0 // col 1
+        && _m3storage[1] == 0.0
+        && _m3storage[2] == 0.0
+        && _m3storage[3] == 0.0 // col 2
+        && _m3storage[4] == 0.0
+        && _m3storage[5] == 0.0
+        && _m3storage[6] == 0.0 // col 3
+        && _m3storage[7] == 0.0
+        && _m3storage[8] == 0.0;
+  }
 }
diff --git a/pub/vector_math/lib/src/vector_math_64/matrix4.dart b/pub/vector_math/lib/src/vector_math_64/matrix4.dart
index b0bed20..96e260e 100644
--- a/pub/vector_math/lib/src/vector_math_64/matrix4.dart
+++ b/pub/vector_math/lib/src/vector_math_64/matrix4.dart
@@ -1980,4 +1980,44 @@
     double z = _m4storage[10];
     return new Vector3(x, y, z);
   }
+
+  /// Is [this] the identity matrix?
+  bool isIdentity() {
+    return _m4storage[0] == 1.0 // col 1
+        && _m4storage[1] == 0.0
+        && _m4storage[2] == 0.0
+        && _m4storage[3] == 0.0
+        && _m4storage[4] == 0.0 // col 2
+        && _m4storage[5] == 1.0
+        && _m4storage[6] == 0.0
+        && _m4storage[7] == 0.0
+        && _m4storage[8] == 0.0 // col 3
+        && _m4storage[9] == 0.0
+        && _m4storage[10] == 1.0
+        && _m4storage[11] == 0.0
+        && _m4storage[12] == 0.0 // col 4
+        && _m4storage[13] == 0.0
+        && _m4storage[14] == 0.0
+        && _m4storage[15] == 1.0;
+  }
+
+  /// Is [this] the zero matrix?
+  bool isZero() {
+    return _m4storage[0] == 0.0 // col 1
+        && _m4storage[1] == 0.0
+        && _m4storage[2] == 0.0
+        && _m4storage[3] == 0.0
+        && _m4storage[4] == 0.0 // col 2
+        && _m4storage[5] == 0.0
+        && _m4storage[6] == 0.0
+        && _m4storage[7] == 0.0
+        && _m4storage[8] == 0.0 // col 3
+        && _m4storage[9] == 0.0
+        && _m4storage[10] == 0.0
+        && _m4storage[11] == 0.0
+        && _m4storage[12] == 0.0 // col 4
+        && _m4storage[13] == 0.0
+        && _m4storage[14] == 0.0
+        && _m4storage[15] == 0.0;
+  }
 }
diff --git a/pub/vector_math/lib/src/vector_math_64/opengl.dart b/pub/vector_math/lib/src/vector_math_64/opengl.dart
index 1d2ba0e..b53dfaa 100644
--- a/pub/vector_math/lib/src/vector_math_64/opengl.dart
+++ b/pub/vector_math/lib/src/vector_math_64/opengl.dart
@@ -113,10 +113,16 @@
 /// (always positive).
 void setPerspectiveMatrix(Matrix4 perspectiveMatrix, double fovYRadians,
     double aspectRatio, double zNear, double zFar) {
-  double height = Math.tan(fovYRadians * 0.5) * zNear;
-  double width = height * aspectRatio;
-  setFrustumMatrix(
-      perspectiveMatrix, -width, width, -height, height, zNear, zFar);
+  final double height = Math.tan(fovYRadians * 0.5);
+  final double width = height * aspectRatio;
+  final double near_minus_far = zNear - zFar;
+
+  final Matrix4 view = perspectiveMatrix..setZero();
+  view.setEntry(0, 0, 1.0 / width);
+  view.setEntry(1, 1, 1.0 / height);
+  view.setEntry(2, 2, (zFar + zNear) / near_minus_far);
+  view.setEntry(3, 2, -1.0);
+  view.setEntry(2, 3, (2.0 * zNear * zFar) / near_minus_far);
 }
 
 /// Constructs a new OpenGL perspective projection matrix.
@@ -136,6 +142,41 @@
   return r;
 }
 
+/// Constructs an OpenGL infinite projection matrix in [infiniteMatrix].
+/// [fovYRadians] specifies the field of view angle, in radians, in the y
+/// direction.
+/// [aspectRatio] specifies the aspect ratio that determines the field of view
+/// in the x direction. The aspect ratio of x (width) to y (height).
+/// [zNear] specifies the distance from the viewer to the near plane
+/// (always positive).
+void setInfiniteMatrix(Matrix4 infiniteMatrix, double fovYRadians,
+    double aspectRatio, double zNear) {
+  final double height = Math.tan(fovYRadians * 0.5);
+  final double width = height * aspectRatio;
+
+  final Matrix4 view = infiniteMatrix..setZero();
+  view.setEntry(0, 0, 1.0 / width);
+  view.setEntry(1, 1, 1.0 / height);
+  view.setEntry(2, 2, -1.0);
+  view.setEntry(3, 2, -1.0);
+  view.setEntry(2, 3, -2.0 * zNear);
+}
+
+/// Constructs a new OpenGL infinite projection matrix.
+///
+/// [fovYRadians] specifies the field of view angle, in radians, in the y
+/// direction.
+/// [aspectRatio] specifies the aspect ratio that determines the field of view
+/// in the x direction. The aspect ratio of x (width) to y (height).
+/// [zNear] specifies the distance from the viewer to the near plane
+/// (always positive).
+Matrix4 makeInfiniteMatrix(
+    double fovYRadians, double aspectRatio, double zNear) {
+  Matrix4 r = new Matrix4.zero();
+  setInfiniteMatrix(r, fovYRadians, aspectRatio, zNear);
+  return r;
+}
+
 /// Constructs an OpenGL perspective projection matrix in [perspectiveMatrix].
 ///
 /// [left], [right] specify the coordinates for the left and right vertical
diff --git a/pub/vector_math/lib/src/vector_math_64/third_party/noise.dart b/pub/vector_math/lib/src/vector_math_64/third_party/noise.dart
index 7d81c6a..bb1b81f 100644
--- a/pub/vector_math/lib/src/vector_math_64/third_party/noise.dart
+++ b/pub/vector_math/lib/src/vector_math_64/third_party/noise.dart
@@ -28,53 +28,53 @@
 
 class SimplexNoise {
   static final _grad3 = <List<double>>[
-    [1, 1, 0],
-    [-1, 1, 0],
-    [1, -1, 0],
-    [-1, -1, 0],
-    [1, 0, 1],
-    [-1, 0, 1],
-    [1, 0, -1],
-    [-1, 0, -1],
-    [0, 1, 1],
-    [0, -1, 1],
-    [0, 1, -1],
-    [0, -1, -1]
+    [1.0, 1.0, 0.0],
+    [-1.0, 1.0, 0.0],
+    [1.0, -1.0, 0.0],
+    [-1.0, -1.0, 0.0],
+    [1.0, 0.0, 1.0],
+    [-1.0, 0.0, 1.0],
+    [1.0, 0.0, -1.0],
+    [-1.0, 0.0, -1.0],
+    [0.0, 1.0, 1.0],
+    [0.0, -1.0, 1.0],
+    [0.0, 1.0, -1.0],
+    [0.0, -1.0, -1.0]
   ];
 
   static final _grad4 = <List<double>>[
-    [0, 1, 1, 1],
-    [0, 1, 1, -1],
-    [0, 1, -1, 1],
-    [0, 1, -1, -1],
-    [0, -1, 1, 1],
-    [0, -1, 1, -1],
-    [0, -1, -1, 1],
-    [0, -1, -1, -1],
-    [1, 0, 1, 1],
-    [1, 0, 1, -1],
-    [1, 0, -1, 1],
-    [1, 0, -1, -1],
-    [-1, 0, 1, 1],
-    [-1, 0, 1, -1],
-    [-1, 0, -1, 1],
-    [-1, 0, -1, -1],
-    [1, 1, 0, 1],
-    [1, 1, 0, -1],
-    [1, -1, 0, 1],
-    [1, -1, 0, -1],
-    [-1, 1, 0, 1],
-    [-1, 1, 0, -1],
-    [-1, -1, 0, 1],
-    [-1, -1, 0, -1],
-    [1, 1, 1, 0],
-    [1, 1, -1, 0],
-    [1, -1, 1, 0],
-    [1, -1, -1, 0],
-    [-1, 1, 1, 0],
-    [-1, 1, -1, 0],
-    [-1, -1, 1, 0],
-    [-1, -1, -1, 0]
+    [0.0, 1.0, 1.0, 1.0],
+    [0.0, 1.0, 1.0, -1.0],
+    [0.0, 1.0, -1.0, 1.0],
+    [0.0, 1.0, -1.0, -1.0],
+    [0.0, -1.0, 1.0, 1.0],
+    [0.0, -1.0, 1.0, -1.0],
+    [0.0, -1.0, -1.0, 1.0],
+    [0.0, -1.0, -1.0, -1.0],
+    [1.0, 0.0, 1.0, 1.0],
+    [1.0, 0.0, 1.0, -1.0],
+    [1.0, 0.0, -1.0, 1.0],
+    [1.0, 0.0, -1.0, -1.0],
+    [-1.0, 0.0, 1.0, 1.0],
+    [-1.0, 0.0, 1.0, -1.0],
+    [-1.0, 0.0, -1.0, 1.0],
+    [-1.0, 0.0, -1.0, -1.0],
+    [1.0, 1.0, 0.0, 1.0],
+    [1.0, 1.0, 0.0, -1.0],
+    [1.0, -1.0, 0.0, 1.0],
+    [1.0, -1.0, 0.0, -1.0],
+    [-1.0, 1.0, 0.0, 1.0],
+    [-1.0, 1.0, 0.0, -1.0],
+    [-1.0, -1.0, 0.0, 1.0],
+    [-1.0, -1.0, 0.0, -1.0],
+    [1.0, 1.0, 1.0, 0.0],
+    [1.0, 1.0, -1.0, 0.0],
+    [1.0, -1.0, 1.0, 0.0],
+    [1.0, -1.0, -1.0, 0.0],
+    [-1.0, 1.0, 1.0, 0.0],
+    [-1.0, 1.0, -1.0, 0.0],
+    [-1.0, -1.0, 1.0, 0.0],
+    [-1.0, -1.0, -1.0, 0.0]
   ];
 
   // To remove the need for index wrapping, double the permutation table length
@@ -101,7 +101,7 @@
     if (r == null) {
       r = new Math.Random();
     }
-    List p =
+    List<int> p =
         new List<int>.generate(256, (i) => r.nextInt(256), growable: false);
     _perm = new List<int>.generate(p.length * 2, (i) => p[i % p.length],
         growable: false);
diff --git a/pub/vector_math/lib/src/vector_math_64/vector2.dart b/pub/vector_math/lib/src/vector_math_64/vector2.dart
index 7559026..7e4e6e1 100644
--- a/pub/vector_math/lib/src/vector_math_64/vector2.dart
+++ b/pub/vector_math/lib/src/vector_math_64/vector2.dart
@@ -54,6 +54,13 @@
   Vector2.fromBuffer(ByteBuffer buffer, int offset)
       : _v2storage = new Float64List.view(buffer, offset, 2);
 
+  /// Generate random vector in the range (0, 0) to (1, 1). You can
+  /// optionally pass your own random number generator.
+  factory Vector2.random([Math.Random rng]) {
+    rng = rng == null ? new Math.Random() : rng;
+    return new Vector2(rng.nextDouble(), rng.nextDouble());
+  }
+
   /// Set the values of the vector.
   void setValues(double x_, double y_) {
     _v2storage[0] = x_;
@@ -154,7 +161,7 @@
   }
 
   /// Normalize [this]. Returns length of vector before normalization.
-  /// /// DEPRCATED: Use [normalize].
+  /// DEPRECATED: Use [normalize].
   @deprecated
   double normalizeLength() => normalize();
 
@@ -180,6 +187,33 @@
     return dx * dx + dy * dy;
   }
 
+  /// Returns the angle between [this] vector and [other] in radians.
+  double angleTo(Vector2 other) {
+    final otherStorage = other._v2storage;
+    if (_v2storage[0] == otherStorage[0] &&
+        _v2storage[1] == otherStorage[1]) {
+      return 0.0;
+    }
+
+    final d = dot(other);
+
+    return Math.acos(d.clamp(-1.0, 1.0));
+  }
+
+  /// Returns the signed angle between [this] and [other] in radians.
+  double angleToSigned(Vector2 other) {
+    final otherStorage = other._v2storage;
+    if (_v2storage[0] == otherStorage[0] &&
+        _v2storage[1] == otherStorage[1]) {
+      return 0.0;
+    }
+
+    final s = cross(other);
+    final c = dot(other);
+
+    return Math.atan2(s, c);
+  }
+
   /// Inner product.
   double dot(Vector2 other) {
     final otherStorage = other._v2storage;
diff --git a/pub/vector_math/lib/src/vector_math_64/vector3.dart b/pub/vector_math/lib/src/vector_math_64/vector3.dart
index 79cfa81..40dc376 100644
--- a/pub/vector_math/lib/src/vector_math_64/vector3.dart
+++ b/pub/vector_math/lib/src/vector_math_64/vector3.dart
@@ -58,6 +58,13 @@
   Vector3.fromBuffer(ByteBuffer buffer, int offset)
       : _v3storage = new Float64List.view(buffer, offset, 3);
 
+  /// Generate random vector in the range (0, 0, 0) to (1, 1, 1). You can
+  /// optionally pass your own random number generator.
+  factory Vector3.random([Math.Random rng]) {
+    rng = rng == null ? new Math.Random() : rng;
+    return new Vector3(rng.nextDouble(), rng.nextDouble(), rng.nextDouble());
+  }
+
   /// Set the values of the vector.
   void setValues(double x_, double y_, double z_) {
     _v3storage[0] = x_;
diff --git a/pub/vector_math/lib/src/vector_math_64/vector4.dart b/pub/vector_math/lib/src/vector_math_64/vector4.dart
index 8b234e4..e2d09df 100644
--- a/pub/vector_math/lib/src/vector_math_64/vector4.dart
+++ b/pub/vector_math/lib/src/vector_math_64/vector4.dart
@@ -64,6 +64,14 @@
   Vector4.fromBuffer(ByteBuffer buffer, int offset)
       : _v4storage = new Float64List.view(buffer, offset, 4);
 
+  /// Generate random vector in the range (0, 0, 0, 0) to (1, 1, 1, 1). You can
+  /// optionally pass your own random number generator.
+  factory Vector4.random([Math.Random rng]) {
+    rng = rng == null ? new Math.Random() : rng;
+    return new Vector4(
+      rng.nextDouble(), rng.nextDouble(), rng.nextDouble(), rng.nextDouble());
+  }
+
   /// Set the values of the vector.
   void setValues(double x_, double y_, double z_, double w_) {
     _v4storage[3] = w_;
diff --git a/pub/vector_math/pubspec.yaml b/pub/vector_math/pubspec.yaml
index e6b3811..c85ec11 100644
--- a/pub/vector_math/pubspec.yaml
+++ b/pub/vector_math/pubspec.yaml
@@ -1,5 +1,5 @@
 name: vector_math
-version: 2.0.3
+version: 2.0.4
 author: John McCutchan <john@johnmccutchan.com>
 description: A Vector Math library for 2D and 3D applications.
 homepage: https://github.com/google/vector_math.dart